summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2018-04-25 23:57:44 +0200
committerBenjamin Otte <otte@redhat.com>2018-04-26 00:32:44 +0200
commitf5482e6954cb2aca70d14064ec28a3a38d1fd831 (patch)
tree83244c73b769c8f1112bbe0ae8d7186ddf8f97fd
parentfff08fa319dff8542a3f3481a5273523bdfd5dd9 (diff)
downloadgtk+-f5482e6954cb2aca70d14064ec28a3a38d1fd831.tar.gz
fishbowl: Port version from GTK 4
This version also merges widgetbowl into fishbowl.
-rw-r--r--demos/gtk-demo/Makefile.am1
-rw-r--r--demos/gtk-demo/demo.gresource.xml1
-rw-r--r--demos/gtk-demo/fishbowl.c307
-rw-r--r--demos/gtk-demo/fishbowl.ui68
-rw-r--r--demos/gtk-demo/gtkfishbowl.c425
-rw-r--r--demos/gtk-demo/gtkfishbowl.h13
-rw-r--r--demos/gtk-demo/widgetbowl.c365
7 files changed, 549 insertions, 631 deletions
diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am
index decba7d0e2..261d555ae5 100644
--- a/demos/gtk-demo/Makefile.am
+++ b/demos/gtk-demo/Makefile.am
@@ -28,7 +28,6 @@ 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 7ab207c692..a02c4843f9 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -156,7 +156,6 @@
<file>expander.c</file>
<file>filtermodel.c</file>
<file>fishbowl.c</file>
- <file>widgetbowl.c</file>
<file>flowbox.c</file>
<file>foreigndrawing.c</file>
<file>font_features.c</file>
diff --git a/demos/gtk-demo/fishbowl.c b/demos/gtk-demo/fishbowl.c
index db49822fc5..549d09d54c 100644
--- a/demos/gtk-demo/fishbowl.c
+++ b/demos/gtk-demo/fishbowl.c
@@ -9,163 +9,254 @@
#include "gtkfishbowl.h"
-GtkWidget *allow_changes;
+const char *const css =
+".blurred-button {"
+" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
+"}"
+"";
-#define N_STATS 5
+char **icon_names = NULL;
+gsize n_icon_names = 0;
-#define STATS_UPDATE_TIME G_USEC_PER_SEC
+static void
+init_icon_names (GtkIconTheme *theme)
+{
+ GPtrArray *icons;
+ GList *l, *icon_list;
-typedef struct _Stats Stats;
-struct _Stats {
- gint64 last_stats;
- gint64 last_frame;
- gint last_suggestion;
- guint frame_counter_max;
+ if (icon_names)
+ return;
- guint stats_index;
- guint frame_counter[N_STATS];
- guint item_counter[N_STATS];
-};
+ 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 Stats *
-get_stats (GtkWidget *widget)
+static const char *
+get_random_icon_name (GtkIconTheme *theme)
{
- static GQuark stats_quark = 0;
- Stats *stats;
+ init_icon_names (theme);
- if (G_UNLIKELY (stats_quark == 0))
- stats_quark = g_quark_from_static_string ("stats");
+ return icon_names[g_random_int_range(0, n_icon_names)];
+}
- 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;
- }
+GtkWidget *
+create_icon (void)
+{
+ GtkWidget *image;
- return stats;
+ image = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()), GTK_ICON_SIZE_DND);
+
+ return image;
}
-static void
-do_stats (GtkWidget *widget,
- GtkWidget *info_label,
- gint *suggested_change)
+static GtkWidget *
+create_button (void)
{
- Stats *stats;
- gint64 frame_time;
+ return gtk_button_new_with_label ("Button");
+}
- stats = get_stats (widget);
- frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
+static GtkWidget *
+create_blurred_button (void)
+{
+ GtkWidget *w = gtk_button_new ();
- 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 ("icons - %.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;
- }
+ gtk_style_context_add_class (gtk_widget_get_style_context (w), "blurred-button");
+
+ return w;
+}
+
+static GtkWidget *
+create_font_button (void)
+{
+ return gtk_font_button_new ();
+}
+
+static GtkWidget *
+create_level_bar (void)
+{
+ GtkWidget *w = gtk_level_bar_new_for_interval (0, 100);
+
+ gtk_level_bar_set_value (GTK_LEVEL_BAR (w), 50);
+
+ /* Force them to be a bit larger */
+ gtk_widget_set_size_request (w, 200, -1);
- 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]);
+ return w;
}
+static GtkWidget *
+create_spinner (void)
+{
+ GtkWidget *w = gtk_spinner_new ();
+
+ gtk_spinner_start (GTK_SPINNER (w));
+
+ return w;
+}
+
+static GtkWidget *
+create_spinbutton (void)
+{
+ GtkWidget *w = gtk_spin_button_new_with_range (0, 10, 1);
+
+ return w;
+}
+
+static GtkWidget *
+create_label (void)
+{
+ GtkWidget *w = gtk_label_new ("pLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.");
+
+ gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
+ gtk_label_set_max_width_chars (GTK_LABEL (w), 100);
+
+ return w;
+}
+
+#if 0
+static GtkWidget *
+create_gears (void)
+{
+ GtkWidget *w = gtk_gears_new ();
+
+ gtk_widget_set_size_request (w, 100, 100);
+
+ return w;
+}
+#endif
+
+static GtkWidget *
+create_switch (void)
+{
+ GtkWidget *w = gtk_switch_new ();
+
+ gtk_switch_set_state (GTK_SWITCH (w), TRUE);
+
+ return w;
+}
+
+static const struct {
+ const char *name;
+ GtkWidget * (*create_func) (void);
+} widget_types[] = {
+ { "Icon", create_icon },
+ { "Button", create_button },
+ { "Blurbutton", create_blurred_button },
+ { "Fontbutton", create_font_button },
+ { "Levelbar", create_level_bar },
+ { "Label", create_label },
+ { "Spinner", create_spinner },
+ { "Spinbutton", create_spinbutton },
+ // { "Gears", create_gears },
+ { "Switch", create_switch },
+};
+
+static int selected_widget_type = -1;
+static const int N_WIDGET_TYPES = G_N_ELEMENTS (widget_types);
+
static void
-stats_update (GtkWidget *widget)
+set_widget_type (GtkFishbowl *fishbowl,
+ int widget_type_index)
+{
+ GtkWidget *window, *headerbar;
+
+ if (widget_type_index == selected_widget_type)
+ return;
+
+ selected_widget_type = widget_type_index;
+
+ gtk_fishbowl_set_creation_func (fishbowl,
+ widget_types[selected_widget_type].create_func);
+
+ window = gtk_widget_get_toplevel (GTK_WIDGET (fishbowl));
+ headerbar = gtk_window_get_titlebar (GTK_WINDOW (window));
+ gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar),
+ widget_types[selected_widget_type].name);
+}
+
+void
+next_button_clicked_cb (GtkButton *source,
+ gpointer user_data)
{
- Stats *stats;
+ GtkFishbowl *fishbowl = user_data;
+ int new_index;
- stats = get_stats (widget);
+ if (selected_widget_type + 1 >= N_WIDGET_TYPES)
+ new_index = 0;
+ else
+ new_index = selected_widget_type + 1;
- stats->item_counter[stats->stats_index] = gtk_fishbowl_get_count (GTK_FISHBOWL (widget));
+ set_widget_type (fishbowl, new_index);
}
-static gboolean
-move_fish (GtkWidget *bowl,
- GdkFrameClock *frame_clock,
- gpointer info_label)
+void
+prev_button_clicked_cb (GtkButton *source,
+ gpointer user_data)
{
- gint suggested_change = 0;
-
- do_stats (bowl,
- info_label,
- !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (allow_changes)) ? &suggested_change : NULL);
+ GtkFishbowl *fishbowl = user_data;
+ int new_index;
- gtk_fishbowl_set_count (GTK_FISHBOWL (bowl),
- gtk_fishbowl_get_count (GTK_FISHBOWL (bowl)) + suggested_change);
- stats_update (bowl);
+ if (selected_widget_type - 1 < 0)
+ new_index = N_WIDGET_TYPES - 1;
+ else
+ new_index = selected_widget_type - 1;
- return G_SOURCE_CONTINUE;
+ set_widget_type (fishbowl, new_index);
}
+
GtkWidget *
do_fishbowl (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
+ static GtkCssProvider *provider = NULL;
+
+ if (provider == NULL)
+ {
+ provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_data (provider, css, -1, NULL);
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
if (!window)
{
GtkBuilder *builder;
- GtkWidget *bowl, *info_label;
+ GtkWidget *bowl;
g_type_ensure (GTK_TYPE_FISHBOWL);
builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui");
+ gtk_builder_add_callback_symbols (builder,
+ "next_button_clicked_cb", G_CALLBACK (next_button_clicked_cb),
+ "prev_button_clicked_cb", G_CALLBACK (prev_button_clicked_cb),
+ NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl"));
- info_label = GTK_WIDGET (gtk_builder_get_object (builder, "info_label"));
- allow_changes = GTK_WIDGET (gtk_builder_get_object (builder, "changes_allow"));
+ set_widget_type (GTK_FISHBOWL (bowl), 0);
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))
diff --git a/demos/gtk-demo/fishbowl.ui b/demos/gtk-demo/fishbowl.ui
index 403a03bc88..6f1f985aea 100644
--- a/demos/gtk-demo/fishbowl.ui
+++ b/demos/gtk-demo/fishbowl.ui
@@ -8,27 +8,76 @@
<property name="visible">True</property>
<property name="show-close-button">True</property>
<child>
- <object class="GtkLabel" id="info_label">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="label">icons - 0 fps</property>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">pan-start-symbolic</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <signal name="clicked" handler="prev_button_clicked_cb" object="bowl" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">pan-end-symbolic</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <signal name="clicked" handler="next_button_clicked_cb" object="bowl" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label">fps</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" bind-source="bowl" bind-property="framerate"/>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label">Icons, </property>
</object>
<packing>
- <property name="pack_type">end</property>
+ <property name="pack-type">end</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
- <property name="label" bind-source="bowl" bind-property="count">0</property>
+ <property name="label" bind-source="bowl" bind-property="count"/>
</object>
<packing>
- <property name="pack_type">end</property>
+ <property name="pack-type">end</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="changes_allow">
- <property name="active">False</property>
- <property name="visible" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean">True</property>
+ <property name="visible" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean"/>
<property name="relief">none</property>
<child>
<object class="GtkImage">
@@ -38,7 +87,7 @@
</child>
</object>
<packing>
- <property name="pack_type">end</property>
+ <property name="pack-type">end</property>
</packing>
</child>
<child>
@@ -54,7 +103,7 @@
</child>
</object>
<packing>
- <property name="pack_type">end</property>
+ <property name="pack-type">end</property>
</packing>
</child>
</object>
@@ -63,6 +112,7 @@
<object class="GtkFishbowl" id="bowl">
<property name="visible">True</property>
<property name="animating">True</property>
+ <property name="benchmark" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean">True</property>
</object>
</child>
</object>
diff --git a/demos/gtk-demo/gtkfishbowl.c b/demos/gtk-demo/gtkfishbowl.c
index 4f2a2d571f..5101210fd1 100644
--- a/demos/gtk-demo/gtkfishbowl.c
+++ b/demos/gtk-demo/gtkfishbowl.c
@@ -19,18 +19,25 @@
#include "gtkfishbowl.h"
-#include "gtk/fallback-c89.c"
+#include <math.h>
typedef struct _GtkFishbowlPrivate GtkFishbowlPrivate;
typedef struct _GtkFishbowlChild GtkFishbowlChild;
struct _GtkFishbowlPrivate
{
+ GtkFishCreationFunc creation_func;
GList *children;
guint count;
gint64 last_frame_time;
+ gint64 update_delay;
guint tick_id;
+
+ double framerate;
+ int last_benchmark_change;
+
+ guint benchmark : 1;
};
struct _GtkFishbowlChild
@@ -45,7 +52,10 @@ struct _GtkFishbowlChild
enum {
PROP_0,
PROP_ANIMATING,
+ PROP_BENCHMARK,
PROP_COUNT,
+ PROP_FRAMERATE,
+ PROP_UPDATE_DELAY,
NUM_PROPERTIES
};
@@ -56,7 +66,11 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkFishbowl, gtk_fishbowl, GTK_TYPE_CONTAINER)
static void
gtk_fishbowl_init (GtkFishbowl *fishbowl)
{
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
gtk_widget_set_has_window (GTK_WIDGET (fishbowl), FALSE);
+
+ priv->update_delay = G_USEC_PER_SEC;
}
/**
@@ -73,48 +87,9 @@ gtk_fishbowl_new (void)
}
static void
-gtk_widget_measure (GtkWidget *widget,
- GtkOrientation orientation,
- gint size,
- gint *minimum,
- gint *natural,
- gint *minimum_baseline,
- gint *natural_baseline)
-{
- g_return_if_fail (GTK_IS_WIDGET (widget));
- g_return_if_fail (size >= -1);
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- if (size < 0)
- gtk_widget_get_preferred_width (widget, minimum, natural);
- else
- gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural);
-
- if (minimum_baseline)
- *minimum_baseline = -1;
- if (natural_baseline)
- *natural_baseline = -1;
- }
- else
- {
- gtk_widget_get_preferred_height_and_baseline_for_width (widget,
- size,
- minimum,
- natural,
- minimum_baseline,
- natural_baseline);
- }
-}
-
-static void
-gtk_fishbowl_measure (GtkWidget *widget,
- GtkOrientation orientation,
- int for_size,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
+gtk_fishbowl_get_preferred_width (GtkWidget *widget,
+ int *minimum,
+ int *natural)
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
@@ -132,7 +107,7 @@ gtk_fishbowl_measure (GtkWidget *widget,
if (!gtk_widget_get_visible (child->widget))
continue;
- gtk_widget_measure (child->widget, orientation, -1, &child_min, &child_nat, NULL, NULL);
+ gtk_widget_get_preferred_width (child->widget, &child_min, &child_nat);
*minimum = MAX (*minimum, child_min);
*natural = MAX (*natural, child_nat);
@@ -140,39 +115,34 @@ gtk_fishbowl_measure (GtkWidget *widget,
}
static void
-gtk_fishbowl_get_preferred_width (GtkWidget *widget,
- int *minimum,
- int *natural)
-{
- gtk_fishbowl_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural, NULL, NULL);
-}
-
-static void
gtk_fishbowl_get_preferred_height (GtkWidget *widget,
int *minimum,
int *natural)
{
- gtk_fishbowl_measure (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural, NULL, NULL);
-}
+ GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+ GtkFishbowlChild *child;
+ GList *children;
+ gint child_min, child_nat;
-static void
-gtk_fishbowl_get_preferred_width_for_height (GtkWidget *widget,
- int for_size,
- int *minimum,
- int *natural)
-{
- gtk_fishbowl_measure (widget, GTK_ORIENTATION_HORIZONTAL, for_size, minimum, natural, NULL, NULL);
-}
+ *minimum = 0;
+ *natural = 0;
-static void
-gtk_fishbowl_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
- int for_size,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
-{
- gtk_fishbowl_measure (widget, GTK_ORIENTATION_VERTICAL, for_size, minimum, natural, minimum_baseline, natural_baseline);
+ for (children = priv->children; children; children = children->next)
+ {
+ int min_width;
+
+ child = children->data;
+
+ if (!gtk_widget_get_visible (child->widget))
+ continue;
+
+ gtk_widget_get_preferred_width (child->widget, &min_width, NULL);
+ gtk_widget_get_preferred_height_for_width (child->widget, min_width, &child_min, &child_nat);
+
+ *minimum = MAX (*minimum, child_min);
+ *natural = MAX (*natural, child_nat);
+ }
}
static void
@@ -186,8 +156,6 @@ gtk_fishbowl_size_allocate (GtkWidget *widget,
GtkRequisition child_requisition;
GList *children;
- gtk_widget_set_allocation (widget, allocation);
-
for (children = priv->children; children; children = children->next)
{
child = children->data;
@@ -244,7 +212,7 @@ gtk_fishbowl_remove (GtkContainer *container,
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)
@@ -261,8 +229,8 @@ gtk_fishbowl_remove (GtkContainer *container,
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]);
@@ -271,6 +239,7 @@ gtk_fishbowl_remove (GtkContainer *container,
}
}
+
static void
gtk_fishbowl_forall (GtkContainer *container,
gboolean include_internals,
@@ -295,29 +264,6 @@ gtk_fishbowl_forall (GtkContainer *container,
}
}
-static gboolean
-gtk_fishbowl_draw (GtkWidget *widget,
- cairo_t *cr)
-{
- 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_container_propagate_draw (GTK_CONTAINER (fishbowl),
- child->widget,
- cr);
- }
-
- return FALSE;
-}
-
static void
gtk_fishbowl_dispose (GObject *object)
{
@@ -343,10 +289,18 @@ gtk_fishbowl_set_property (GObject *object,
gtk_fishbowl_set_animating (fishbowl, g_value_get_boolean (value));
break;
+ case PROP_BENCHMARK:
+ gtk_fishbowl_set_benchmark (fishbowl, g_value_get_boolean (value));
+ break;
+
case PROP_COUNT:
gtk_fishbowl_set_count (fishbowl, g_value_get_uint (value));
break;
+ case PROP_UPDATE_DELAY:
+ gtk_fishbowl_set_update_delay (fishbowl, g_value_get_int64 (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -367,10 +321,22 @@ gtk_fishbowl_get_property (GObject *object,
g_value_set_boolean (value, gtk_fishbowl_get_animating (fishbowl));
break;
+ case PROP_BENCHMARK:
+ g_value_set_boolean (value, gtk_fishbowl_get_benchmark (fishbowl));
+ break;
+
case PROP_COUNT:
g_value_set_uint (value, gtk_fishbowl_get_count (fishbowl));
break;
+ case PROP_FRAMERATE:
+ g_value_set_double (value, gtk_fishbowl_get_framerate (fishbowl));
+ break;
+
+ case PROP_UPDATE_DELAY:
+ g_value_set_int64 (value, gtk_fishbowl_get_update_delay (fishbowl));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -390,10 +356,7 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
widget_class->get_preferred_width = gtk_fishbowl_get_preferred_width;
widget_class->get_preferred_height = gtk_fishbowl_get_preferred_height;
- widget_class->get_preferred_width_for_height = gtk_fishbowl_get_preferred_width_for_height;
- widget_class->get_preferred_height_and_baseline_for_width = gtk_fishbowl_get_preferred_height_and_baseline_for_width;
widget_class->size_allocate = gtk_fishbowl_size_allocate;
- widget_class->draw = gtk_fishbowl_draw;
container_class->add = gtk_fishbowl_add;
container_class->remove = gtk_fishbowl_remove;
@@ -406,13 +369,36 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
FALSE,
G_PARAM_READWRITE);
+ props[PROP_BENCHMARK] =
+ g_param_spec_boolean ("benchmark",
+ "Benchmark",
+ "Adapt the count property to hit the maximum framerate",
+ FALSE,
+ G_PARAM_READWRITE);
+
props[PROP_COUNT] =
g_param_spec_uint ("count",
"Count",
"Number of widgets",
0, G_MAXUINT,
0,
- G_PARAM_READABLE);
+ G_PARAM_READWRITE);
+
+ props[PROP_FRAMERATE] =
+ g_param_spec_double ("framerate",
+ "Framerate",
+ "Framerate of this widget in frames per second",
+ 0, G_MAXDOUBLE,
+ 0,
+ G_PARAM_READABLE);
+
+ props[PROP_UPDATE_DELAY] =
+ g_param_spec_int64 ("update-delay",
+ "Update delay",
+ "Number of usecs between updates",
+ 0, G_MAXINT64,
+ G_USEC_PER_SEC,
+ G_PARAM_READWRITE);
g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
}
@@ -425,70 +411,58 @@ gtk_fishbowl_get_count (GtkFishbowl *fishbowl)
return priv->count;
}
-char **icon_names = NULL;
-gsize n_icon_names = 0;
-
-static void
-init_icon_names (GtkIconTheme *theme)
+void
+gtk_fishbowl_set_count (GtkFishbowl *fishbowl,
+ guint count)
{
- GPtrArray *icons;
- GList *l, *icon_list;
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
- if (icon_names)
+ if (priv->count == count)
return;
- icon_list = gtk_icon_theme_list_icons (theme, NULL);
- icons = g_ptr_array_new ();
+ g_object_freeze_notify (G_OBJECT (fishbowl));
- for (l = icon_list; l; l = l->next)
+ while (priv->count > count)
{
- if (g_str_has_suffix (l->data, "symbolic"))
- continue;
-
- g_ptr_array_add (icons, g_strdup (l->data));
+ gtk_fishbowl_remove (GTK_CONTAINER (fishbowl), ((GtkFishbowlChild *) priv->children->data)->widget);
}
- n_icon_names = icons->len;
- g_ptr_array_add (icons, NULL); /* NULL-terminate the array */
- icon_names = (char **) g_ptr_array_free (icons, FALSE);
+ while (priv->count < count)
+ {
+ GtkWidget *new_widget;
- /* don't free strings, we assigned them to the array */
- g_list_free_full (icon_list, g_free);
+ new_widget = priv->creation_func ();
+
+ gtk_widget_show (new_widget);
+
+ gtk_fishbowl_add (GTK_CONTAINER (fishbowl), new_widget);
+ }
+
+ g_object_thaw_notify (G_OBJECT (fishbowl));
}
-static const char *
-get_random_icon_name (GtkIconTheme *theme)
+gboolean
+gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl)
{
- init_icon_names (theme);
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
- return icon_names[g_random_int_range(0, n_icon_names)];
+ return priv->benchmark;
}
void
-gtk_fishbowl_set_count (GtkFishbowl *fishbowl,
- guint count)
+gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl,
+ gboolean benchmark)
{
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
- g_object_freeze_notify (G_OBJECT (fishbowl));
-
- while (priv->count > count)
- {
- gtk_container_remove (GTK_CONTAINER (fishbowl),
- ((GtkFishbowlChild *) priv->children->data)->widget);
- }
+ if (priv->benchmark == benchmark)
+ return;
- 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);
- gtk_container_add (GTK_CONTAINER (fishbowl), new_widget);
- }
+ priv->benchmark = benchmark;
+ if (!benchmark)
+ priv->last_benchmark_change = 0;
- g_object_thaw_notify (G_OBJECT (fishbowl));
+ g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_BENCHMARK]);
}
gboolean
@@ -499,6 +473,111 @@ gtk_fishbowl_get_animating (GtkFishbowl *fishbowl)
return priv->tick_id != 0;
}
+static gint64
+guess_refresh_interval (GdkFrameClock *frame_clock)
+{
+ gint64 interval;
+ gint64 i;
+
+ interval = G_MAXINT64;
+
+ for (i = gdk_frame_clock_get_history_start (frame_clock);
+ i < gdk_frame_clock_get_frame_counter (frame_clock);
+ i++)
+ {
+ GdkFrameTimings *t, *before;
+ gint64 ts, before_ts;
+
+ t = gdk_frame_clock_get_timings (frame_clock, i);
+ before = gdk_frame_clock_get_timings (frame_clock, i - 1);
+ if (t == NULL || before == NULL)
+ continue;
+
+ ts = gdk_frame_timings_get_frame_time (t);
+ before_ts = gdk_frame_timings_get_frame_time (before);
+ if (ts == 0 || before_ts == 0)
+ continue;
+
+ interval = MIN (interval, ts - before_ts);
+ }
+
+ if (interval == G_MAXINT64)
+ return 0;
+
+ return interval;
+}
+
+static void
+gtk_fishbowl_do_update (GtkFishbowl *fishbowl)
+{
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+ GdkFrameClock *frame_clock;
+ GdkFrameTimings *start, *end;
+ gint64 start_counter, end_counter;
+ gint64 n_frames, expected_frames;
+ gint64 start_timestamp, end_timestamp;
+ gint64 interval;
+
+ frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (fishbowl));
+ if (frame_clock == NULL)
+ return;
+
+ start_counter = gdk_frame_clock_get_history_start (frame_clock);
+ end_counter = gdk_frame_clock_get_frame_counter (frame_clock);
+ start = gdk_frame_clock_get_timings (frame_clock, start_counter);
+ for (end = gdk_frame_clock_get_timings (frame_clock, end_counter);
+ end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
+ end = gdk_frame_clock_get_timings (frame_clock, end_counter))
+ end_counter--;
+ if (end_counter - start_counter < 4)
+ return;
+
+ start_timestamp = gdk_frame_timings_get_presentation_time (start);
+ end_timestamp = gdk_frame_timings_get_presentation_time (end);
+ if (start_timestamp == 0 || end_timestamp == 0)
+ {
+ start_timestamp = gdk_frame_timings_get_frame_time (start);
+ end_timestamp = gdk_frame_timings_get_frame_time (end);
+ }
+
+ n_frames = end_counter - start_counter;
+ priv->framerate = ((double) n_frames) * G_USEC_PER_SEC / (end_timestamp - start_timestamp);
+ g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
+
+ if (!priv->benchmark)
+ return;
+
+ interval = gdk_frame_timings_get_refresh_interval (end);
+ if (interval == 0)
+ {
+ interval = guess_refresh_interval (frame_clock);
+ if (interval == 0)
+ return;
+ }
+ expected_frames = round ((double) (end_timestamp - start_timestamp) / interval);
+
+ if (n_frames >= expected_frames)
+ {
+ if (priv->last_benchmark_change > 0)
+ priv->last_benchmark_change *= 2;
+ else
+ priv->last_benchmark_change = 1;
+ }
+ else if (n_frames + 1 < expected_frames)
+ {
+ if (priv->last_benchmark_change < 0)
+ priv->last_benchmark_change--;
+ else
+ priv->last_benchmark_change = -1;
+ }
+ else
+ {
+ priv->last_benchmark_change = 0;
+ }
+
+ gtk_fishbowl_set_count (fishbowl, MAX (1, (int) priv->count + priv->last_benchmark_change));
+}
+
static gboolean
gtk_fishbowl_tick (GtkWidget *widget,
GdkFrameClock *frame_clock,
@@ -509,9 +588,11 @@ gtk_fishbowl_tick (GtkWidget *widget,
GtkFishbowlChild *child;
GList *l;
gint64 frame_time, elapsed;
+ gboolean do_update;
frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
elapsed = frame_time - priv->last_frame_time;
+ do_update = frame_time / priv->update_delay != priv->last_frame_time / priv->update_delay;
priv->last_frame_time = frame_time;
/* last frame was 0, so we're just starting to animate */
@@ -550,6 +631,9 @@ gtk_fishbowl_tick (GtkWidget *widget,
gtk_widget_queue_allocate (widget);
+ if (do_update)
+ gtk_fishbowl_do_update (fishbowl);
+
return G_SOURCE_CONTINUE;
}
@@ -574,8 +658,57 @@ gtk_fishbowl_set_animating (GtkFishbowl *fishbowl,
priv->last_frame_time = 0;
gtk_widget_remove_tick_callback (GTK_WIDGET (fishbowl), priv->tick_id);
priv->tick_id = 0;
+ priv->framerate = 0;
+ g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
}
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_ANIMATING]);
}
+double
+gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl)
+{
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+ return priv->framerate;
+}
+
+gint64
+gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl)
+{
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+ return priv->update_delay;
+}
+
+void
+gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl,
+ gint64 update_delay)
+{
+ GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+ if (priv->update_delay == update_delay)
+ return;
+
+ priv->update_delay = update_delay;
+
+ 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->last_benchmark_change = 0;
+
+ priv->creation_func = creation_func;
+
+ gtk_fishbowl_set_count (fishbowl, 1);
+
+ g_object_thaw_notify (G_OBJECT (fishbowl));
+}
diff --git a/demos/gtk-demo/gtkfishbowl.h b/demos/gtk-demo/gtkfishbowl.h
index 2ac1ad12ea..47441927d0 100644
--- a/demos/gtk-demo/gtkfishbowl.h
+++ b/demos/gtk-demo/gtkfishbowl.h
@@ -32,9 +32,11 @@ G_BEGIN_DECLS
typedef struct _GtkFishbowl GtkFishbowl;
typedef struct _GtkFishbowlClass GtkFishbowlClass;
+typedef GtkWidget * (* GtkFishCreationFunc) (void);
+
struct _GtkFishbowl
{
- GtkContainer container;
+ GtkContainer parent;
};
struct _GtkFishbowlClass
@@ -52,6 +54,15 @@ void gtk_fishbowl_set_count (GtkFishbowl *fishbowl,
gboolean gtk_fishbowl_get_animating (GtkFishbowl *fishbowl);
void gtk_fishbowl_set_animating (GtkFishbowl *fishbowl,
gboolean animating);
+gboolean gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl);
+void gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl,
+ gboolean animating);
+double gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl);
+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
diff --git a/demos/gtk-demo/widgetbowl.c b/demos/gtk-demo/widgetbowl.c
deleted file mode 100644
index 0b7e5a0ab7..0000000000
--- a/demos/gtk-demo/widgetbowl.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/* Benchmark/Widgetbowl
- *
- * This is a version of the Fishbowl demo that instead shows different
- * kinds of widgets, which is useful for comparing the rendering performance
- * of theme specifics.
- */
-
-#include <gtk/gtk.h>
-
-#include "gtkfishbowl.h"
-
-const char *const css =
-".blurred-button {"
-" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
-"}"
-"";
-
-GtkWidget *fishbowl;
-
-static GtkWidget *
-create_button (void)
-{
- return gtk_button_new_with_label ("Button");
-}
-static GtkWidget *
-create_blurred_button (void)
-{
- GtkWidget *w = gtk_button_new ();
-
- gtk_style_context_add_class (gtk_widget_get_style_context (w), "blurred-button");
-
- return w;
-}
-
-static GtkWidget *
-create_font_button (void)
-{
- return gtk_font_button_new ();
-}
-
-static GtkWidget *
-create_level_bar (void)
-{
- GtkWidget *w = gtk_level_bar_new_for_interval (0, 100);
-
- gtk_level_bar_set_value (GTK_LEVEL_BAR (w), 50);
-
- /* Force them to be a bit larger */
- gtk_widget_set_size_request (w, 200, -1);
-
- return w;
-}
-
-static GtkWidget *
-create_spinner (void)
-{
- GtkWidget *w = gtk_spinner_new ();
-
- gtk_spinner_start (GTK_SPINNER (w));
-
- return w;
-}
-
-static GtkWidget *
-create_spinbutton (void)
-{
- GtkWidget *w = gtk_spin_button_new_with_range (0, 10, 1);
-
- return w;
-}
-
-static GtkWidget *
-create_label (void)
-{
- GtkWidget *w = gtk_label_new ("pLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.");
-
- gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
- gtk_label_set_max_width_chars (GTK_LABEL (w), 100);
-
- return w;
-}
-
-static const struct {
- const char *name;
- GtkWidget * (*create_func) (void);
-} widget_types[] = {
- { "Button", create_button },
- { "Blurbutton", create_blurred_button },
- { "Fontbutton", create_font_button },
- { "Levelbar" , create_level_bar },
- { "Label" , create_label },
- { "Spinner" , create_spinner },
- { "Spinbutton", create_spinbutton },
-};
-
-static int selected_widget_type = -1;
-static const int N_WIDGET_TYPES = G_N_ELEMENTS (widget_types);
-
-#define N_STATS 5
-
-#define STATS_UPDATE_TIME G_USEC_PER_SEC
-
-static void
-set_widget_type (GtkWidget *headerbar,
- int widget_type_index)
-{
- if (widget_type_index == selected_widget_type)
- return;
-
- /* Remove everything */
- gtk_fishbowl_set_count (GTK_FISHBOWL (fishbowl), 0);
-
- 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_widget_show (new_widget);
-
- gtk_container_add (GTK_CONTAINER (fishbowl), new_widget);
-
- }
- }
- else if (suggested_change < 0)
- {
- gtk_fishbowl_set_count (GTK_FISHBOWL (fishbowl),
- gtk_fishbowl_get_count (GTK_FISHBOWL (fishbowl)) + suggested_change);
- }
-
- stats_update (bowl);
-
- return G_SOURCE_CONTINUE;
-}
-
-static void
-next_button_clicked_cb (GtkButton *source,
- gpointer user_data)
-{
- GtkWidget *headerbar = user_data;
- int new_index;
-
- if (selected_widget_type + 1 >= N_WIDGET_TYPES)
- new_index = 0;
- else
- new_index = selected_widget_type + 1;
-
- set_widget_type (headerbar, new_index);
-}
-
-static void
-prev_button_clicked_cb (GtkButton *source,
- gpointer user_data)
-{
- GtkWidget *headerbar = user_data;
- int new_index;
-
- if (selected_widget_type - 1 < 0)
- new_index = N_WIDGET_TYPES - 1;
- else
- new_index = selected_widget_type - 1;
-
- set_widget_type (headerbar, new_index);
-}
-
-GtkWidget *
-do_widgetbowl (GtkWidget *do_widget)
-{
- static GtkWidget *window = NULL;
- static GtkCssProvider *provider = NULL;
-
- if (provider == NULL)
- {
- provider = gtk_css_provider_new ();
- gtk_css_provider_load_from_data (provider, css, -1, NULL);
- gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
- GTK_STYLE_PROVIDER (provider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
- }
-
- if (!window)
- {
- GtkWidget *info_label;
- GtkWidget *count_label;
- GtkWidget *titlebar;
- GtkWidget *title_box;
- GtkWidget *left_box;
- GtkWidget *next_button;
- GtkWidget *prev_button;
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- titlebar = gtk_header_bar_new ();
- gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (titlebar), TRUE);
- info_label = gtk_label_new ("widget - 00.0 fps");
- count_label = gtk_label_new ("0");
- fishbowl = gtk_fishbowl_new ();
- title_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- prev_button = gtk_button_new_from_icon_name ("pan-start-symbolic", GTK_ICON_SIZE_BUTTON);
- next_button = gtk_button_new_from_icon_name ("pan-end-symbolic", GTK_ICON_SIZE_BUTTON);
- left_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-
- g_object_bind_property (fishbowl, "count", count_label, "label", 0);
- g_signal_connect (next_button, "clicked", G_CALLBACK (next_button_clicked_cb), titlebar);
- g_signal_connect (prev_button, "clicked", G_CALLBACK (prev_button_clicked_cb), titlebar);
-
- gtk_fishbowl_set_animating (GTK_FISHBOWL (fishbowl), TRUE);
-
- gtk_widget_set_hexpand (title_box, TRUE);
- gtk_widget_set_halign (title_box, GTK_ALIGN_END);
-
- gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
- gtk_container_add (GTK_CONTAINER (title_box), count_label);
- gtk_container_add (GTK_CONTAINER (title_box), info_label);
- gtk_header_bar_pack_end (GTK_HEADER_BAR (titlebar), title_box);
- gtk_container_add (GTK_CONTAINER (window), fishbowl);
-
-
- gtk_style_context_add_class (gtk_widget_get_style_context (left_box), "linked");
- gtk_container_add (GTK_CONTAINER (left_box), prev_button);
- gtk_container_add (GTK_CONTAINER (left_box), next_button);
- gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), left_box);
-
- g_signal_connect (window, "destroy",
- 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);
- }
-
- if (!gtk_widget_get_visible (window))
- gtk_widget_show_all (window);
- else
- gtk_widget_destroy (window);
-
-
- return window;
-}