Re: GTK Theme Torturer



Hello,

On Fri, 2006-04-08 at 19:22 +0200, Manu Cornet wrote:
> This "GTK Theme Torturer" mainly does two things: 
> 
> 1) crash test the engine by calling all the GTK paint functions with
> unusual parameters and Doesn'

This is interesting though one thing that bugs me is that it does not
currently test different detail strings. This is pretty important, as
otherwise most code paths inside the engines will not be hit during the
test. Also testing different sizes seems like a waste to me, as
everything should be robust now with cairo.

I actually decided to write a small test app inspired by your stuff
yesterday (attached). Nothing fancy, but I was able to fix a lot of
engine bugs with it and your tool :-).

One thing I was thinking about is, whether it might be feasible to
create an automated test with something like this. Though I would like
to test the engine that was build and not the installed one, not sure
how this can be achieved.


> 2) measure the time the theme takes to create/map/expose/resize/destroy
> widgets (with help from Federico Mena's widget profiler's
> infrastructure).

One thing I am wondering about is the fact that it recreates the window
all the time. I would expect that the redrawing of the window titles and
window list may have an impact on the timings.


> I have used it to benchmark a few themes (Clearlooks, Human,
> HighContrast and the OLPC theme -- for which the torturer was originally
> designed). The results are available as a spreadsheet here:
> 
> http://www.manucornet.net/pub/Themes_performance.ods
> 
> (absolute values aren't really interesting, but the ratios give some
> useful info).

Hmm, a comparison of the engines in gtk-engines might be interesting ;-)


