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 "chrome/browser/ui/gtk/gtk_expanded_container.h" 6 7 #include <gtk/gtk.h> 8 9 #include <algorithm> 10 11 namespace { 12 13 enum { 14 CHILD_SIZE_REQUEST, 15 LAST_SIGNAL 16 }; 17 18 guint expanded_container_signals[LAST_SIGNAL] = { 0 }; 19 20 struct SizeAllocateData { 21 GtkWidget* container; 22 GtkAllocation* allocation; 23 int border_width; 24 }; 25 26 void GetChildPosition(GtkWidget* container, GtkWidget* child, int* x, int* y) { 27 GValue v = { 0 }; 28 g_value_init(&v, G_TYPE_INT); 29 gtk_container_child_get_property(GTK_CONTAINER(container), child, "x", &v); 30 *x = g_value_get_int(&v); 31 gtk_container_child_get_property(GTK_CONTAINER(container), child, "y", &v); 32 *y = g_value_get_int(&v); 33 g_value_unset(&v); 34 } 35 36 void ChildSizeAllocate(GtkWidget* child, gpointer userdata) { 37 if (!GTK_WIDGET_VISIBLE(child)) 38 return; 39 40 SizeAllocateData* data = reinterpret_cast<SizeAllocateData*>(userdata); 41 42 GtkRequisition child_requisition; 43 child_requisition.width = data->allocation->width - data->border_width * 2; 44 child_requisition.height = data->allocation->height - data->border_width * 2; 45 46 // We need to give whoever is pulling our strings a chance to adjust the 47 // size of our children. 48 g_signal_emit(data->container, 49 expanded_container_signals[CHILD_SIZE_REQUEST], 0, 50 child, &child_requisition); 51 52 GtkAllocation child_allocation; 53 child_allocation.width = child_requisition.width; 54 child_allocation.height = child_requisition.height; 55 if (child_allocation.width < 0 || child_allocation.height < 0) { 56 gtk_widget_get_child_requisition(child, &child_requisition); 57 if (child_allocation.width < 0) 58 child_allocation.width = child_requisition.width; 59 if (child_allocation.height < 0) 60 child_allocation.height = child_requisition.height; 61 } 62 63 int x, y; 64 GetChildPosition(data->container, child, &x, &y); 65 66 child_allocation.x = x + data->border_width; 67 child_allocation.y = y + data->border_width; 68 69 if (GTK_WIDGET_NO_WINDOW(data->container)) { 70 child_allocation.x += data->allocation->x; 71 child_allocation.y += data->allocation->y; 72 } 73 gtk_widget_size_allocate(child, &child_allocation); 74 } 75 76 void Marshal_VOID__OBJECT_BOXED(GClosure* closure, 77 GValue* return_value G_GNUC_UNUSED, 78 guint n_param_values, 79 const GValue* param_values, 80 gpointer invocation_hint G_GNUC_UNUSED, 81 gpointer marshal_data) { 82 typedef void (*GMarshalFunc_VOID__OBJECT_BOXED) (gpointer data1, 83 gpointer arg_1, 84 gpointer arg_2, 85 gpointer data2); 86 register GMarshalFunc_VOID__OBJECT_BOXED callback; 87 register GCClosure *cc = reinterpret_cast<GCClosure*>(closure); 88 register gpointer data1, data2; 89 90 g_return_if_fail(n_param_values == 3); 91 92 if (G_CCLOSURE_SWAP_DATA(closure)) { 93 data1 = closure->data; 94 data2 = g_value_peek_pointer(param_values + 0); 95 } else { 96 data1 = g_value_peek_pointer(param_values + 0); 97 data2 = closure->data; 98 } 99 100 callback = reinterpret_cast<GMarshalFunc_VOID__OBJECT_BOXED>( 101 marshal_data ? marshal_data : cc->callback); 102 103 callback(data1, 104 g_value_get_object(param_values + 1), 105 g_value_get_boxed(param_values + 2), 106 data2); 107 } 108 109 } // namespace 110 111 G_BEGIN_DECLS 112 113 static void gtk_expanded_container_size_allocate(GtkWidget* widget, 114 GtkAllocation* allocation); 115 116 G_DEFINE_TYPE(GtkExpandedContainer, gtk_expanded_container, GTK_TYPE_FIXED) 117 118 static void gtk_expanded_container_class_init( 119 GtkExpandedContainerClass *klass) { 120 GtkObjectClass* object_class = 121 reinterpret_cast<GtkObjectClass*>(klass); 122 123 GtkWidgetClass* widget_class = 124 reinterpret_cast<GtkWidgetClass*>(klass); 125 widget_class->size_allocate = gtk_expanded_container_size_allocate; 126 127 expanded_container_signals[CHILD_SIZE_REQUEST] = 128 g_signal_new("child-size-request", 129 G_OBJECT_CLASS_TYPE(object_class), 130 static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST), 131 0, 132 NULL, NULL, 133 Marshal_VOID__OBJECT_BOXED, 134 G_TYPE_NONE, 2, 135 GTK_TYPE_WIDGET, 136 GTK_TYPE_REQUISITION | G_SIGNAL_TYPE_STATIC_SCOPE); 137 } 138 139 static void gtk_expanded_container_init(GtkExpandedContainer* container) { 140 } 141 142 static void gtk_expanded_container_size_allocate(GtkWidget* widget, 143 GtkAllocation* allocation) { 144 widget->allocation = *allocation; 145 146 if (!GTK_WIDGET_NO_WINDOW(widget) && GTK_WIDGET_REALIZED(widget)) { 147 gdk_window_move_resize(widget->window, 148 allocation->x, 149 allocation->y, 150 allocation->width, 151 allocation->height); 152 } 153 154 SizeAllocateData data; 155 data.container = widget; 156 data.allocation = allocation; 157 data.border_width = gtk_container_get_border_width(GTK_CONTAINER(widget)); 158 159 gtk_container_foreach(GTK_CONTAINER(widget), ChildSizeAllocate, &data); 160 } 161 162 GtkWidget* gtk_expanded_container_new() { 163 return GTK_WIDGET(g_object_new(GTK_TYPE_EXPANDED_CONTAINER, NULL)); 164 } 165 166 void gtk_expanded_container_put(GtkExpandedContainer* container, 167 GtkWidget* widget, gint x, gint y) { 168 g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container)); 169 g_return_if_fail(GTK_IS_WIDGET(widget)); 170 gtk_fixed_put(GTK_FIXED(container), widget, x, y); 171 } 172 173 void gtk_expanded_container_move(GtkExpandedContainer* container, 174 GtkWidget* widget, gint x, gint y) { 175 g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container)); 176 g_return_if_fail(GTK_IS_WIDGET(widget)); 177 gtk_fixed_move(GTK_FIXED(container), widget, x, y); 178 } 179 180 void gtk_expanded_container_set_has_window(GtkExpandedContainer* container, 181 gboolean has_window) { 182 g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container)); 183 g_return_if_fail(!GTK_WIDGET_REALIZED(container)); 184 gtk_fixed_set_has_window(GTK_FIXED(container), has_window); 185 } 186 187 gboolean gtk_expanded_container_get_has_window( 188 GtkExpandedContainer* container) { 189 g_return_val_if_fail(GTK_IS_EXPANDED_CONTAINER(container), FALSE); 190 return gtk_fixed_get_has_window(GTK_FIXED(container)); 191 } 192 193 G_END_DECLS 194