#include "gtkfishbowl.h"
+char **icon_names = NULL;
+gsize n_icon_names = 0;
+
+static void
+init_icon_names (GtkIconTheme *theme)
+{
+ GPtrArray *icons;
+ GList *l, *icon_list;
+
+ if (icon_names)
+ return;
+
+ icon_list = gtk_icon_theme_list_icons (theme, NULL);
+ icons = g_ptr_array_new ();
+
+ for (l = icon_list; l; l = l->next)
+ {
+ if (g_str_has_suffix (l->data, "symbolic"))
+ continue;
+
+ g_ptr_array_add (icons, g_strdup (l->data));
+ }
+
+ n_icon_names = icons->len;
+ g_ptr_array_add (icons, NULL); /* NULL-terminate the array */
+ icon_names = (char **) g_ptr_array_free (icons, FALSE);
+
+ /* don't free strings, we assigned them to the array */
+ g_list_free_full (icon_list, g_free);
+}
+
+static const char *
+get_random_icon_name (GtkIconTheme *theme)
+{
+ init_icon_names (theme);
+
+ return icon_names[g_random_int_range(0, n_icon_names)];
+}
+
+GtkWidget *
+create_icon (void)
+{
+ GtkWidget *image;
+
+ image = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()));
+ gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
+
+ return image;
+}
+
GtkWidget *
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);
+ gtk_fishbowl_set_creation_func (GTK_FISHBOWL (bowl), create_icon);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
struct _GtkFishbowlPrivate
{
+ GtkFishCreationFunc creation_func;
GList *children;
guint count;
double framerate;
int last_benchmark_change;
- guint use_icons : 1;
guint benchmark : 1;
};
static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
-G_DEFINE_TYPE_WITH_PRIVATE (GtkFishbowl, gtk_fishbowl, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_PRIVATE (GtkFishbowl, gtk_fishbowl, GTK_TYPE_WIDGET)
static void
gtk_fishbowl_init (GtkFishbowl *fishbowl)
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,
}
static void
-gtk_fishbowl_add (GtkContainer *container,
- GtkWidget *widget)
+gtk_fishbowl_add (GtkFishbowl *fishbowl,
+ GtkWidget *widget)
{
- GtkFishbowl *fishbowl = GTK_FISHBOWL (container);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child_info;
}
static void
-gtk_fishbowl_remove (GtkContainer *container,
- GtkWidget *widget)
+gtk_fishbowl_remove (GtkFishbowl *fishbowl,
+ GtkWidget *widget)
{
- GtkFishbowl *fishbowl = GTK_FISHBOWL (container);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
- GtkWidget *widget_container = GTK_WIDGET (container);
+ GtkWidget *widget_bowl = GTK_WIDGET (fishbowl);
GList *children;
for (children = priv->children; children; children = children->next)
g_list_free (children);
g_free (child);
- if (was_visible && gtk_widget_get_visible (widget_container))
- gtk_widget_queue_resize (widget_container);
+ if (was_visible && gtk_widget_get_visible (widget_bowl))
+ gtk_widget_queue_resize (widget_bowl);
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
}
}
-static void
-gtk_fishbowl_forall (GtkContainer *container,
- GtkCallback callback,
- gpointer callback_data)
-{
- GtkFishbowl *fishbowl = GTK_FISHBOWL (container);
- GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
- GtkFishbowlChild *child;
- GList *children;
-
- children = priv->children;
- while (children)
- {
- child = children->data;
- children = children->next;
-
- (* callback) (child->widget, callback_data);
- }
-}
-
static void
gtk_fishbowl_dispose (GObject *object)
{
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
object_class->dispose = gtk_fishbowl_dispose;
object_class->set_property = gtk_fishbowl_set_property;
widget_class->measure = gtk_fishbowl_measure;
widget_class->size_allocate = gtk_fishbowl_size_allocate;
- container_class->add = gtk_fishbowl_add;
- container_class->remove = gtk_fishbowl_remove;
- container_class->forall = gtk_fishbowl_forall;
-
props[PROP_ANIMATING] =
g_param_spec_boolean ("animating",
"animating",
return priv->count;
}
-char **icon_names = NULL;
-gsize n_icon_names = 0;
-
-static void
-init_icon_names (GtkIconTheme *theme)
-{
- GPtrArray *icons;
- GList *l, *icon_list;
-
- if (icon_names)
- return;
-
- icon_list = gtk_icon_theme_list_icons (theme, NULL);
- icons = g_ptr_array_new ();
-
- for (l = icon_list; l; l = l->next)
- {
- if (g_str_has_suffix (l->data, "symbolic"))
- continue;
-
- g_ptr_array_add (icons, g_strdup (l->data));
- }
-
- n_icon_names = icons->len;
- g_ptr_array_add (icons, NULL); /* NULL-terminate the array */
- icon_names = (char **) g_ptr_array_free (icons, FALSE);
-
- /* don't free strings, we assigned them to the array */
- g_list_free_full (icon_list, g_free);
-}
-
-static const char *
-get_random_icon_name (GtkIconTheme *theme)
-{
- init_icon_names (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)
{
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+ if (priv->count == count)
+ return;
+
g_object_freeze_notify (G_OBJECT (fishbowl));
while (priv->count > count)
{
- gtk_container_remove (GTK_CONTAINER (fishbowl),
- ((GtkFishbowlChild *) priv->children->data)->widget);
+ gtk_fishbowl_remove (fishbowl, gtk_widget_get_first_child (GTK_WIDGET (fishbowl)));
}
while (priv->count < count)
{
GtkWidget *new_widget;
- if (priv->use_icons)
- {
- new_widget = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()));
- gtk_image_set_icon_size (GTK_IMAGE (new_widget), GTK_ICON_SIZE_LARGE);
- }
- else
- new_widget = g_object_new (get_random_widget_type (), NULL);
+ new_widget = priv->creation_func ();
- gtk_container_add (GTK_CONTAINER (fishbowl), new_widget);
+ gtk_fishbowl_add (fishbowl, new_widget);
}
g_object_thaw_notify (G_OBJECT (fishbowl));
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_UPDATE_DELAY]);
}
+void
+gtk_fishbowl_set_creation_func (GtkFishbowl *fishbowl,
+ GtkFishCreationFunc creation_func)
+{
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+ g_object_freeze_notify (G_OBJECT (fishbowl));
+
+ gtk_fishbowl_set_count (fishbowl, 0);
+
+ priv->creation_func = creation_func;
+
+ g_object_thaw_notify (G_OBJECT (fishbowl));
+}
typedef struct _GtkFishbowl GtkFishbowl;
typedef struct _GtkFishbowlClass GtkFishbowlClass;
+typedef GtkWidget * (* GtkFishCreationFunc) (void);
+
struct _GtkFishbowl
{
- GtkContainer container;
+ GtkWidget parent;
};
struct _GtkFishbowlClass
{
- GtkContainerClass parent_class;
+ GtkWidgetClass parent_class;
};
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);
gint64 gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl);
void gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl,
gint64 update_delay);
+void gtk_fishbowl_set_creation_func (GtkFishbowl *fishbowl,
+ GtkFishCreationFunc creation_func);
G_END_DECLS
set_widget_type (GtkWidget *headerbar,
int widget_type_index)
{
- GList *children, *l;
-
if (widget_type_index == selected_widget_type)
return;
- /* Remove everything */
- children = gtk_container_get_children (GTK_CONTAINER (fishbowl));
- for (l = children; l; l = l->next)
- {
- gtk_container_remove (GTK_CONTAINER (fishbowl), (GtkWidget*)l->data);
- }
-
- g_list_free (children);
-
selected_widget_type = widget_type_index;
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar),
widget_types[selected_widget_type].name);
-}
-
-
-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, &suggested_change);
-
- if (suggested_change > 0)
- {
- int i;
-
- for (i = 0; i < suggested_change; i ++)
- {
- GtkWidget *new_widget = widget_types[selected_widget_type].create_func ();
-
- gtk_container_add (GTK_CONTAINER (fishbowl), new_widget);
-
- }
- }
- else if (suggested_change < 0)
- {
- GList *children, *l;
- int n_removed = 0;
-
- children = gtk_container_get_children (GTK_CONTAINER (fishbowl));
- for (l = children; l; l = l->next)
- {
- gtk_container_remove (GTK_CONTAINER (fishbowl), (GtkWidget *)l->data);
- n_removed ++;
-
- if (n_removed >= (-suggested_change))
- break;
- }
-
- g_list_free (children);
- }
-
- stats_update (bowl);
-
- return G_SOURCE_CONTINUE;
+ gtk_fishbowl_set_creation_func (GTK_FISHBOWL (fishbowl),
+ widget_types[selected_widget_type].create_func);
}
static void
g_signal_connect (prev_button, "clicked", G_CALLBACK (prev_button_clicked_cb), titlebar);
gtk_fishbowl_set_animating (GTK_FISHBOWL (fishbowl), TRUE);
+ gtk_fishbowl_set_benchmark (GTK_FISHBOWL (fishbowl), TRUE);
gtk_widget_set_hexpand (title_box, TRUE);
gtk_widget_set_halign (title_box, GTK_ALIGN_END);
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_widget_realize (window);
- gtk_widget_add_tick_callback (fishbowl, move_fish, info_label, NULL);
set_widget_type (titlebar, 0);
}