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.
5 #include "ui/base/gtk/gtk_floating_container.h"
11 #include "ui/gfx/gtk_compat.h"
16 SET_FLOATING_POSITION
,
26 // Returns the GtkFloatingContainerChild associated with |widget| (or NULL if
27 // |widget| not found).
28 GtkFloatingContainerChild
* GetChild(GtkFloatingContainer
* container
,
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
);
35 if (child
->widget
== widget
)
42 const GParamFlags kStaticReadWriteProp
= static_cast<GParamFlags
>(
43 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
49 static void gtk_floating_container_remove(GtkContainer
* container
,
51 static void gtk_floating_container_forall(GtkContainer
* container
,
52 gboolean include_internals
,
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
,
64 static void gtk_floating_container_get_child_property(GtkContainer
* container
,
70 static guint floating_container_signals
[LAST_SIGNAL
] = { 0 };
72 G_DEFINE_TYPE(GtkFloatingContainer
, gtk_floating_container
, GTK_TYPE_BIN
)
74 static void gtk_floating_container_class_init(
75 GtkFloatingContainerClass
*klass
) {
76 GtkObjectClass
* object_class
=
77 reinterpret_cast<GtkObjectClass
*>(klass
);
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
;
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
;
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
;
94 gtk_container_class_install_child_property(
99 "X position of child widget",
103 kStaticReadWriteProp
));
105 gtk_container_class_install_child_property(
108 g_param_spec_int("y",
110 "Y position of child widget",
114 kStaticReadWriteProp
));
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
|
123 g_cclosure_marshal_VOID__BOXED
,
125 GDK_TYPE_RECTANGLE
| G_SIGNAL_TYPE_STATIC_SCOPE
);
128 static void gtk_floating_container_init(GtkFloatingContainer
* container
) {
129 gtk_widget_set_has_window(GTK_WIDGET(container
), FALSE
);
130 container
->floating_children
= NULL
;
133 static void gtk_floating_container_remove(GtkContainer
* container
,
135 g_return_if_fail(GTK_IS_WIDGET(widget
));
137 GtkBin
* bin
= GTK_BIN(container
);
138 if (gtk_bin_get_child(bin
) == widget
) {
139 ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class
))->remove
)
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;
147 GtkFloatingContainerChild
* child
=
148 reinterpret_cast<GtkFloatingContainerChild
*>(children
->data
);
150 if (child
->widget
== widget
) {
151 removed_child
= true;
152 gboolean was_visible
= gtk_widget_get_visible(GTK_WIDGET(widget
));
154 gtk_widget_unparent(widget
);
156 floating
->floating_children
=
157 g_list_remove_link(floating
->floating_children
, children
);
158 g_list_free(children
);
161 if (was_visible
&& gtk_widget_get_visible(GTK_WIDGET(container
)))
162 gtk_widget_queue_resize(GTK_WIDGET(container
));
166 children
= children
->next
;
169 g_return_if_fail(removed_child
);
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
);
180 GtkFloatingContainer
* floating
= GTK_FLOATING_CONTAINER(container
);
181 GList
* children
= floating
->floating_children
;
183 GtkFloatingContainerChild
* child
=
184 reinterpret_cast<GtkFloatingContainerChild
*>(children
->data
);
185 children
= children
->next
;
187 (*callback
)(child
->widget
, callback_data
);
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
);
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
);
201 requisition
->width
= 0;
202 requisition
->height
= 0;
206 static void gtk_floating_container_size_allocate(GtkWidget
* widget
,
207 GtkAllocation
* allocation
) {
208 gtk_widget_set_allocation(widget
, allocation
);
210 if (gtk_widget_get_has_window(widget
) && gtk_widget_get_realized(widget
)) {
211 gdk_window_move_resize(gtk_widget_get_window(widget
),
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
);
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,
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
232 GtkFloatingContainer
* container
= GTK_FLOATING_CONTAINER(widget
);
233 GList
* children
= container
->floating_children
;
234 GtkAllocation child_allocation
;
235 GtkRequisition child_requisition
;
237 GtkFloatingContainerChild
* child
=
238 reinterpret_cast<GtkFloatingContainerChild
*>(children
->data
);
239 children
= children
->next
;
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
,
247 child_allocation
.height
= std::max(1, std::min(child_requisition
.height
,
248 allocation
->height
));
249 gtk_widget_size_allocate(child
->widget
, &child_allocation
);
254 static void gtk_floating_container_set_child_property(GtkContainer
* container
,
259 GtkFloatingContainerChild
* floating_child
=
260 GetChild(GTK_FLOATING_CONTAINER(container
), child
);
261 g_return_if_fail(floating_child
);
263 switch (property_id
) {
265 floating_child
->x
= g_value_get_int(value
);
266 gtk_widget_child_notify(child
, "x");
269 floating_child
->y
= g_value_get_int(value
);
270 gtk_widget_child_notify(child
, "y");
273 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(
274 container
, property_id
, pspec
);
279 static void gtk_floating_container_get_child_property(GtkContainer
* container
,
284 GtkFloatingContainerChild
* floating_child
=
285 GetChild(GTK_FLOATING_CONTAINER(container
), child
);
286 g_return_if_fail(floating_child
);
288 switch (property_id
) {
290 g_value_set_int(value
, floating_child
->x
);
293 g_value_set_int(value
, floating_child
->y
);
296 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(
297 container
, property_id
, pspec
);
302 GtkWidget
* gtk_floating_container_new() {
303 return GTK_WIDGET(g_object_new(GTK_TYPE_FLOATING_CONTAINER
, NULL
));
306 void gtk_floating_container_add_floating(GtkFloatingContainer
* container
,
308 g_return_if_fail(GTK_IS_FLOATING_CONTAINER(container
));
309 g_return_if_fail(GTK_IS_WIDGET(widget
));
311 GtkFloatingContainerChild
* child_info
= g_new(GtkFloatingContainerChild
, 1);
312 child_info
->widget
= widget
;
316 gtk_widget_set_parent(widget
, GTK_WIDGET(container
));
318 container
->floating_children
=
319 g_list_append(container
->floating_children
, child_info
);