diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-24 22:23:40 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-24 22:23:40 +0000 |
commit | 4b4eb65a253a5fb16bd243a7a3d31a24881afcb1 (patch) | |
tree | 9f9cf7618d6ef35a5b3675e42b96245ebf43641f /ui/base/gtk | |
parent | 53de9917a5e3424b4a022059c69a1cc6b860c094 (diff) | |
download | chromium_src-4b4eb65a253a5fb16bd243a7a3d31a24881afcb1.zip chromium_src-4b4eb65a253a5fb16bd243a7a3d31a24881afcb1.tar.gz chromium_src-4b4eb65a253a5fb16bd243a7a3d31a24881afcb1.tar.bz2 |
content: Move gtk_floating_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/7701012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98130 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base/gtk')
-rw-r--r-- | ui/base/gtk/gtk_floating_container.cc | 320 | ||||
-rw-r--r-- | ui/base/gtk/gtk_floating_container.h | 90 |
2 files changed, 410 insertions, 0 deletions
diff --git a/ui/base/gtk/gtk_floating_container.cc b/ui/base/gtk/gtk_floating_container.cc new file mode 100644 index 0000000..0bda427 --- /dev/null +++ b/ui/base/gtk/gtk_floating_container.cc @@ -0,0 +1,320 @@ +// 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_floating_container.h" + +#include <gtk/gtk.h> +#include <gtk/gtkmarshal.h> +#include <gtk/gtkprivate.h> + +#include <algorithm> + +namespace { + +enum { + SET_FLOATING_POSITION, + LAST_SIGNAL +}; + +enum { + CHILD_PROP_0, + CHILD_PROP_X, + CHILD_PROP_Y +}; + +// Returns the GtkFloatingContainerChild associated with |widget| (or NULL if +// |widget| not found). +GtkFloatingContainerChild* GetChild(GtkFloatingContainer* container, + GtkWidget* widget) { + for (GList* floating_children = container->floating_children; + floating_children; floating_children = g_list_next(floating_children)) { + GtkFloatingContainerChild* child = + reinterpret_cast<GtkFloatingContainerChild*>(floating_children->data); + + if (child->widget == widget) + return child; + } + + return NULL; +} + +} // namespace + +G_BEGIN_DECLS + +static void gtk_floating_container_remove(GtkContainer* container, + GtkWidget* widget); +static void gtk_floating_container_forall(GtkContainer* container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static void gtk_floating_container_size_request(GtkWidget* widget, + GtkRequisition* requisition); +static void gtk_floating_container_size_allocate(GtkWidget* widget, + GtkAllocation* allocation); +static void gtk_floating_container_set_child_property(GtkContainer* container, + GtkWidget* child, + guint property_id, + const GValue* value, + GParamSpec* pspec); +static void gtk_floating_container_get_child_property(GtkContainer* container, + GtkWidget* child, + guint property_id, + GValue* value, + GParamSpec* pspec); + +static guint floating_container_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(GtkFloatingContainer, gtk_floating_container, GTK_TYPE_BIN) + +static void gtk_floating_container_class_init( + GtkFloatingContainerClass *klass) { + GtkObjectClass* object_class = + reinterpret_cast<GtkObjectClass*>(klass); + + GtkWidgetClass* widget_class = + reinterpret_cast<GtkWidgetClass*>(klass); + widget_class->size_request = gtk_floating_container_size_request; + widget_class->size_allocate = gtk_floating_container_size_allocate; + + GtkContainerClass* container_class = + reinterpret_cast<GtkContainerClass*>(klass); + container_class->remove = gtk_floating_container_remove; + container_class->forall = gtk_floating_container_forall; + + container_class->set_child_property = + gtk_floating_container_set_child_property; + container_class->get_child_property = + gtk_floating_container_get_child_property; + + gtk_container_class_install_child_property( + container_class, + CHILD_PROP_X, + g_param_spec_int("x", + "X position", + "X position of child widget", + G_MININT, + G_MAXINT, + 0, + static_cast<GParamFlags>(GTK_PARAM_READWRITE))); + + gtk_container_class_install_child_property( + container_class, + CHILD_PROP_Y, + g_param_spec_int("y", + "Y position", + "Y position of child widget", + G_MININT, + G_MAXINT, + 0, + static_cast<GParamFlags>(GTK_PARAM_READWRITE))); + + floating_container_signals[SET_FLOATING_POSITION] = + g_signal_new("set-floating-position", + G_OBJECT_CLASS_TYPE(object_class), + static_cast<GSignalFlags>(G_SIGNAL_RUN_FIRST | + G_SIGNAL_ACTION), + 0, + NULL, NULL, + gtk_marshal_VOID__BOXED, + G_TYPE_NONE, 1, + GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE); +} + +static void gtk_floating_container_init(GtkFloatingContainer* container) { + GTK_WIDGET_SET_FLAGS(container, GTK_NO_WINDOW); + + container->floating_children = NULL; +} + +static void gtk_floating_container_remove(GtkContainer* container, + GtkWidget* widget) { + g_return_if_fail(GTK_IS_WIDGET(widget)); + + GtkBin* bin = GTK_BIN(container); + if (bin->child == widget) { + ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class))->remove) + (container, widget); + } else { + // Handle the other case where it's in our |floating_children| list. + GtkFloatingContainer* floating = GTK_FLOATING_CONTAINER(container); + GList* children = floating->floating_children; + gboolean removed_child = false; + while (children) { + GtkFloatingContainerChild* child = + reinterpret_cast<GtkFloatingContainerChild*>(children->data); + + if (child->widget == widget) { + removed_child = true; + gboolean was_visible = gtk_widget_get_visible(GTK_WIDGET(widget)); + + gtk_widget_unparent(widget); + + floating->floating_children = + g_list_remove_link(floating->floating_children, children); + g_list_free(children); + g_free(child); + + if (was_visible && gtk_widget_get_visible(GTK_WIDGET(container))) + gtk_widget_queue_resize(GTK_WIDGET(container)); + + break; + } + children = children->next; + } + + g_return_if_fail(removed_child); + } +} + +static void gtk_floating_container_forall(GtkContainer* container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) { + g_return_if_fail(container != NULL); + g_return_if_fail(callback != NULL); + + // Let GtkBin do its part of the forall. + ((GTK_CONTAINER_CLASS(gtk_floating_container_parent_class))->forall) + (container, include_internals, callback, callback_data); + + GtkFloatingContainer* floating = GTK_FLOATING_CONTAINER(container); + GList* children = floating->floating_children; + while (children) { + GtkFloatingContainerChild* child = + reinterpret_cast<GtkFloatingContainerChild*>(children->data); + children = children->next; + + (*callback)(child->widget, callback_data); + } +} + +static void gtk_floating_container_size_request(GtkWidget* widget, + GtkRequisition* requisition) { + GtkBin* bin = GTK_BIN(widget); + if (bin && bin->child) { + gtk_widget_size_request(bin->child, requisition); + } else { + requisition->width = 0; + requisition->height = 0; + } +} + +static void gtk_floating_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); + } + + // Give the same allocation to our GtkBin component. + GtkBin* bin = GTK_BIN(widget); + if (bin->child) { + gtk_widget_size_allocate(bin->child, allocation); + } + + // We need to give whoever is pulling our strings a chance to set the "x" and + // "y" properties on all of our children. + g_signal_emit(widget, floating_container_signals[SET_FLOATING_POSITION], 0, + allocation); + + // Our allocation has been set. We've asked our controller to place the other + // widgets. Pass out allocations to all our children based on where they want + // to be. + GtkFloatingContainer* container = GTK_FLOATING_CONTAINER(widget); + GList* children = container->floating_children; + GtkAllocation child_allocation; + GtkRequisition child_requisition; + while (children) { + GtkFloatingContainerChild* child = + reinterpret_cast<GtkFloatingContainerChild*>(children->data); + children = children->next; + + if (gtk_widget_get_visible(GTK_WIDGET(child->widget))) { + gtk_widget_size_request(child->widget, &child_requisition); + child_allocation.x = allocation->x + child->x; + child_allocation.y = allocation->y + child->y; + child_allocation.width = std::max(1, std::min(child_requisition.width, + allocation->width)); + child_allocation.height = std::max(1, std::min(child_requisition.height, + allocation->height)); + gtk_widget_size_allocate(child->widget, &child_allocation); + } + } +} + +static void gtk_floating_container_set_child_property(GtkContainer* container, + GtkWidget* child, + guint property_id, + const GValue* value, + GParamSpec* pspec) { + GtkFloatingContainerChild* floating_child = + GetChild(GTK_FLOATING_CONTAINER(container), child); + g_return_if_fail(floating_child); + + switch (property_id) { + case CHILD_PROP_X: + floating_child->x = g_value_get_int(value); + gtk_widget_child_notify(child, "x"); + break; + case CHILD_PROP_Y: + floating_child->y = g_value_get_int(value); + gtk_widget_child_notify(child, "y"); + break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID( + container, property_id, pspec); + break; + }; +} + +static void gtk_floating_container_get_child_property(GtkContainer* container, + GtkWidget* child, + guint property_id, + GValue* value, + GParamSpec* pspec) { + GtkFloatingContainerChild* floating_child = + GetChild(GTK_FLOATING_CONTAINER(container), child); + g_return_if_fail(floating_child); + + switch (property_id) { + case CHILD_PROP_X: + g_value_set_int(value, floating_child->x); + break; + case CHILD_PROP_Y: + g_value_set_int(value, floating_child->y); + break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID( + container, property_id, pspec); + break; + }; +} + +GtkWidget* gtk_floating_container_new() { + return GTK_WIDGET(g_object_new(GTK_TYPE_FLOATING_CONTAINER, NULL)); +} + +void gtk_floating_container_add_floating(GtkFloatingContainer* container, + GtkWidget* widget) { + g_return_if_fail(GTK_IS_FLOATING_CONTAINER(container)); + g_return_if_fail(GTK_IS_WIDGET(widget)); + + GtkFloatingContainerChild* child_info = g_new(GtkFloatingContainerChild, 1); + child_info->widget = widget; + child_info->x = 0; + child_info->y = 0; + + gtk_widget_set_parent(widget, GTK_WIDGET(container)); + + container->floating_children = + g_list_append(container->floating_children, child_info); +} + +G_END_DECLS diff --git a/ui/base/gtk/gtk_floating_container.h b/ui/base/gtk/gtk_floating_container.h new file mode 100644 index 0000000..a6977df --- /dev/null +++ b/ui/base/gtk/gtk_floating_container.h @@ -0,0 +1,90 @@ +// 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_FLOATING_CONTAINER_H_ +#define UI_BASE_GTK_GTK_FLOATING_CONTAINER_H_ +#pragma once + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +#include "ui/base/ui_export.h" + +// A specialized container, which is a cross between a GtkBin and a +// GtkFixed. This container dervies from GtkBin and the implementation of +// gtk_container_add() is the same: only one GtkWidget can be added through +// that interface. The GtkBin portion contains normal content and is given the +// same allocation that this container has. +// +// In addition, any number of widgets can be added through the +// gtk_floating_container_add_floating() method, which provides functionality +// similar to a GtkFixed. Unlike a GtkFixed, coordinates are not set when you +// gtk_fixed_put(). The location of the floating widgets is determined while +// running the "set-floating-position" signal, which is emitted during this +// container's "size-allocate" handler. +// +// The "set-floating-position" signal is (semi-)mandatory if you want widgets +// placed anywhere other than the origin and should have the following +// signature: +// +// void (*set_floating_position)(GtkFloatingContainer* container, +// GtkAllocation* allocation, +// gpointer userdata); +// +// Your handler should, for each floating widget, set the "x" and "y" child +// properties. + +G_BEGIN_DECLS + +#define GTK_TYPE_FLOATING_CONTAINER \ + (gtk_floating_container_get_type()) +#define GTK_FLOATING_CONTAINER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_FLOATING_CONTAINER, \ + GtkFloatingContainer)) +#define GTK_FLOATING_CONTAINER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_FLOATING_CONTAINER, \ + GtkFloatingContainerClass)) +#define GTK_IS_FLOATING_CONTAINER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_FLOATING_CONTAINER)) +#define GTK_IS_FLOATING_CONTAINER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_FLOATING_CONTAINER)) +#define GTK_FLOATING_CONTAINER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_FLOATING_CONTAINER, \ + GtkFloatingContainerClass)) + +typedef struct _GtkFloatingContainer GtkFloatingContainer; +typedef struct _GtkFloatingContainerClass GtkFloatingContainerClass; +typedef struct _GtkFloatingContainerChild GtkFloatingContainerChild; + +struct _GtkFloatingContainer { + // Parent class. + GtkBin bin; + + // A GList of all our floating children, in GtkFloatingContainerChild + // structs. Owned by the GtkFloatingContainer. + GList* floating_children; +}; + +struct _GtkFloatingContainerClass { + GtkBinClass parent_class; +}; + +// Internal structure used to associate a widget and its x/y child properties. +struct _GtkFloatingContainerChild { + GtkWidget* widget; + gint x; + gint y; +}; + +UI_EXPORT GType gtk_floating_container_get_type() G_GNUC_CONST; +UI_EXPORT GtkWidget* gtk_floating_container_new(); +UI_EXPORT void gtk_floating_container_add_floating( + GtkFloatingContainer* container, + GtkWidget* widget); +// Use gtk_container_remove to remove all widgets; both widgets added with +// gtk_container_add() and gtk_floating_container_add_floating(). + +G_END_DECLS + +#endif // UI_BASE_GTK_GTK_FLOATING_CONTAINER_H_ |