summaryrefslogtreecommitdiffstats
path: root/ui/base
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-25 20:16:22 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-25 20:16:22 +0000
commit9fb4ad4cf87dfc132627aef2dd513be8b45940ae (patch)
tree8f639ec0cbf3230bd2f9de545832ab2da536a110 /ui/base
parentc203f03fc14b048592445ee37620fa5c366b2251 (diff)
downloadchromium_src-9fb4ad4cf87dfc132627aef2dd513be8b45940ae.zip
chromium_src-9fb4ad4cf87dfc132627aef2dd513be8b45940ae.tar.gz
chromium_src-9fb4ad4cf87dfc132627aef2dd513be8b45940ae.tar.bz2
content: Move gtk_expanded_container to ui/base/gtk/.
This is used in code that will be moved for use in content_shell. BUG=93804 TEST=none; code move Review URL: http://codereview.chromium.org/7740003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98282 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-rw-r--r--ui/base/gtk/gtk_expanded_container.cc193
-rw-r--r--ui/base/gtk/gtk_expanded_container.h75
-rw-r--r--ui/base/gtk/gtk_expanded_container_unittest.cc159
3 files changed, 427 insertions, 0 deletions
diff --git a/ui/base/gtk/gtk_expanded_container.cc b/ui/base/gtk/gtk_expanded_container.cc
new file mode 100644
index 0000000..e5b23b5
--- /dev/null
+++ b/ui/base/gtk/gtk_expanded_container.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/gtk/gtk_expanded_container.h"
+
+#include <gtk/gtk.h>
+
+#include <algorithm>
+
+namespace {
+
+enum {
+ CHILD_SIZE_REQUEST,
+ LAST_SIGNAL
+};
+
+guint expanded_container_signals[LAST_SIGNAL] = { 0 };
+
+struct SizeAllocateData {
+ GtkWidget* container;
+ GtkAllocation* allocation;
+ int border_width;
+};
+
+void GetChildPosition(GtkWidget* container, GtkWidget* child, int* x, int* y) {
+ GValue v = { 0 };
+ g_value_init(&v, G_TYPE_INT);
+ gtk_container_child_get_property(GTK_CONTAINER(container), child, "x", &v);
+ *x = g_value_get_int(&v);
+ gtk_container_child_get_property(GTK_CONTAINER(container), child, "y", &v);
+ *y = g_value_get_int(&v);
+ g_value_unset(&v);
+}
+
+void ChildSizeAllocate(GtkWidget* child, gpointer userdata) {
+ if (!gtk_widget_get_visible(child))
+ return;
+
+ SizeAllocateData* data = reinterpret_cast<SizeAllocateData*>(userdata);
+
+ GtkRequisition child_requisition;
+ child_requisition.width = data->allocation->width - data->border_width * 2;
+ child_requisition.height = data->allocation->height - data->border_width * 2;
+
+ // We need to give whoever is pulling our strings a chance to adjust the
+ // size of our children.
+ g_signal_emit(data->container,
+ expanded_container_signals[CHILD_SIZE_REQUEST], 0,
+ child, &child_requisition);
+
+ GtkAllocation child_allocation;
+ child_allocation.width = child_requisition.width;
+ child_allocation.height = child_requisition.height;
+ if (child_allocation.width < 0 || child_allocation.height < 0) {
+ gtk_widget_get_child_requisition(child, &child_requisition);
+ if (child_allocation.width < 0)
+ child_allocation.width = child_requisition.width;
+ if (child_allocation.height < 0)
+ child_allocation.height = child_requisition.height;
+ }
+
+ int x, y;
+ GetChildPosition(data->container, child, &x, &y);
+
+ child_allocation.x = x + data->border_width;
+ child_allocation.y = y + data->border_width;
+
+ if (GTK_WIDGET_NO_WINDOW(data->container)) {
+ child_allocation.x += data->allocation->x;
+ child_allocation.y += data->allocation->y;
+ }
+ gtk_widget_size_allocate(child, &child_allocation);
+}
+
+void 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) {
+ typedef void (*GMarshalFunc_VOID__OBJECT_BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__OBJECT_BOXED callback;
+ register GCClosure *cc = reinterpret_cast<GCClosure*>(closure);
+ register gpointer data1, data2;
+
+ g_return_if_fail(n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA(closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer(param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer(param_values + 0);
+ data2 = closure->data;
+ }
+
+ callback = reinterpret_cast<GMarshalFunc_VOID__OBJECT_BOXED>(
+ marshal_data ? marshal_data : cc->callback);
+
+ callback(data1,
+ g_value_get_object(param_values + 1),
+ g_value_get_boxed(param_values + 2),
+ data2);
+}
+
+} // namespace
+
+G_BEGIN_DECLS
+
+static void gtk_expanded_container_size_allocate(GtkWidget* widget,
+ GtkAllocation* allocation);
+
+G_DEFINE_TYPE(GtkExpandedContainer, gtk_expanded_container, GTK_TYPE_FIXED)
+
+static void gtk_expanded_container_class_init(
+ GtkExpandedContainerClass *klass) {
+ GtkObjectClass* object_class =
+ reinterpret_cast<GtkObjectClass*>(klass);
+
+ GtkWidgetClass* widget_class =
+ reinterpret_cast<GtkWidgetClass*>(klass);
+ widget_class->size_allocate = gtk_expanded_container_size_allocate;
+
+ expanded_container_signals[CHILD_SIZE_REQUEST] =
+ g_signal_new("child-size-request",
+ G_OBJECT_CLASS_TYPE(object_class),
+ static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST),
+ 0,
+ NULL, NULL,
+ Marshal_VOID__OBJECT_BOXED,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_WIDGET,
+ GTK_TYPE_REQUISITION | G_SIGNAL_TYPE_STATIC_SCOPE);
+}
+
+static void gtk_expanded_container_init(GtkExpandedContainer* container) {
+}
+
+static void gtk_expanded_container_size_allocate(GtkWidget* widget,
+ GtkAllocation* allocation) {
+ widget->allocation = *allocation;
+
+ if (!GTK_WIDGET_NO_WINDOW(widget) && GTK_WIDGET_REALIZED(widget)) {
+ gdk_window_move_resize(widget->window,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+ }
+
+ SizeAllocateData data;
+ data.container = widget;
+ data.allocation = allocation;
+ data.border_width = gtk_container_get_border_width(GTK_CONTAINER(widget));
+
+ gtk_container_foreach(GTK_CONTAINER(widget), ChildSizeAllocate, &data);
+}
+
+GtkWidget* gtk_expanded_container_new() {
+ return GTK_WIDGET(g_object_new(GTK_TYPE_EXPANDED_CONTAINER, NULL));
+}
+
+void gtk_expanded_container_put(GtkExpandedContainer* container,
+ GtkWidget* widget, gint x, gint y) {
+ g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
+ g_return_if_fail(GTK_IS_WIDGET(widget));
+ gtk_fixed_put(GTK_FIXED(container), widget, x, y);
+}
+
+void gtk_expanded_container_move(GtkExpandedContainer* container,
+ GtkWidget* widget, gint x, gint y) {
+ g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
+ g_return_if_fail(GTK_IS_WIDGET(widget));
+ gtk_fixed_move(GTK_FIXED(container), widget, x, y);
+}
+
+void gtk_expanded_container_set_has_window(GtkExpandedContainer* container,
+ gboolean has_window) {
+ g_return_if_fail(GTK_IS_EXPANDED_CONTAINER(container));
+ g_return_if_fail(!GTK_WIDGET_REALIZED(container));
+ gtk_fixed_set_has_window(GTK_FIXED(container), has_window);
+}
+
+gboolean gtk_expanded_container_get_has_window(
+ GtkExpandedContainer* container) {
+ g_return_val_if_fail(GTK_IS_EXPANDED_CONTAINER(container), FALSE);
+ return gtk_fixed_get_has_window(GTK_FIXED(container));
+}
+
+G_END_DECLS
diff --git a/ui/base/gtk/gtk_expanded_container.h b/ui/base/gtk/gtk_expanded_container.h
new file mode 100644
index 0000000..23f1d69
--- /dev/null
+++ b/ui/base/gtk/gtk_expanded_container.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_GTK_GTK_EXPANDED_CONTAINER_H_
+#define UI_BASE_GTK_GTK_EXPANDED_CONTAINER_H_
+#pragma once
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "ui/base/ui_export.h"
+
+// A specialized container derived from GtkFixed, which expands the size of its
+// children to fill the container, in one or both directions. The usage of this
+// container is similar to GtkFixed.
+//
+// The "child-size-request" signal is optional, if you want to expand child
+// widgets to customized size other than the container's size. It should have
+// the following signature:
+//
+// void (*child_size_request)(GtkExpandedContainer* container,
+// GtkWidget* child,
+// GtkRequisition* requisition);
+//
+// This signal is emitted for each child with the requisition set to the size of
+// the container. Your handler may adjust the value of the requisition. If the
+// width or height is set to -1, then that direction will not be expanded, and
+// the original size request of the child will be used.
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_EXPANDED_CONTAINER \
+ (gtk_expanded_container_get_type())
+#define GTK_EXPANDED_CONTAINER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_EXPANDED_CONTAINER, \
+ GtkExpandedContainer))
+#define GTK_EXPANDED_CONTAINER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_EXPANDED_CONTAINER, \
+ GtkExpandedContainerClass))
+#define GTK_IS_EXPANDED_CONTAINER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_EXPANDED_CONTAINER))
+#define GTK_IS_EXPANDED_CONTAINER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_EXPANDED_CONTAINER))
+#define GTK_EXPANDED_CONTAINER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_EXPANDED_CONTAINER, \
+ GtkExpandedContainerClass))
+
+typedef struct _GtkExpandedContainer GtkExpandedContainer;
+typedef struct _GtkExpandedContainerClass GtkExpandedContainerClass;
+
+struct _GtkExpandedContainer {
+ // Parent class.
+ GtkFixed fixed;
+};
+
+struct _GtkExpandedContainerClass {
+ GtkFixedClass parent_class;
+};
+
+UI_EXPORT GType gtk_expanded_container_get_type() G_GNUC_CONST;
+UI_EXPORT GtkWidget* gtk_expanded_container_new();
+UI_EXPORT void gtk_expanded_container_put(GtkExpandedContainer* container,
+ GtkWidget* widget, gint x, gint y);
+UI_EXPORT void gtk_expanded_container_move(GtkExpandedContainer* container,
+ GtkWidget* widget, gint x, gint y);
+UI_EXPORT void gtk_expanded_container_set_has_window(
+ GtkExpandedContainer* container,
+ gboolean has_window);
+UI_EXPORT gboolean gtk_expanded_container_get_has_window(
+ GtkExpandedContainer* container);
+
+G_END_DECLS
+
+#endif // UI_BASE_GTK_GTK_EXPANDED_CONTAINER_H_
diff --git a/ui/base/gtk/gtk_expanded_container_unittest.cc b/ui/base/gtk/gtk_expanded_container_unittest.cc
new file mode 100644
index 0000000..c8721a3
--- /dev/null
+++ b/ui/base/gtk/gtk_expanded_container_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/gtk/gtk_expanded_container.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+class GtkExpandedContainerTest : public testing::Test {
+ protected:
+ GtkExpandedContainerTest()
+ : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
+ expanded_(gtk_expanded_container_new()) {
+ gtk_window_set_default_size(GTK_WINDOW(window_), 200, 200);
+ gtk_container_add(GTK_CONTAINER(window_), expanded_);
+ }
+ ~GtkExpandedContainerTest() {
+ gtk_widget_destroy(window_);
+ }
+
+ bool FindChild(GtkWidget* widget) {
+ GList* children = gtk_container_get_children(GTK_CONTAINER(expanded_));
+ for (GList* child = children; child; child = child->next) {
+ if (GTK_WIDGET(child->data) == widget) {
+ g_list_free(children);
+ return true;
+ }
+ }
+ g_list_free(children);
+ return false;
+ }
+
+ int GetChildX(GtkWidget* widget) {
+ GValue x = { 0 };
+ g_value_init(&x, G_TYPE_INT);
+ gtk_container_child_get_property(GTK_CONTAINER(expanded_), widget, "x", &x);
+ return g_value_get_int(&x);
+ }
+
+ int GetChildY(GtkWidget* widget) {
+ GValue y = { 0 };
+ g_value_init(&y, G_TYPE_INT);
+ gtk_container_child_get_property(GTK_CONTAINER(expanded_), widget, "y", &y);
+ return g_value_get_int(&y);
+ }
+
+ protected:
+ GtkWidget* window_;
+ GtkWidget* expanded_;
+};
+
+TEST_F(GtkExpandedContainerTest, AddRemove) {
+ GtkWidget* child1 = gtk_fixed_new();
+ GtkWidget* child2 = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(expanded_), child1);
+ ASSERT_TRUE(FindChild(child1));
+
+ gtk_container_add(GTK_CONTAINER(expanded_), child2);
+ ASSERT_TRUE(FindChild(child2));
+ ASSERT_TRUE(FindChild(child1));
+
+ gtk_container_remove(GTK_CONTAINER(expanded_), child1);
+ ASSERT_FALSE(FindChild(child1));
+ ASSERT_TRUE(FindChild(child2));
+
+ gtk_container_remove(GTK_CONTAINER(expanded_), child2);
+ ASSERT_FALSE(FindChild(child2));
+}
+
+TEST_F(GtkExpandedContainerTest, Expand) {
+ GtkWidget* child1 = gtk_fixed_new();
+ GtkWidget* child2 = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(expanded_), child1);
+ gtk_expanded_container_put(GTK_EXPANDED_CONTAINER(expanded_),
+ child2, 10, 20);
+ gtk_widget_show_all(window_);
+
+ GtkAllocation allocation = { 0, 0, 50, 100 };
+ gtk_widget_size_allocate(expanded_, &allocation);
+
+ EXPECT_EQ(0, child1->allocation.x);
+ EXPECT_EQ(0, child1->allocation.y);
+ EXPECT_EQ(50, child1->allocation.width);
+ EXPECT_EQ(100, child1->allocation.height);
+
+ EXPECT_EQ(10, child2->allocation.x);
+ EXPECT_EQ(20, child2->allocation.y);
+ EXPECT_EQ(50, child2->allocation.width);
+ EXPECT_EQ(100, child2->allocation.height);
+
+ allocation.x = 10;
+ allocation.y = 20;
+ gtk_widget_size_allocate(expanded_, &allocation);
+
+ EXPECT_EQ(10, child1->allocation.x);
+ EXPECT_EQ(20, child1->allocation.y);
+ EXPECT_EQ(20, child2->allocation.x);
+ EXPECT_EQ(40, child2->allocation.y);
+}
+
+// Test if the size allocation for children still works when using own
+// GdkWindow. In this case, the children's origin starts from (0, 0) rather
+// than the container's origin.
+TEST_F(GtkExpandedContainerTest, HasWindow) {
+ GtkWidget* child = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(expanded_), child);
+ gtk_expanded_container_set_has_window(GTK_EXPANDED_CONTAINER(expanded_),
+ TRUE);
+ gtk_widget_show_all(window_);
+
+ GtkAllocation allocation = { 10, 10, 50, 100 };
+ gtk_widget_size_allocate(expanded_, &allocation);
+
+ EXPECT_EQ(0, child->allocation.x);
+ EXPECT_EQ(0, child->allocation.y);
+ EXPECT_EQ(50, child->allocation.width);
+ EXPECT_EQ(100, child->allocation.height);
+}
+
+static void OnChildSizeRequest(GtkExpandedContainer* container,
+ GtkWidget* child,
+ GtkRequisition* requisition,
+ gpointer userdata) {
+ ASSERT_EQ(child, GTK_WIDGET(userdata));
+ requisition->width = 250;
+ requisition->height = -1;
+}
+
+TEST_F(GtkExpandedContainerTest, ChildSizeRequest) {
+ GtkWidget* child = gtk_fixed_new();
+ gtk_widget_set_size_request(child, 10, 25);
+ g_signal_connect(expanded_, "child-size-request",
+ G_CALLBACK(OnChildSizeRequest), child);
+ gtk_container_add(GTK_CONTAINER(expanded_), child);
+ gtk_widget_show_all(window_);
+
+ GtkAllocation allocation = { 0, 0, 300, 100 };
+ gtk_widget_size_allocate(expanded_, &allocation);
+
+ EXPECT_EQ(0, child->allocation.x);
+ EXPECT_EQ(0, child->allocation.y);
+ EXPECT_EQ(250, child->allocation.width);
+ EXPECT_EQ(25, child->allocation.height);
+}
+
+TEST_F(GtkExpandedContainerTest, ChildPosition) {
+ GtkWidget* child = gtk_fixed_new();
+ gtk_expanded_container_put(GTK_EXPANDED_CONTAINER(expanded_),
+ child, 10, 20);
+ gtk_widget_show_all(window_);
+
+ EXPECT_EQ(10, GetChildX(child));
+ EXPECT_EQ(20, GetChildY(child));
+
+ gtk_expanded_container_move(GTK_EXPANDED_CONTAINER(expanded_),
+ child, 40, 50);
+ EXPECT_EQ(40, GetChildX(child));
+ EXPECT_EQ(50, GetChildY(child));
+}