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