diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 22db1bad21..238503c0d2 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -112,6 +112,9 @@
dnd.css
+
+ errorstates.ui
+
fishbowl.ui
gtkfishbowl.c
@@ -222,6 +225,7 @@
editable_cells.c
entry_completion.c
entry_undo.c
+ errorstates.c
expander.c
filtermodel.c
fishbowl.c
diff --git a/demos/gtk-demo/errorstates.c b/demos/gtk-demo/errorstates.c
new file mode 100644
index 0000000000..3dc3b50f3b
--- /dev/null
+++ b/demos/gtk-demo/errorstates.c
@@ -0,0 +1,124 @@
+/* Error states
+ *
+ * GtkLabel and GtkEntry can indicate errors if you set the .error
+ * style class on them.
+ *
+ * This examples shows how this can be used in a dialog for input validation.
+ *
+ * It also shows how pass callbacks and objects to GtkBuilder with
+ * GtkBuilderScope and gtk_builder_expose_object().
+ */
+
+#include
+#include
+
+static void
+validate_more_details (GtkEntry *entry,
+ GParamSpec *pspec,
+ GtkEntry *details)
+{
+ if (strlen (gtk_editable_get_text (GTK_EDITABLE (entry))) > 0 &&
+ strlen (gtk_editable_get_text (GTK_EDITABLE (details))) == 0)
+ {
+ gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "Must have details first");
+ gtk_widget_add_css_class (GTK_WIDGET (entry), "error");
+ }
+ else
+ {
+ gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "");
+ gtk_widget_remove_css_class (GTK_WIDGET (entry), "error");
+ }
+}
+
+static gboolean
+mode_switch_state_set (GtkSwitch *sw,
+ gboolean state,
+ GtkWidget *scale)
+{
+ GtkWidget *label;
+
+ label = GTK_WIDGET (g_object_get_data (G_OBJECT (sw), "error_label"));
+
+ if (!state ||
+ (gtk_range_get_value (GTK_RANGE (scale)) > 50))
+ {
+ gtk_widget_hide (label);
+ gtk_switch_set_state (sw, state);
+ }
+ else
+ {
+ gtk_widget_show (label);
+ }
+
+ return TRUE;
+}
+
+static void
+level_scale_value_changed (GtkRange *range,
+ GtkWidget *sw)
+{
+ GtkWidget *label;
+
+ label = GTK_WIDGET (g_object_get_data (G_OBJECT (sw), "error_label"));
+
+ if (gtk_switch_get_active (GTK_SWITCH (sw)) &&
+ !gtk_switch_get_state (GTK_SWITCH (sw)) &&
+ (gtk_range_get_value (range) > 50))
+ {
+ gtk_widget_hide (label);
+ gtk_switch_set_state (GTK_SWITCH (sw), TRUE);
+ }
+ else if (gtk_switch_get_state (GTK_SWITCH (sw)) &&
+ (gtk_range_get_value (range) <= 50))
+ {
+ gtk_switch_set_state (GTK_SWITCH (sw), FALSE);
+ }
+}
+
+GtkWidget *
+do_errorstates (GtkWidget *do_widget)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window)
+ {
+ GtkWidget *toplevel;
+ GtkBuilder *builder;
+ GtkBuilderScope *scope;
+ GtkWidget *sw, *label;
+
+ toplevel = GTK_WIDGET (gtk_widget_get_root (do_widget));
+
+ scope = gtk_builder_cscope_new ();
+ gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
+ "validate_more_details", G_CALLBACK (validate_more_details),
+ "mode_switch_state_set", G_CALLBACK (mode_switch_state_set),
+ "level_scale_value_changed", G_CALLBACK (level_scale_value_changed),
+ NULL);
+
+ builder = gtk_builder_new ();
+ gtk_builder_set_scope (builder, scope);
+ gtk_builder_expose_object (builder, "toplevel", G_OBJECT (toplevel));
+ gtk_builder_add_from_resource (builder, "/errorstates/errorstates.ui", NULL);
+
+ window = GTK_WIDGET (gtk_builder_get_object (builder, "dialog"));
+
+ gtk_window_set_display (GTK_WINDOW (window),
+ gtk_widget_get_display (do_widget));
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
+
+ sw = GTK_WIDGET (gtk_builder_get_object (builder, "mode_switch"));
+ label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
+ g_object_set_data (G_OBJECT (sw), "error_label", label);
+
+ g_object_unref (builder);
+ g_object_unref (scope);
+ }
+
+ if (!gtk_widget_get_visible (window))
+ gtk_widget_show (window);
+ else
+ gtk_window_destroy (GTK_WINDOW (window));
+
+ return window;
+}
diff --git a/demos/gtk-demo/errorstates.ui b/demos/gtk-demo/errorstates.ui
new file mode 100644
index 0000000000..dd4a95b8fc
--- /dev/null
+++ b/demos/gtk-demo/errorstates.ui
@@ -0,0 +1,158 @@
+
+
+
+
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 07fd1b2330..a60f121896 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -23,6 +23,7 @@ demos = files([
'editable_cells.c',
'entry_completion.c',
'entry_undo.c',
+ 'errorstates.c',
'expander.c',
'filtermodel.c',
'fishbowl.c',