OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ui/base/gtk/gtk_floating_container.h" | |
6 | |
7 #include <gtk/gtk.h> | |
8 | |
9 #include <algorithm> | |
10 | |
11 #include "ui/gfx/gtk_compat.h" | |
12 | |
13 namespace { | |
14 | |
15 enum { | |
16 SET_FLOATING_POSITION, | |
17 LAST_SIGNAL | |
18 }; | |
19 | |
20 enum { | |
21 CHILD_PROP_0, | |
22 CHILD_PROP_X, | |
23 CHILD_PROP_Y | |
24 }; | |
25 | |
26 // Returns the GtkFloatingContainerChild associated with |widget| (or NULL if | |
27 // |widget| not found). | |
28 GtkFloatingContainerChild* GetChild(GtkFloatingContainer* container, | |
29 GtkWidget* widget) { | |
30 for (GList* floating_children = container->floating_children; | |
31 floating_children; floating_children = g_list_next(floating_children)) { | |
32 GtkFloatingContainerChild* child = | |
33 reinterpret_cast<GtkFloatingContainerChild*>(floating_children->data); | |
34 | |
35 if (child->widget == widget) | |
36 return child; | |
37 } | |
38 | |
39 return NULL; | |
40 } | |
41 | |
42 const GParamFlags kStaticReadWriteProp = static_cast<GParamFlags>( | |
43 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); | |
44 | |
45 } // namespace | |
46 | |
47 G_BEGIN_DECLS | |
48 | |
49 static void gtk_floating_container_remove(GtkContainer* container, | |
50 GtkWidget* widget); | |
51 static void gtk_floating_container_forall(GtkContainer* container, | |
52 gboolean include_internals, | |
53 GtkCallback callback, | |
54 gpointer callback_data); | |
55 static void gtk_floating_container_size_request(GtkWidget* widget, | |
56 GtkRequisition* requisition); | |
57 static void gtk_floating_container_size_allocate(GtkWidget* widget, | |
58 GtkAllocation* allocation); | |
59 static void gtk_floating_container_set_child_property(GtkContainer* container, | |
60 GtkWidget* child, | |
61 guint property_id, | |
62 const GValue* value, | |
63 GParamSpec* pspec); | |
64 static void gtk_floating_container_get_child_property(GtkContainer* container, | |
65 GtkWidget* child, | |
66 guint property_id, | |
67 GValue* value, | |
68 GParamSpec* pspec); | |
69 | |
70 static guint floating_container_signals[LAST_SIGNAL] = { 0 }; | |
71 | |
72 G_DEFINE_TYPE(GtkFloatingContainer, gtk_floating_container, GTK_TYPE_BIN) | |
73 | |
74 static void gtk_floating_container_class_init( | |
75 GtkFloatingContainerClass *klass) { | |
76 GtkObjectClass* object_class = | |
77 reinterpret_cast<GtkObjectClass*>(klass); | |
78 | |
79 GtkWidgetClass* widget_class = | |
80 reinterpret_cast<GtkWidgetClass*>(klass); | |
81 widget_class->size_request = gtk_floating_container_size_request; | |
82 widget_class->size_allocate = gtk_floating_container_size_allocate; | |
83 | |
84 GtkContainerClass* container_class = | |
85 reinterpret_cast<GtkContainerClass*>(klass); | |
86 container_class->remove = gtk_floating_container_remove; | |
87 container_class->forall = gtk_floating_container_forall; | |
88 | |
89 container_class->set_child_property = | |
90 gtk_floating_container_set_child_property; | |
91 container_class->get_child_property = | |
92 gtk_floating_container_get_child_property; | |
93 | |
94 gtk_container_class_install_child_property( | |
95 container_class, | |
96 CHILD_PROP_X, | |
97 g_param_spec_int("x", | |
98 "X position", | |
99 "X position of child widget", | |
100 G_MININT, | |
101 G_MAXINT, | |
102 0, | |
103 kStaticReadWriteProp)); | |
104 | |
105 gtk_container_class_install_child_property( | |
106 container_class, | |
107 CHILD_PROP_Y, | |
108 g_param_spec_int("y", | |
109 "Y position", | |
110 "Y position of child widget", | |
111 G_MININT, | |
112 G_MAXINT, | |
113 0, | |
114 kStaticReadWriteProp)); | |
115 | |
116 floating_container_signals[SET_FLOATING_POSITION] = | |
117 g_signal_new("set-floating-position", | |
118 G_OBJECT_CLASS_TYPE(object_class), | |
119 static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST | | |
120 G_SIGNAL_ACTION), | |
121 0, | |
122 NULL, NULL, | |
123 g_cclosure_marshal_VOID__BOXED, | |
124 G_TYPE_NONE, 1, | |
125 GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE); | |
126 } | |
127 | |
128 static void gtk_floating_container_init(GtkFloatingContainer* container) { | |
129 gtk_widget_set_has_window(GTK_WIDGET(container), FALSE); | |
130 container->floating_children = NULL; | |
131 } | |
132 | |
133 static void gtk_floating_container_remove(GtkContainer* container, | |
134 GtkWidget* widget) { | |
135 g_return_if_fail(GTK_IS_WIDGET(widget)); | |
136 | |
137 GtkBin* bin = GTK_BIN(container); | |
138 if (gtk_bin_get_child(bin) == widget) { | |
139 ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class))->remove) | |
140 (container, widget); | |
141 } else { | |
142 // Handle the other case where it's in our |floating_children| list. | |
143 GtkFloatingContainer* floating = GTK_FLOATING_CONTAINER(container); | |
144 GList* children = floating->floating_children; | |
145 gboolean removed_child = false; | |
146 while (children) { | |
147 GtkFloatingContainerChild* child = | |
148 reinterpret_cast<GtkFloatingContainerChild*>(children->data); | |
149 | |
150 if (child->widget == widget) { | |
151 removed_child = true; | |
152 gboolean was_visible = gtk_widget_get_visible(GTK_WIDGET(widget)); | |
153 | |
154 gtk_widget_unparent(widget); | |
155 | |
156 floating->floating_children = | |
157 g_list_remove_link(floating->floating_children, children); | |
158 g_list_free(children); | |
159 g_free(child); | |
160 | |
161 if (was_visible && gtk_widget_get_visible(GTK_WIDGET(container))) | |
162 gtk_widget_queue_resize(GTK_WIDGET(container)); | |
163 | |
164 break; | |
165 } | |
166 children = children->next; | |
167 } | |
168 | |
169 g_return_if_fail(removed_child); | |
170 } | |
171 } | |
172 | |
173 static void gtk_floating_container_forall(GtkContainer* container, | |
174 gboolean include_internals, | |
175 GtkCallback callback, | |
176 gpointer callback_data) { | |
177 g_return_if_fail(container != NULL); | |
178 g_return_if_fail(callback != NULL); | |
179 | |
180 GtkFloatingContainer* floating = GTK_FLOATING_CONTAINER(container); | |
181 GList* children = floating->floating_children; | |
182 while (children) { | |
183 GtkFloatingContainerChild* child = | |
184 reinterpret_cast<GtkFloatingContainerChild*>(children->data); | |
185 children = children->next; | |
186 | |
187 (*callback)(child->widget, callback_data); | |
188 } | |
189 | |
190 // Let GtkBin do its part of the forall. | |
191 ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class))->forall) | |
192 (container, include_internals, callback, callback_data); | |
193 } | |
194 | |
195 static void gtk_floating_container_size_request(GtkWidget* widget, | |
196 GtkRequisition* requisition) { | |
197 GtkBin* bin = GTK_BIN(widget); | |
198 if (bin && gtk_bin_get_child(bin)) { | |
199 gtk_widget_size_request(gtk_bin_get_child(bin), requisition); | |
200 } else { | |
201 requisition->width = 0; | |
202 requisition->height = 0; | |
203 } | |
204 } | |
205 | |
206 static void gtk_floating_container_size_allocate(GtkWidget* widget, | |
207 GtkAllocation* allocation) { | |
208 gtk_widget_set_allocation(widget, allocation); | |
209 | |
210 if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) { | |
211 gdk_window_move_resize(gtk_widget_get_window(widget), | |
212 allocation->x, | |
213 allocation->y, | |
214 allocation->width, | |
215 allocation->height); | |
216 } | |
217 | |
218 // Give the same allocation to our GtkBin component. | |
219 GtkBin* bin = GTK_BIN(widget); | |
220 if (gtk_bin_get_child(bin)) { | |
221 gtk_widget_size_allocate(gtk_bin_get_child(bin), allocation); | |
222 } | |
223 | |
224 // We need to give whoever is pulling our strings a chance to set the "x" and | |
225 // "y" properties on all of our children. | |
226 g_signal_emit(widget, floating_container_signals[SET_FLOATING_POSITION], 0, | |
227 allocation); | |
228 | |
229 // Our allocation has been set. We've asked our controller to place the other | |
230 // widgets. Pass out allocations to all our children based on where they want | |
231 // to be. | |
232 GtkFloatingContainer* container = GTK_FLOATING_CONTAINER(widget); | |
233 GList* children = container->floating_children; | |
234 GtkAllocation child_allocation; | |
235 GtkRequisition child_requisition; | |
236 while (children) { | |
237 GtkFloatingContainerChild* child = | |
238 reinterpret_cast<GtkFloatingContainerChild*>(children->data); | |
239 children = children->next; | |
240 | |
241 if (gtk_widget_get_visible(GTK_WIDGET(child->widget))) { | |
242 gtk_widget_size_request(child->widget, &child_requisition); | |
243 child_allocation.x = allocation->x + child->x; | |
244 child_allocation.y = allocation->y + child->y; | |
245 child_allocation.width = std::max(1, std::min(child_requisition.width, | |
246 allocation->width)); | |
247 child_allocation.height = std::max(1, std::min(child_requisition.height, | |
248 allocation->height)); | |
249 gtk_widget_size_allocate(child->widget, &child_allocation); | |
250 } | |
251 } | |
252 } | |
253 | |
254 static void gtk_floating_container_set_child_property(GtkContainer* container, | |
255 GtkWidget* child, | |
256 guint property_id, | |
257 const GValue* value, | |
258 GParamSpec* pspec) { | |
259 GtkFloatingContainerChild* floating_child = | |
260 GetChild(GTK_FLOATING_CONTAINER(container), child); | |
261 g_return_if_fail(floating_child); | |
262 | |
263 switch (property_id) { | |
264 case CHILD_PROP_X: | |
265 floating_child->x = g_value_get_int(value); | |
266 gtk_widget_child_notify(child, "x"); | |
267 break; | |
268 case CHILD_PROP_Y: | |
269 floating_child->y = g_value_get_int(value); | |
270 gtk_widget_child_notify(child, "y"); | |
271 break; | |
272 default: | |
273 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID( | |
274 container, property_id, pspec); | |
275 break; | |
276 }; | |
277 } | |
278 | |
279 static void gtk_floating_container_get_child_property(GtkContainer* container, | |
280 GtkWidget* child, | |
281 guint property_id, | |
282 GValue* value, | |
283 GParamSpec* pspec) { | |
284 GtkFloatingContainerChild* floating_child = | |
285 GetChild(GTK_FLOATING_CONTAINER(container), child); | |
286 g_return_if_fail(floating_child); | |
287 | |
288 switch (property_id) { | |
289 case CHILD_PROP_X: | |
290 g_value_set_int(value, floating_child->x); | |
291 break; | |
292 case CHILD_PROP_Y: | |
293 g_value_set_int(value, floating_child->y); | |
294 break; | |
295 default: | |
296 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID( | |
297 container, property_id, pspec); | |
298 break; | |
299 }; | |
300 } | |
301 | |
302 GtkWidget* gtk_floating_container_new() { | |
303 return GTK_WIDGET(g_object_new(GTK_TYPE_FLOATING_CONTAINER, NULL)); | |
304 } | |
305 | |
306 void gtk_floating_container_add_floating(GtkFloatingContainer* container, | |
307 GtkWidget* widget) { | |
308 g_return_if_fail(GTK_IS_FLOATING_CONTAINER(container)); | |
309 g_return_if_fail(GTK_IS_WIDGET(widget)); | |
310 | |
311 GtkFloatingContainerChild* child_info = g_new(GtkFloatingContainerChild, 1); | |
312 child_info->widget = widget; | |
313 child_info->x = 0; | |
314 child_info->y = 0; | |
315 | |
316 gtk_widget_set_parent(widget, GTK_WIDGET(container)); | |
317 | |
318 container->floating_children = | |
319 g_list_append(container->floating_children, child_info); | |
320 } | |
321 | |
322 G_END_DECLS | |
OLD | NEW |