| 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 | 
|---|