1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 2014 Benjamin Otte <otte@gnome.org> |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | |
20 | #include "gtkcsswidgetnodeprivate.h" |
21 | |
22 | #include "gtkcssanimatedstyleprivate.h" |
23 | #include "gtkprivate.h" |
24 | #include "gtksettingsprivate.h" |
25 | #include "gtkstylecontextprivate.h" |
26 | #include "gtkwidgetprivate.h" |
27 | #include "gtkwindowprivate.h" |
28 | |
29 | G_DEFINE_TYPE (GtkCssWidgetNode, gtk_css_widget_node, GTK_TYPE_CSS_NODE) |
30 | |
31 | static void |
32 | gtk_css_widget_node_finalize (GObject *object) |
33 | { |
34 | GtkCssWidgetNode *node = GTK_CSS_WIDGET_NODE (object); |
35 | |
36 | g_object_unref (object: node->last_updated_style); |
37 | |
38 | G_OBJECT_CLASS (gtk_css_widget_node_parent_class)->finalize (object); |
39 | } |
40 | |
41 | static gboolean |
42 | gtk_css_widget_node_queue_callback (GtkWidget *widget, |
43 | GdkFrameClock *frame_clock, |
44 | gpointer user_data) |
45 | { |
46 | GtkCssNode *node = user_data; |
47 | |
48 | gtk_css_node_invalidate_frame_clock (cssnode: node, TRUE); |
49 | gtk_root_queue_restyle (self: GTK_ROOT (ptr: widget)); |
50 | |
51 | return G_SOURCE_CONTINUE; |
52 | } |
53 | |
54 | static void |
55 | gtk_css_widget_node_queue_validate (GtkCssNode *node) |
56 | { |
57 | GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); |
58 | |
59 | if (GTK_IS_ROOT (ptr: widget_node->widget)) |
60 | widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget: widget_node->widget, |
61 | callback: gtk_css_widget_node_queue_callback, |
62 | user_data: node, |
63 | NULL); |
64 | } |
65 | |
66 | static void |
67 | gtk_css_widget_node_dequeue_validate (GtkCssNode *node) |
68 | { |
69 | GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); |
70 | |
71 | if (widget_node->widget && GTK_IS_ROOT (ptr: widget_node->widget)) |
72 | gtk_widget_remove_tick_callback (widget: widget_node->widget, |
73 | id: widget_node->validate_cb_id); |
74 | } |
75 | |
76 | static void |
77 | gtk_css_widget_node_validate (GtkCssNode *node) |
78 | { |
79 | GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); |
80 | GtkCssStyleChange change; |
81 | GtkCssStyle *style; |
82 | |
83 | if (widget_node->widget == NULL) |
84 | return; |
85 | |
86 | if (node->style == widget_node->last_updated_style) |
87 | return; |
88 | |
89 | style = gtk_css_node_get_style (cssnode: node); |
90 | |
91 | gtk_css_style_change_init (change: &change, old_style: widget_node->last_updated_style, new_style: style); |
92 | if (gtk_css_style_change_has_change (change: &change)) |
93 | { |
94 | gtk_widget_css_changed (widget: widget_node->widget, change: &change); |
95 | g_set_object (&widget_node->last_updated_style, style); |
96 | } |
97 | gtk_css_style_change_finish (change: &change); |
98 | } |
99 | |
100 | static GtkStyleProvider * |
101 | gtk_css_widget_node_get_style_provider (GtkCssNode *node) |
102 | { |
103 | GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); |
104 | GtkStyleContext *context; |
105 | GtkStyleCascade *cascade; |
106 | |
107 | if (widget_node->widget == NULL) |
108 | return NULL; |
109 | |
110 | context = _gtk_widget_peek_style_context (widget: widget_node->widget); |
111 | if (context) |
112 | return gtk_style_context_get_style_provider (context); |
113 | |
114 | cascade = _gtk_settings_get_style_cascade (settings: gtk_widget_get_settings (widget: widget_node->widget), |
115 | scale: gtk_widget_get_scale_factor (widget: widget_node->widget)); |
116 | return GTK_STYLE_PROVIDER (cascade); |
117 | } |
118 | |
119 | static GdkFrameClock * |
120 | gtk_css_widget_node_get_frame_clock (GtkCssNode *node) |
121 | { |
122 | GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); |
123 | |
124 | if (widget_node->widget == NULL) |
125 | return NULL; |
126 | |
127 | if (!gtk_settings_get_enable_animations (settings: gtk_widget_get_settings (widget: widget_node->widget))) |
128 | return NULL; |
129 | |
130 | return gtk_widget_get_frame_clock (widget: widget_node->widget); |
131 | } |
132 | |
133 | static void |
134 | gtk_css_widget_node_class_init (GtkCssWidgetNodeClass *klass) |
135 | { |
136 | GtkCssNodeClass *node_class = GTK_CSS_NODE_CLASS (klass); |
137 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
138 | |
139 | object_class->finalize = gtk_css_widget_node_finalize; |
140 | node_class->validate = gtk_css_widget_node_validate; |
141 | node_class->queue_validate = gtk_css_widget_node_queue_validate; |
142 | node_class->dequeue_validate = gtk_css_widget_node_dequeue_validate; |
143 | node_class->get_style_provider = gtk_css_widget_node_get_style_provider; |
144 | node_class->get_frame_clock = gtk_css_widget_node_get_frame_clock; |
145 | } |
146 | |
147 | static void |
148 | gtk_css_widget_node_init (GtkCssWidgetNode *node) |
149 | { |
150 | node->last_updated_style = g_object_ref (gtk_css_static_style_get_default ()); |
151 | } |
152 | |
153 | GtkCssNode * |
154 | gtk_css_widget_node_new (GtkWidget *widget) |
155 | { |
156 | GtkCssWidgetNode *result; |
157 | |
158 | gtk_internal_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); |
159 | |
160 | result = g_object_new (GTK_TYPE_CSS_WIDGET_NODE, NULL); |
161 | result->widget = widget; |
162 | gtk_css_node_set_visible (GTK_CSS_NODE (result), |
163 | visible: _gtk_widget_get_visible (widget)); |
164 | |
165 | return GTK_CSS_NODE (result); |
166 | } |
167 | |
168 | void |
169 | gtk_css_widget_node_widget_destroyed (GtkCssWidgetNode *node) |
170 | { |
171 | gtk_internal_return_if_fail (GTK_IS_CSS_WIDGET_NODE (node)); |
172 | gtk_internal_return_if_fail (node->widget != NULL); |
173 | |
174 | node->widget = NULL; |
175 | /* Contents of this node are now undefined. |
176 | * So we don't clear the style or anything. |
177 | */ |
178 | } |
179 | |
180 | GtkWidget * |
181 | gtk_css_widget_node_get_widget (GtkCssWidgetNode *node) |
182 | { |
183 | gtk_internal_return_val_if_fail (GTK_IS_CSS_WIDGET_NODE (node), NULL); |
184 | |
185 | return node->widget; |
186 | } |
187 | |
188 | |