> I have sent a short analysis of these tests to the OLPC list [1] and the
> Ubuntu list [2].
> 
> 
> In the near future, I'll certainly be hanging around on IRC to ask some
> advice, if it is okay with you: I'm going to start working on the OLPC
> theme/engine and I'm definitely going to need some expert
> help/teaching/advice :) Which channel do you guys usually stay on (there
> was nobody on #gnome-themes on GimpNet)?

We hang out in #gnome-art on GIMPNet.

Benjamin

> [1] http://mailman.laptop.org/pipermail/devel/2006-August/001026.html
> 
> [2]
> https://lists.ubuntu.com/archives/ubuntu-devel/2006-August/019738.html

#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>

typedef enum {
	WIDGET_NULL,
	WIDGET_HSCROLLBAR,
	WIDGET_VSCROLLBAR,
	WIDGET_TOGGLE_BUTTON,
	WIDGET_BUTTON,
	WIDGET_LAST
} WidgetType;

#define WIDGET_ALL (-1)


GType
widget_type_get_type (void)
{
	static GType type = 0;
	if (type == 0) {
		static const GEnumValue values[] = {
			{ WIDGET_NULL, "WIDGET_NULL", "NULL" },
			{ WIDGET_HSCROLLBAR, "WIDGET_HSCROLLBAR", "GtkHScrollBar" },
			{ WIDGET_VSCROLLBAR, "WIDGET_VSCROLLBAR", "GtkVScrollBar" },
			{ WIDGET_TOGGLE_BUTTON, "WIDGET_TOGGLE_BUTTON", "GtkToggleButton" },
			{ WIDGET_BUTTON, "WIDGET_BUTTON", "GtkButton" },
			{ 0, NULL, NULL }
		};
	type = g_enum_register_static ("WidgeType", values);
	}
	return type;
}

GType
bool_get_type (void)
{
	static GType type = 0;
	if (type == 0) {
		static const GEnumValue values[] = {
			{ 0, "BOOL_FALSE", "False" },
			{ 1, "BOOL_TRUE", "True" },
			{ 0, NULL, NULL }
		};
		type = g_enum_register_static ("GtkBoolDummyType", values);
	}
	return type;
}


#define WIDGET_TYPE (widget_type_get_type ())
#define BOOL_TYPE (bool_get_type ())


typedef enum {
	FUNCTION_ARROW		= 1 << 0,
	FUNCTION_BOX		= 1 << 1,
	FUNCTION_SHADOW		= 1 << 2,
	FUNCTION_BOX_GAP	= 1 << 3,
	FUNCTION_SHADOW_GAP	= 1 << 4,
	FUNCTION_CHECK		= 1 << 5,
	FUNCTION_EXPANDER	= 1 << 6,
	FUNCTION_EXTENSION	= 1 << 7,
	FUNCTION_FLAT_BOX	= 1 << 8,
	FUNCTION_FOCUS		= 1 << 9,
	FUNCTION_HANDLE		= 1 << 10,
	FUNCTION_HLINE		= 1 << 11,
	FUNCTION_VLINE		= 1 << 12,
	FUNCTION_OPTION		= 1 << 13,
	FUNCTION_RESIZE_GRIP	= 1 << 14,
	FUNCTION_SLIDER		= 1 << 15,
	FUNCTION_TAB		= 1 << 15,

	FUNCTION_ALL		= -1,
} FunctionType;
#define FUNCTION_LAST FUNCTION_BOX

GtkWidget *window;
GtkWidget *widgets[WIDGET_LAST];

typedef struct {
	FunctionType     function;
	WidgetType       widget;
	gchar           *detail;
	GtkStateType     state;
	GtkShadowType    shadow;
	GtkArrowType     arrow_type;
	gboolean         fill;
	GtkPositionType  gap_side;
	GtkOrientation   orientation;
	GtkExpanderStyle expander_style;
	GdkWindowEdge    edge;
} Test;

#define ARROW_ALL (-1)
#define STATE_ALL (-1)
#define SHADOW_ALL (-1)
#define FILL_ALL (-1)
#define EXPANDER_ALL (-1)
#define EDGE_ALL (-1)
#define GAP_SIDE_ALL (-1)
#define ORIENTATION_ALL (-1)

static Test tests[] = {
	{
		FUNCTION_ALL,
		WIDGET_NULL,
		NULL,
		STATE_ALL /*GTK_STATE_NORMAL*/,
		SHADOW_ALL /* GTK_SHADOW_IN */,
		GTK_ARROW_UP,
		TRUE,
		GTK_SIDE_TOP,
		GTK_ORIENTATION_HORIZONTAL,
		GTK_EXPANDER_EXPANDED,
		GDK_WINDOW_EDGE_SOUTH
	},
	{
		FUNCTION_ALL,
		WIDGET_NULL,
		"arrow:bar:base:button:buttondefault:cellcheck:cell_even:cell_even_ruled:cell_even_ruled_sorted:cell_even_sorted:cell_odd:cell_odd_ruled:cell_odd_ruled_sorted:cell_odd_sorted:cellradio:check:checkbutton:combo_entry_button:dockitem:dockitem_bin:entry:entry_bg:frame:handle:handlebox:handlebox_bin:hpaned:hruler:hscale:hscrollbar:hseparator:label:menu:menubar:menuitem:metacity:notebook:option:optionmenu:optionmenutab:paned:radiobutton:scrolled_window:slider:spinbutton:spinbutton_arrow:spinbutton_down:spinbutton_up:stepper:tab:text:togglebutton:togglebuttondefault:toolbar:tooltip:treeitem:treeview:trough:viewport:viewportbin:vpaned:vruler:vscale:vscrollbar:vseparator",
		STATE_ALL /*GTK_STATE_NORMAL*/,
		SHADOW_ALL /* GTK_SHADOW_IN */,
		GTK_ARROW_UP,
		TRUE,
		GTK_SIDE_TOP,
		GTK_ORIENTATION_HORIZONTAL,
		GTK_EXPANDER_EXPANDED,
		GDK_WINDOW_EDGE_SOUTH
	},
};

#define ENUM_NEXT(enum_type, ind, target)				\
	do {								\
		GEnumClass *enum_class = g_type_class_ref (enum_type);	\
		if (initial || values[ind] >= enum_class->n_values - 1) { \
			values[ind] = 0;				\
		} else {						\
			done = FALSE;					\
			values[ind]++;					\
		}							\
									\
		if (!done && !initial)					\
			goto end;					\
		target = enum_class->values[values[ind]].value;		\
		g_type_class_unref (enum_class);			\
	} while(0)

static gboolean
get_next_combination (Test *wildcard_test, Test *test, gboolean initial)
{
	gint i;
	gchar *cur_pos, *col_pos;
	gboolean done = !initial;
	static gint values[10];
	
	test->function = wildcard_test->function;
	
	if (wildcard_test->widget == WIDGET_ALL)
		ENUM_NEXT (WIDGET_TYPE, 0, test->widget);
	else
		test->widget = wildcard_test->widget;

	if (wildcard_test->state == STATE_ALL)
		ENUM_NEXT (GTK_TYPE_STATE_TYPE, 1, test->state);
	else
		test->state = wildcard_test->state;

	if (wildcard_test->shadow == SHADOW_ALL)
		ENUM_NEXT (GTK_TYPE_SHADOW_TYPE, 2, test->shadow);
	else
		test->shadow = wildcard_test->shadow;

	if (wildcard_test->arrow_type == ARROW_ALL)
		ENUM_NEXT (GTK_TYPE_ARROW_TYPE, 3, test->arrow_type);
	else
		test->arrow_type = wildcard_test->arrow_type;

	if (wildcard_test->fill == FILL_ALL)
		ENUM_NEXT (BOOL_TYPE, 4, test->fill);
	else
		test->fill = wildcard_test->fill;

	if (wildcard_test->gap_side == GAP_SIDE_ALL)
		ENUM_NEXT (GTK_TYPE_POSITION_TYPE, 5, test->gap_side);
	else
		test->gap_side = wildcard_test->gap_side;

	if (wildcard_test->orientation == ORIENTATION_ALL)
		ENUM_NEXT (GTK_TYPE_ORIENTATION, 6, test->orientation);
	else
		test->orientation = wildcard_test->orientation;

	if (wildcard_test->expander_style == EXPANDER_ALL)
		ENUM_NEXT (GTK_TYPE_EXPANDER_STYLE, 7, test->expander_style);
	else
		test->expander_style = wildcard_test->expander_style;

	if (wildcard_test->edge == EDGE_ALL)
		ENUM_NEXT (GDK_TYPE_WINDOW_EDGE, 8, test->edge);
	else
		test->edge = wildcard_test->edge;
	
end:
	/* the detail is a : seperated list ... */
	if (initial) {
		values[9] = 0;
	} else {
		values[9]++;
	}
	i = 0;
	cur_pos = wildcard_test->detail;
	
	while (i < values[9] && cur_pos) {
		cur_pos = strchr (cur_pos, ':');
		if (cur_pos != NULL) cur_pos++;
		i++;
	}
	if (cur_pos == NULL) {
		values[9] = 0;
		cur_pos = wildcard_test->detail;
	} else {
		if (done)
			return TRUE;
	}
	if (cur_pos != NULL) {
		col_pos = strchr (cur_pos, ':');
		if (col_pos == NULL)
			test->detail = g_strdup (cur_pos);
		else
			test->detail = g_strndup (cur_pos, col_pos - cur_pos);
	} else
		test->detail = NULL;
	
	return done;
}

static void
run_functions (Test *test)
{
	GtkStyle *style = window->style;
	
	if (test->function & FUNCTION_ARROW)
		gtk_paint_arrow (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, test->arrow_type, test->fill, 0, 0, 10, 10);

	if (test->function & FUNCTION_BOX)
		gtk_paint_box (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);

	if (test->function & FUNCTION_SHADOW)
		gtk_paint_shadow (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);

	if (test->function & FUNCTION_BOX_GAP)
		gtk_paint_box_gap (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10, test->gap_side, 0, 100);

	if (test->function & FUNCTION_SHADOW_GAP)
		gtk_paint_shadow_gap (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10, test->gap_side, 0, 100);


	if (test->function & FUNCTION_CHECK)
		gtk_paint_check (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);
		
	if (test->function & FUNCTION_EXPANDER)
		gtk_paint_expander (window->style, window->window, test->state, NULL, widgets[test->widget], test->detail, 10, 10, test->expander_style);

	if (test->function & FUNCTION_EXTENSION)
		gtk_paint_extension (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10, test->gap_side);

	if (test->function & FUNCTION_FLAT_BOX)
		gtk_paint_flat_box (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);

	if (test->function & FUNCTION_FOCUS)
		gtk_paint_focus (window->style, window->window, test->state, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);

	if (test->function & FUNCTION_HANDLE)
		gtk_paint_handle (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10, test->orientation);

	if (test->function & FUNCTION_OPTION)
		gtk_paint_option (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);

	if (test->function & FUNCTION_RESIZE_GRIP)
		gtk_paint_resize_grip (window->style, window->window, test->state, NULL, widgets[test->widget], test->detail, test->edge, 0, 0, 10, 10);

	if (test->function & FUNCTION_SLIDER)
		gtk_paint_slider (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10, test->orientation);

	if (test->function & FUNCTION_TAB)
		gtk_paint_tab (window->style, window->window, test->state, test->shadow, NULL, widgets[test->widget], test->detail, 0, 0, 10, 10);


	if (test->function & FUNCTION_HLINE)
		gtk_paint_hline (window->style, window->window, test->state, NULL, widgets[test->widget], test->detail, 1, 10, 4);

	if (test->function & FUNCTION_VLINE)
		gtk_paint_vline (window->style, window->window, test->state, NULL, widgets[test->widget], test->detail, 1, 10, 4);
}

static void
run_test (gint test)
{
	Test current_test;
	gint initial = TRUE;
	
	while (!get_next_combination (&tests[test], &current_test, initial)) {
		initial = FALSE;
		run_functions (&current_test);
		g_free (current_test.detail);
	}
}

static void
create_testwidgets ()
{
	widgets[WIDGET_HSCROLLBAR] = gtk_hscrollbar_new (NULL);
	widgets[WIDGET_VSCROLLBAR] = gtk_vscrollbar_new (NULL);
	widgets[WIDGET_BUTTON] = gtk_button_new_with_label ("blah");
	widgets[WIDGET_TOGGLE_BUTTON] = gtk_toggle_button_new_with_label ("blah");
}

int
main (int argc, char **argv)
{
	gint i;
	char *env;
	GtkSettings *settings;

	gtk_init (&argc, &argv);
          
	env = getenv ("GTK_THEME");
	
	if (env != NULL) {
		settings = gtk_settings_get_default ();
		g_object_set (settings, "gtk-theme-name", env);
	}
	
	create_testwidgets ();
	
	window = gtk_window_new (GDK_WINDOW_TOPLEVEL);
	gtk_widget_show (window);
	while (gdk_events_pending ())
		gtk_main_iteration_do (FALSE);
	
	for (i = 0; i < G_N_ELEMENTS (tests); i++)
		run_test (i);
	
	return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]