diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am index b3bcd7de69..ea20c49684 100644 --- a/demos/gtk-demo/Makefile.am +++ b/demos/gtk-demo/Makefile.am @@ -28,6 +28,7 @@ demos_base = \ expander.c \ filtermodel.c \ fishbowl.c \ + widgetbowl.c \ foreigndrawing.c \ gestures.c \ glarea.c \ diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 2604f1801b..17eb5c430c 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -156,6 +156,7 @@ expander.c filtermodel.c fishbowl.c + widgetbowl.c flowbox.c foreigndrawing.c font_features.c diff --git a/demos/gtk-demo/fishbowl.c b/demos/gtk-demo/fishbowl.c index db49822fc5..4d8765517a 100644 --- a/demos/gtk-demo/fishbowl.c +++ b/demos/gtk-demo/fishbowl.c @@ -157,6 +157,7 @@ do_fishbowl (GtkWidget *do_widget) gtk_builder_connect_signals (builder, NULL); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl")); + gtk_fishbowl_set_use_icons (GTK_FISHBOWL (bowl), TRUE); info_label = GTK_WIDGET (gtk_builder_get_object (builder, "info_label")); allow_changes = GTK_WIDGET (gtk_builder_get_object (builder, "changes_allow")); gtk_window_set_screen (GTK_WINDOW (window), diff --git a/demos/gtk-demo/fishbowl.ui b/demos/gtk-demo/fishbowl.ui index 538f9ba68a..f1869990e6 100644 --- a/demos/gtk-demo/fishbowl.ui +++ b/demos/gtk-demo/fishbowl.ui @@ -10,7 +10,6 @@ True - icons - 0 fps end diff --git a/demos/gtk-demo/gtkfishbowl.c b/demos/gtk-demo/gtkfishbowl.c index 447610c3c7..d3343eb796 100644 --- a/demos/gtk-demo/gtkfishbowl.c +++ b/demos/gtk-demo/gtkfishbowl.c @@ -29,6 +29,8 @@ struct _GtkFishbowlPrivate gint64 last_frame_time; guint tick_id; + + guint use_icons: 1; }; struct _GtkFishbowlChild @@ -70,6 +72,15 @@ gtk_fishbowl_new (void) return g_object_new (GTK_TYPE_FISHBOWL, NULL); } +void +gtk_fishbowl_set_use_icons (GtkFishbowl *fishbowl, + gboolean use_icons) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + + priv->use_icons = use_icons; +} + static void gtk_fishbowl_measure (GtkWidget *widget, GtkOrientation orientation, @@ -218,27 +229,6 @@ gtk_fishbowl_forall (GtkContainer *container, } } -static void -gtk_fishbowl_snapshot (GtkWidget *widget, - GtkSnapshot *snapshot) -{ - GtkFishbowl *fishbowl = GTK_FISHBOWL (widget); - GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); - GtkFishbowlChild *child; - GList *list; - - for (list = priv->children; - list; - list = list->next) - { - child = list->data; - - gtk_widget_snapshot_child (widget, - child->widget, - snapshot); - } -} - static void gtk_fishbowl_dispose (GObject *object) { @@ -311,7 +301,6 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass) widget_class->measure = gtk_fishbowl_measure; widget_class->size_allocate = gtk_fishbowl_size_allocate; - widget_class->snapshot = gtk_fishbowl_snapshot; container_class->add = gtk_fishbowl_add; container_class->remove = gtk_fishbowl_remove; @@ -382,6 +371,25 @@ get_random_icon_name (GtkIconTheme *theme) return icon_names[g_random_int_range(0, n_icon_names)]; } +static GType +get_random_widget_type () +{ + GType types[] = { + GTK_TYPE_SWITCH, + GTK_TYPE_BUTTON, + GTK_TYPE_ENTRY, + GTK_TYPE_SPIN_BUTTON, + GTK_TYPE_FONT_BUTTON, + GTK_TYPE_SCROLLBAR, + GTK_TYPE_SCALE, + GTK_TYPE_LEVEL_BAR, + GTK_TYPE_PROGRESS_BAR, + GTK_TYPE_RADIO_BUTTON, + GTK_TYPE_CHECK_BUTTON + }; + return types[g_random_int_range (0, G_N_ELEMENTS (types))]; +} + void gtk_fishbowl_set_count (GtkFishbowl *fishbowl, guint count) @@ -399,10 +407,13 @@ gtk_fishbowl_set_count (GtkFishbowl *fishbowl, while (priv->count < count) { GtkWidget *new_widget; - - new_widget = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()), - GTK_ICON_SIZE_DIALOG); - gtk_widget_show (new_widget); + + if (priv->use_icons) + new_widget = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()), + GTK_ICON_SIZE_DIALOG); + else + new_widget = g_object_new (get_random_widget_type (), NULL); + gtk_container_add (GTK_CONTAINER (fishbowl), new_widget); } diff --git a/demos/gtk-demo/gtkfishbowl.h b/demos/gtk-demo/gtkfishbowl.h index 2ac1ad12ea..b1559d0b26 100644 --- a/demos/gtk-demo/gtkfishbowl.h +++ b/demos/gtk-demo/gtkfishbowl.h @@ -46,6 +46,9 @@ GType gtk_fishbowl_get_type (void) G_GNUC_CONST; GtkWidget* gtk_fishbowl_new (void); +void gtk_fishbowl_set_use_icons (GtkFishbowl *fishbowl, + gboolean use_icons); + guint gtk_fishbowl_get_count (GtkFishbowl *fishbowl); void gtk_fishbowl_set_count (GtkFishbowl *fishbowl, guint count); diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index 6acfa168de..ea34ee3846 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -25,6 +25,7 @@ demos = files([ 'expander.c', 'filtermodel.c', 'fishbowl.c', + 'widgetbowl.c', 'foreigndrawing.c', 'gestures.c', 'glarea.c', diff --git a/demos/gtk-demo/widgetbowl.c b/demos/gtk-demo/widgetbowl.c new file mode 100644 index 0000000000..074e00a8a8 --- /dev/null +++ b/demos/gtk-demo/widgetbowl.c @@ -0,0 +1,179 @@ +/* Benchmark/Widgetbowl + * + * This demo models the fishbowl demos seen on the web in a GTK way. + * It's also a neat little tool to see how fast your computer (or + * your GTK version) is. + */ + +#include + +#include "gtkfishbowl.h" + +GtkWidget *allow_changes; + +#define N_STATS 5 + +#define STATS_UPDATE_TIME G_USEC_PER_SEC + +typedef struct _Stats Stats; +struct _Stats { + gint64 last_stats; + gint64 last_frame; + gint last_suggestion; + guint frame_counter_max; + + guint stats_index; + guint frame_counter[N_STATS]; + guint item_counter[N_STATS]; +}; + +static Stats * +get_stats (GtkWidget *widget) +{ + static GQuark stats_quark = 0; + Stats *stats; + + if (G_UNLIKELY (stats_quark == 0)) + stats_quark = g_quark_from_static_string ("stats"); + + stats = g_object_get_qdata (G_OBJECT (widget), stats_quark); + if (stats == NULL) + { + stats = g_new0 (Stats, 1); + g_object_set_qdata_full (G_OBJECT (widget), stats_quark, stats, g_free); + stats->last_frame = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget)); + stats->last_stats = stats->last_frame; + } + + return stats; +} + +static void +do_stats (GtkWidget *widget, + GtkWidget *info_label, + gint *suggested_change) +{ + Stats *stats; + gint64 frame_time; + + stats = get_stats (widget); + frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget)); + + if (stats->last_stats + STATS_UPDATE_TIME < frame_time) + { + char *new_label; + guint i, n_frames; + + n_frames = 0; + for (i = 0; i < N_STATS; i++) + { + n_frames += stats->frame_counter[i]; + } + + new_label = g_strdup_printf ("widgets - %.1f fps", + (double) G_USEC_PER_SEC * n_frames + / (N_STATS * STATS_UPDATE_TIME)); + gtk_label_set_label (GTK_LABEL (info_label), new_label); + g_free (new_label); + + if (stats->frame_counter[stats->stats_index] >= 19 * stats->frame_counter_max / 20) + { + if (stats->last_suggestion > 0) + stats->last_suggestion *= 2; + else + stats->last_suggestion = 1; + } + else + { + if (stats->last_suggestion < 0) + stats->last_suggestion--; + else + stats->last_suggestion = -1; + stats->last_suggestion = MAX (stats->last_suggestion, 1 - (int) stats->item_counter[stats->stats_index]); + } + + stats->stats_index = (stats->stats_index + 1) % N_STATS; + stats->frame_counter[stats->stats_index] = 0; + stats->item_counter[stats->stats_index] = stats->item_counter[(stats->stats_index + N_STATS - 1) % N_STATS]; + stats->last_stats = frame_time; + + if (suggested_change) + *suggested_change = stats->last_suggestion; + else + stats->last_suggestion = 0; + } + else + { + if (suggested_change) + *suggested_change = 0; + } + + stats->last_frame = frame_time; + stats->frame_counter[stats->stats_index]++; + stats->frame_counter_max = MAX (stats->frame_counter_max, stats->frame_counter[stats->stats_index]); +} + +static void +stats_update (GtkWidget *widget) +{ + Stats *stats; + + stats = get_stats (widget); + + stats->item_counter[stats->stats_index] = gtk_fishbowl_get_count (GTK_FISHBOWL (widget)); +} + +static gboolean +move_fish (GtkWidget *bowl, + GdkFrameClock *frame_clock, + gpointer info_label) +{ + gint suggested_change = 0; + + do_stats (bowl, + info_label, + !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (allow_changes)) ? &suggested_change : NULL); + + gtk_fishbowl_set_count (GTK_FISHBOWL (bowl), + gtk_fishbowl_get_count (GTK_FISHBOWL (bowl)) + suggested_change); + stats_update (bowl); + + return G_SOURCE_CONTINUE; +} + +GtkWidget * +do_widgetbowl (GtkWidget *do_widget) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkBuilder *builder; + GtkWidget *bowl, *info_label; + + g_type_ensure (GTK_TYPE_FISHBOWL); + + builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui"); + gtk_builder_connect_signals (builder, NULL); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl")); + gtk_fishbowl_set_use_icons (GTK_FISHBOWL (bowl), FALSE); + info_label = GTK_WIDGET (gtk_builder_get_object (builder, "info_label")); + allow_changes = GTK_WIDGET (gtk_builder_get_object (builder, "changes_allow")); + gtk_window_set_screen (GTK_WINDOW (window), + gtk_widget_get_screen (do_widget)); + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_widget_destroyed), &window); + + gtk_widget_realize (window); + gtk_widget_add_tick_callback (bowl, move_fish, info_label, NULL); + } + + if (!gtk_widget_get_visible (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); + + + return window; +}