tests: Rework the way foreigndrawing works
Instead of the weird PathElt struct, generate a quick-n-dirty parser that parses CSS selectors into GtkWidgetPath elements. Based on a patch by Benjamin Otte.
This commit is contained in:
parent
c543712551
commit
bc020fdeb7
@ -18,15 +18,107 @@
|
|||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
typedef struct {
|
#include <string.h>
|
||||||
GType type;
|
|
||||||
const gchar *name;
|
static void
|
||||||
const gchar *class1;
|
append_element (GtkWidgetPath *path,
|
||||||
const gchar *class2;
|
const char *selector)
|
||||||
} PathElt;
|
{
|
||||||
|
static const struct {
|
||||||
|
const char *name;
|
||||||
|
GtkStateFlags state_flag;
|
||||||
|
} pseudo_classes[] = {
|
||||||
|
{ "active", GTK_STATE_FLAG_ACTIVE },
|
||||||
|
{ "hover", GTK_STATE_FLAG_PRELIGHT },
|
||||||
|
{ "selected", GTK_STATE_FLAG_SELECTED },
|
||||||
|
{ "disabled", GTK_STATE_FLAG_INSENSITIVE },
|
||||||
|
{ "indeterminate", GTK_STATE_FLAG_INCONSISTENT },
|
||||||
|
{ "focus", GTK_STATE_FLAG_FOCUSED },
|
||||||
|
{ "backdrop", GTK_STATE_FLAG_BACKDROP },
|
||||||
|
{ "dir(ltr)", GTK_STATE_FLAG_DIR_LTR },
|
||||||
|
{ "dir(rtl)", GTK_STATE_FLAG_DIR_RTL },
|
||||||
|
{ "link", GTK_STATE_FLAG_LINK },
|
||||||
|
{ "visited", GTK_STATE_FLAG_VISITED },
|
||||||
|
{ "checked", GTK_STATE_FLAG_CHECKED },
|
||||||
|
{ "drop(active)", GTK_STATE_FLAG_DROP_ACTIVE }
|
||||||
|
};
|
||||||
|
const char *next;
|
||||||
|
char *name;
|
||||||
|
char type;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
next = strpbrk (selector, "#.:");
|
||||||
|
if (next == NULL)
|
||||||
|
next = selector + strlen (selector);
|
||||||
|
|
||||||
|
name = g_strndup (selector, next - selector);
|
||||||
|
if (g_ascii_isupper (selector[0]))
|
||||||
|
{
|
||||||
|
GType gtype;
|
||||||
|
gtype = g_type_from_name (name);
|
||||||
|
if (gtype == G_TYPE_INVALID)
|
||||||
|
{
|
||||||
|
g_critical ("Unknown type name `%s'", name);
|
||||||
|
g_free (name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gtk_widget_path_append_type (path, gtype);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Omit type, we're using name */
|
||||||
|
gtk_widget_path_append_type (path, G_TYPE_NONE);
|
||||||
|
gtk_widget_path_iter_set_object_name (path, -1, name);
|
||||||
|
}
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
while (*next != '\0')
|
||||||
|
{
|
||||||
|
type = *next;
|
||||||
|
selector = next + 1;
|
||||||
|
next = strpbrk (selector, "#.:");
|
||||||
|
if (next == NULL)
|
||||||
|
next = selector + strlen (selector);
|
||||||
|
name = g_strndup (selector, next - selector);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case '#':
|
||||||
|
gtk_widget_path_iter_set_name (path, -1, name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
gtk_widget_path_iter_add_class (path, -1, name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':':
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
|
||||||
|
{
|
||||||
|
if (g_str_equal (pseudo_classes[i].name, name))
|
||||||
|
{
|
||||||
|
gtk_widget_path_iter_set_state (path,
|
||||||
|
-1,
|
||||||
|
gtk_widget_path_iter_get_state (path, -1)
|
||||||
|
| pseudo_classes[i].state_flag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == G_N_ELEMENTS (pseudo_classes))
|
||||||
|
g_critical ("Unknown pseudo-class :%s", name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GtkStyleContext *
|
static GtkStyleContext *
|
||||||
get_style (PathElt *pelt, GtkStyleContext *parent)
|
get_style (GtkStyleContext *parent,
|
||||||
|
const char *selector)
|
||||||
{
|
{
|
||||||
GtkWidgetPath *path;
|
GtkWidgetPath *path;
|
||||||
GtkStyleContext *context;
|
GtkStyleContext *context;
|
||||||
@ -36,17 +128,13 @@ get_style (PathElt *pelt, GtkStyleContext *parent)
|
|||||||
else
|
else
|
||||||
path = gtk_widget_path_new ();
|
path = gtk_widget_path_new ();
|
||||||
|
|
||||||
gtk_widget_path_append_type (path, pelt->type);
|
append_element (path, selector);
|
||||||
if (pelt->name)
|
|
||||||
gtk_widget_path_iter_set_object_name (path, -1, pelt->name);
|
|
||||||
if (pelt->class1)
|
|
||||||
gtk_widget_path_iter_add_class (path, -1, pelt->class1);
|
|
||||||
if (pelt->class2)
|
|
||||||
gtk_widget_path_iter_add_class (path, -1, pelt->class2);
|
|
||||||
|
|
||||||
context = gtk_style_context_new ();
|
context = gtk_style_context_new ();
|
||||||
gtk_style_context_set_path (context, path);
|
gtk_style_context_set_path (context, path);
|
||||||
gtk_style_context_set_parent (context, parent);
|
gtk_style_context_set_parent (context, parent);
|
||||||
|
/* XXX: Why is this necessary? */
|
||||||
|
gtk_style_context_set_state (context, gtk_widget_path_iter_get_state (path, -1));
|
||||||
gtk_widget_path_unref (path);
|
gtk_widget_path_unref (path);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
@ -67,15 +155,15 @@ draw_horizontal_scrollbar (GtkWidget *widget,
|
|||||||
GtkStyleContext *slider_context;
|
GtkStyleContext *slider_context;
|
||||||
|
|
||||||
/* This information is taken from the GtkScrollbar docs, see "CSS nodes" */
|
/* This information is taken from the GtkScrollbar docs, see "CSS nodes" */
|
||||||
PathElt path[3] = {
|
const char *path[3] = {
|
||||||
{ GTK_TYPE_SCROLLBAR, "scrollbar", "horizontal", NULL },
|
"scrollbar.horizontal",
|
||||||
{ G_TYPE_NONE, "trough", NULL, NULL },
|
"trough",
|
||||||
{ G_TYPE_NONE, "slider", NULL, NULL }
|
"slider"
|
||||||
};
|
};
|
||||||
|
|
||||||
scrollbar_context = get_style (&path[0], NULL);
|
scrollbar_context = get_style (NULL, path[0]);
|
||||||
trough_context = get_style (&path[1], scrollbar_context);
|
trough_context = get_style (scrollbar_context, path[1]);
|
||||||
slider_context = get_style (&path[2], trough_context);
|
slider_context = get_style (trough_context, path[2]);
|
||||||
|
|
||||||
gtk_style_context_set_state (scrollbar_context, state);
|
gtk_style_context_set_state (scrollbar_context, state);
|
||||||
gtk_style_context_set_state (trough_context, state);
|
gtk_style_context_set_state (trough_context, state);
|
||||||
@ -106,13 +194,13 @@ draw_text (GtkWidget *widget,
|
|||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
|
|
||||||
/* This information is taken from the GtkLabel docs, see "CSS nodes" */
|
/* This information is taken from the GtkLabel docs, see "CSS nodes" */
|
||||||
PathElt path[2] = {
|
const char *path[2] = {
|
||||||
{ GTK_TYPE_LABEL, "label", "view", NULL },
|
"label.view",
|
||||||
{ G_TYPE_NONE, "selection", NULL, NULL }
|
"selection"
|
||||||
};
|
};
|
||||||
|
|
||||||
label_context = get_style (&path[0], NULL);
|
label_context = get_style (NULL, path[0]);
|
||||||
selection_context = get_style (&path[1], label_context);
|
selection_context = get_style (label_context, path[1]);
|
||||||
|
|
||||||
gtk_style_context_set_state (label_context, state);
|
gtk_style_context_set_state (label_context, state);
|
||||||
|
|
||||||
@ -144,13 +232,13 @@ draw_check (GtkWidget *widget,
|
|||||||
GtkStyleContext *check_context;
|
GtkStyleContext *check_context;
|
||||||
|
|
||||||
/* This information is taken from the GtkCheckButton docs, see "CSS nodes" */
|
/* This information is taken from the GtkCheckButton docs, see "CSS nodes" */
|
||||||
PathElt path[2] = {
|
const char *path[2] = {
|
||||||
{ GTK_TYPE_LABEL, "checkbutton", NULL, NULL },
|
"checkbutton",
|
||||||
{ G_TYPE_NONE, "check", NULL, NULL }
|
"check"
|
||||||
};
|
};
|
||||||
|
|
||||||
button_context = get_style (&path[0], NULL);
|
button_context = get_style (NULL, path[0]);
|
||||||
check_context = get_style (&path[1], button_context);
|
check_context = get_style (button_context, path[1]);
|
||||||
|
|
||||||
gtk_style_context_set_state (check_context, state);
|
gtk_style_context_set_state (check_context, state);
|
||||||
|
|
||||||
@ -174,13 +262,13 @@ draw_radio (GtkWidget *widget,
|
|||||||
GtkStyleContext *check_context;
|
GtkStyleContext *check_context;
|
||||||
|
|
||||||
/* This information is taken from the GtkRadioButton docs, see "CSS nodes" */
|
/* This information is taken from the GtkRadioButton docs, see "CSS nodes" */
|
||||||
PathElt path[2] = {
|
const char *path[2] = {
|
||||||
{ GTK_TYPE_LABEL, "radiobutton", NULL, NULL },
|
"radiobutton",
|
||||||
{ G_TYPE_NONE, "radio", NULL, NULL }
|
"radio"
|
||||||
};
|
};
|
||||||
|
|
||||||
button_context = get_style (&path[0], NULL);
|
button_context = get_style (NULL, path[0]);
|
||||||
check_context = get_style (&path[1], button_context);
|
check_context = get_style (button_context, path[1]);
|
||||||
|
|
||||||
gtk_style_context_set_state (check_context, state);
|
gtk_style_context_set_state (check_context, state);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user