• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetChildPosition(GtkWidget * container,GtkWidget * child,int * x,int * y)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 
ChildSizeAllocate(GtkWidget * child,gpointer userdata)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 
Marshal_VOID__OBJECT_BOXED(GClosure * closure,GValue * return_value G_GNUC_UNUSED,guint n_param_values,const GValue * param_values,gpointer invocation_hint G_GNUC_UNUSED,gpointer marshal_data)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 
G_DEFINE_TYPE(GtkExpandedContainer,gtk_expanded_container,GTK_TYPE_FIXED)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 
gtk_expanded_container_init(GtkExpandedContainer * container)139 static void gtk_expanded_container_init(GtkExpandedContainer* container) {
140 }
141 
gtk_expanded_container_size_allocate(GtkWidget * widget,GtkAllocation * allocation)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 
gtk_expanded_container_new()162 GtkWidget* gtk_expanded_container_new() {
163   return GTK_WIDGET(g_object_new(GTK_TYPE_EXPANDED_CONTAINER, NULL));
164 }
165 
gtk_expanded_container_put(GtkExpandedContainer * container,GtkWidget * widget,gint x,gint y)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 
gtk_expanded_container_move(GtkExpandedContainer * container,GtkWidget * widget,gint x,gint y)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 
gtk_expanded_container_set_has_window(GtkExpandedContainer * container,gboolean has_window)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 
gtk_expanded_container_get_has_window(GtkExpandedContainer * container)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