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 | |
9 | static void |
10 | show_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 | |
39 | static void |
40 | css_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 | |
55 | static void |
56 | drawing_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 | |
68 | static void |
69 | apply_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 | |
80 | GtkWidget * |
81 | do_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 | |