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