1/* Theming/Multiple Backgrounds
2 *
3 * GTK themes are written using CSS. Every widget is build of multiple items
4 * that you can style very similarly to a regular website.
5 */
6
7#include <gtk/gtk.h>
8
9static void
10show_parsing_error (GtkCssProvider *provider,
11 GtkCssSection *section,
12 const GError *error,
13 GtkTextBuffer *buffer)
14{
15 const GtkCssLocation *start_location, *end_location;
16 GtkTextIter start, end;
17 const char *tag_name;
18
19 start_location = gtk_css_section_get_start_location (section);
20 gtk_text_buffer_get_iter_at_line_index (buffer,
21 iter: &start,
22 line_number: start_location->lines,
23 byte_index: start_location->line_bytes);
24 end_location = gtk_css_section_get_end_location (section);
25 gtk_text_buffer_get_iter_at_line_index (buffer,
26 iter: &end,
27 line_number: end_location->lines,
28 byte_index: end_location->line_bytes);
29
30
31 if (error->domain == GTK_CSS_PARSER_WARNING)
32 tag_name = "warning";
33 else
34 tag_name = "error";
35
36 gtk_text_buffer_apply_tag_by_name (buffer, name: tag_name, start: &start, end: &end);
37}
38
39static void
40css_text_changed (GtkTextBuffer *buffer,
41 GtkCssProvider *provider)
42{
43 GtkTextIter start, end;
44 char *text;
45
46 gtk_text_buffer_get_start_iter (buffer, iter: &start);
47 gtk_text_buffer_get_end_iter (buffer, iter: &end);
48 gtk_text_buffer_remove_all_tags (buffer, start: &start, end: &end);
49
50 text = gtk_text_buffer_get_text (buffer, start: &start, end: &end, FALSE);
51 gtk_css_provider_load_from_data (css_provider: provider, data: text, length: -1);
52 g_free (mem: text);
53}
54
55static void
56drawing_area_draw (GtkDrawingArea *da,
57 cairo_t *cr,
58 int width,
59 int height,
60 gpointer data)
61{
62 GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (da));
63
64 gtk_render_background (context, cr, x: 0, y: 0, width, height);
65 gtk_render_frame (context, cr, x: 0, y: 0, width, height);
66}
67
68static void
69apply_css (GtkWidget *widget, GtkStyleProvider *provider)
70{
71 GtkWidget *child;
72
73 gtk_style_context_add_provider (context: gtk_widget_get_style_context (widget), provider, G_MAXUINT);
74 for (child = gtk_widget_get_first_child (widget);
75 child != NULL;
76 child = gtk_widget_get_next_sibling (widget: child))
77 apply_css (widget: child, provider);
78}
79
80GtkWidget *
81do_css_multiplebgs (GtkWidget *do_widget)
82{
83 static GtkWidget *window = NULL;
84
85 if (!window)
86 {
87 GtkWidget *paned, *overlay, *child, *sw;
88 GtkStyleProvider *provider;
89 GtkTextBuffer *text;
90 GBytes *bytes;
91
92 window = gtk_window_new ();
93 gtk_window_set_title (GTK_WINDOW (window), title: "Multiple Backgrounds");
94 gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
95 gtk_window_set_default_size (GTK_WINDOW (window), width: 400, height: 300);
96 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
97
98 overlay = gtk_overlay_new ();
99 gtk_window_set_child (GTK_WINDOW (window), child: overlay);
100
101 child = gtk_drawing_area_new ();
102 gtk_widget_set_name (widget: child, name: "canvas");
103 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
104 draw_func: drawing_area_draw,
105 NULL, NULL);
106 gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
107
108 child = gtk_button_new ();
109 gtk_overlay_add_overlay (GTK_OVERLAY (overlay), widget: child);
110 gtk_widget_set_name (widget: child, name: "bricks-button");
111 gtk_widget_set_halign (widget: child, align: GTK_ALIGN_CENTER);
112 gtk_widget_set_valign (widget: child, align: GTK_ALIGN_CENTER);
113 gtk_widget_set_size_request (widget: child, width: 250, height: 84);
114
115 paned = gtk_paned_new (orientation: GTK_ORIENTATION_VERTICAL);
116 gtk_overlay_add_overlay (GTK_OVERLAY (overlay), widget: paned);
117
118 /* Need a filler so we get a handle */
119 child = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0);
120 gtk_paned_set_start_child (GTK_PANED (paned), child);
121
122 text = gtk_text_buffer_new (NULL);
123 gtk_text_buffer_create_tag (buffer: text,
124 tag_name: "warning",
125 first_property_name: "underline", PANGO_UNDERLINE_SINGLE,
126 NULL);
127 gtk_text_buffer_create_tag (buffer: text,
128 tag_name: "error",
129 first_property_name: "underline", PANGO_UNDERLINE_ERROR,
130 NULL);
131
132 provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
133
134 sw = gtk_scrolled_window_new ();
135 gtk_paned_set_end_child (GTK_PANED (paned), child: sw);
136 child = gtk_text_view_new_with_buffer (buffer: text);
137 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
138 g_signal_connect (text,
139 "changed",
140 G_CALLBACK (css_text_changed),
141 provider);
142
143 bytes = g_resources_lookup_data (path: "/css_multiplebgs/css_multiplebgs.css", lookup_flags: 0, NULL);
144 gtk_text_buffer_set_text (buffer: text, text: g_bytes_get_data (bytes, NULL), len: g_bytes_get_size (bytes));
145 g_bytes_unref (bytes);
146
147 g_signal_connect (provider,
148 "parsing-error",
149 G_CALLBACK (show_parsing_error),
150 gtk_text_view_get_buffer (GTK_TEXT_VIEW (child)));
151
152 apply_css (widget: window, provider);
153 }
154
155 if (!gtk_widget_get_visible (widget: window))
156 gtk_widget_show (widget: window);
157 else
158 gtk_window_destroy (GTK_WINDOW (window));
159
160 return window;
161}
162

source code of gtk/demos/gtk-demo/css_multiplebgs.c