1 | /* Theming/CSS Basics |
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 | if (error->domain == GTK_CSS_PARSER_WARNING) |
31 | tag_name = "warning" ; |
32 | else |
33 | tag_name = "error" ; |
34 | |
35 | gtk_text_buffer_apply_tag_by_name (buffer, name: tag_name, start: &start, end: &end); |
36 | } |
37 | |
38 | static void |
39 | css_text_changed (GtkTextBuffer *buffer, |
40 | GtkCssProvider *provider) |
41 | { |
42 | GtkTextIter start, end; |
43 | char *text; |
44 | |
45 | gtk_text_buffer_get_start_iter (buffer, iter: &start); |
46 | gtk_text_buffer_get_end_iter (buffer, iter: &end); |
47 | gtk_text_buffer_remove_all_tags (buffer, start: &start, end: &end); |
48 | |
49 | text = gtk_text_buffer_get_text (buffer, start: &start, end: &end, FALSE); |
50 | gtk_css_provider_load_from_data (css_provider: provider, data: text, length: -1); |
51 | g_free (mem: text); |
52 | } |
53 | |
54 | static void |
55 | apply_css (GtkWidget *widget, GtkStyleProvider *provider) |
56 | { |
57 | GtkWidget *child; |
58 | |
59 | gtk_style_context_add_provider (context: gtk_widget_get_style_context (widget), provider, G_MAXUINT); |
60 | for (child = gtk_widget_get_first_child (widget); |
61 | child != NULL; |
62 | child = gtk_widget_get_next_sibling (widget: child)) |
63 | apply_css (widget: child, provider); |
64 | } |
65 | |
66 | GtkWidget * |
67 | do_css_basics (GtkWidget *do_widget) |
68 | { |
69 | static GtkWidget *window = NULL; |
70 | |
71 | if (!window) |
72 | { |
73 | GtkWidget *container, *child; |
74 | GtkStyleProvider *provider; |
75 | GtkTextBuffer *text; |
76 | GBytes *bytes; |
77 | |
78 | window = gtk_window_new (); |
79 | gtk_window_set_title (GTK_WINDOW (window), title: "CSS Basics" ); |
80 | gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget)); |
81 | gtk_window_set_default_size (GTK_WINDOW (window), width: 400, height: 300); |
82 | g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window); |
83 | |
84 | text = gtk_text_buffer_new (NULL); |
85 | gtk_text_buffer_create_tag (buffer: text, |
86 | tag_name: "warning" , |
87 | first_property_name: "underline" , PANGO_UNDERLINE_SINGLE, |
88 | NULL); |
89 | gtk_text_buffer_create_tag (buffer: text, |
90 | tag_name: "error" , |
91 | first_property_name: "underline" , PANGO_UNDERLINE_ERROR, |
92 | NULL); |
93 | |
94 | provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ()); |
95 | |
96 | container = gtk_scrolled_window_new (); |
97 | gtk_window_set_child (GTK_WINDOW (window), child: container); |
98 | child = gtk_text_view_new_with_buffer (buffer: text); |
99 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child); |
100 | g_signal_connect (text, "changed" , |
101 | G_CALLBACK (css_text_changed), provider); |
102 | |
103 | bytes = g_resources_lookup_data (path: "/css_basics/css_basics.css" , lookup_flags: 0, NULL); |
104 | gtk_text_buffer_set_text (buffer: text, text: g_bytes_get_data (bytes, NULL), len: g_bytes_get_size (bytes)); |
105 | g_bytes_unref (bytes); |
106 | |
107 | g_signal_connect (provider, |
108 | "parsing-error" , |
109 | G_CALLBACK (show_parsing_error), |
110 | gtk_text_view_get_buffer (GTK_TEXT_VIEW (child))); |
111 | |
112 | apply_css (widget: window, provider); |
113 | } |
114 | |
115 | if (!gtk_widget_get_visible (widget: window)) |
116 | gtk_widget_show (widget: window); |
117 | else |
118 | gtk_window_destroy (GTK_WINDOW (window)); |
119 | |
120 | return window; |
121 | } |
122 | |