[gtk+/overlay: 1/34] overlay: add initial version of gtkoverlay



commit aea302af51723c46a04c4f4a2d57ade5d1e40f75
Author: Ignacio Casal Quinteiro <icq gnome org>
Date:   Thu May 19 18:53:05 2011 +0200

    overlay: add initial version of gtkoverlay

 gtk/Makefile.am       |    4 +
 gtk/gtkoverlay.c      |  529 +++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkoverlay.h      |   81 ++++++++
 gtk/gtkoverlaychild.c |  307 ++++++++++++++++++++++++++++
 gtk/gtkoverlaychild.h |   70 +++++++
 5 files changed, 991 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 4111938..ee600de 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -256,6 +256,8 @@ gtk_public_h_sources = 		\
 	gtknumerableicon.h	\
 	gtkoffscreenwindow.h	\
 	gtkorientable.h		\
+	gtkoverlay.h		\
+	gtkoverlaychild.h	\
 	gtkpagesetup.h		\
 	gtkpaned.h		\
 	gtkpapersize.h		\
@@ -587,6 +589,8 @@ gtk_base_c_sources = 		\
 	gtknumerableicon.c	\
 	gtkoffscreenwindow.c	\
 	gtkorientable.c		\
+	gtkoverlay.c		\
+	gtkoverlaychild.c	\
 	gtkpagesetup.c		\
 	gtkpaned.c		\
 	gtkpango.c		\
diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c
new file mode 100644
index 0000000..68221df
--- /dev/null
+++ b/gtk/gtkoverlay.c
@@ -0,0 +1,529 @@
+/*
+ * gtkoverlay.c
+ * This file is part of gtk
+ *
+ * Copyright (C) 2011 - Ignacio Casal Quinteiro, Mike Krüger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkoverlay.h"
+
+typedef struct
+{
+  GtkWidget *child;
+  GtkWidget *original;
+} ChildContainer;
+
+struct _GtkOverlayPrivate
+{
+  GtkWidget *main_widget;
+  GtkWidget *relative_widget;
+  GSList    *children;
+};
+
+enum
+{
+  PROP_0,
+  PROP_MAIN_WIDGET,
+  PROP_RELATIVE_WIDGET
+};
+
+G_DEFINE_TYPE (GtkOverlay, gtk_overlay, GTK_TYPE_CONTAINER)
+
+static ChildContainer *
+child_container_new (GtkWidget *child,
+                     GtkWidget *original)
+{
+  ChildContainer *ret;
+
+  ret = g_slice_new (ChildContainer);
+  ret->child = child;
+  ret->original = original;
+
+  return ret;
+}
+
+static void
+child_container_free (ChildContainer *container)
+{
+  g_slice_free (ChildContainer, container);
+}
+
+static GtkWidget *
+child_container_get_child (ChildContainer *container)
+{
+  GtkWidget *child;
+
+  if (container->child != NULL)
+    child = container->child;
+  else
+    child = container->original;
+
+  return child;
+}
+
+static void
+add_toplevel_widget (GtkOverlay *overlay,
+                     GtkWidget  *child,
+                     GtkWidget  *original)
+{
+  ChildContainer *container;
+
+  if (child != NULL)
+    gtk_widget_set_parent (child, GTK_WIDGET (overlay));
+  else
+    gtk_widget_set_parent (original, GTK_WIDGET (overlay));
+
+  container = child_container_new (child, original);
+
+  overlay->priv->children = g_slist_append (overlay->priv->children,
+                                            container);
+}
+
+static void
+gtk_overlay_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (gtk_overlay_parent_class)->dispose (object);
+}
+
+static void
+gtk_overlay_get_property (GObject    *object,
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (object);
+  GtkOverlayPrivate *priv = overlay->priv;
+
+  switch (prop_id)
+    {
+      case PROP_MAIN_WIDGET:
+        g_value_set_object (value, priv->main_widget);
+        break;
+
+      case PROP_RELATIVE_WIDGET:
+        g_value_set_object (value, priv->relative_widget);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static GtkWidget *
+wrap_child_if_needed (GtkWidget *widget)
+{
+  GtkWidget *child;
+
+  if (GTK_IS_OVERLAY_CHILD (widget))
+    return widget;
+
+  child = GTK_WIDGET (gtk_overlay_child_new (widget));
+  gtk_widget_show (child);
+
+  g_signal_connect_swapped (widget,
+                            "destroy",
+                            G_CALLBACK (gtk_widget_destroy),
+                            child);
+
+  return child;
+}
+
+static void
+gtk_overlay_set_property (GObject      *object,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (object);
+  GtkOverlayPrivate *priv = overlay->priv;
+
+  switch (prop_id)
+    {
+      case PROP_MAIN_WIDGET:
+        priv->main_widget = g_value_get_object (value);
+
+        add_toplevel_widget (overlay,
+                             NULL,
+                             priv->main_widget);
+        break;
+
+      case PROP_RELATIVE_WIDGET:
+        priv->relative_widget = g_value_get_object (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gtk_overlay_realize (GtkWidget *widget)
+{
+  GtkAllocation allocation;
+  GdkWindow *window;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GtkStyleContext *context;
+
+  gtk_widget_set_realized (widget, TRUE);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                           &attributes, attributes_mask);
+  gtk_widget_set_window (widget, window);
+  gdk_window_set_user_data (window, widget);
+
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
+  gtk_style_context_set_background (context, window);
+}
+
+static void
+gtk_overlay_get_preferred_width (GtkWidget *widget,
+                                 gint      *minimum,
+                                 gint      *natural)
+{
+  GtkOverlayPrivate *priv = GTK_OVERLAY (widget)->priv;
+
+  *minimum = 0;
+  *natural = 0;
+
+  if (priv->main_widget)
+    gtk_widget_get_preferred_width (priv->main_widget, minimum, natural);
+}
+
+static void
+gtk_overlay_get_preferred_height (GtkWidget *widget,
+                                  gint      *minimum,
+                                  gint      *natural)
+{
+  GtkOverlayPrivate *priv = GTK_OVERLAY (widget)->priv;
+
+  *minimum = 0;
+  *natural = 0;
+
+  if (priv->main_widget)
+    gtk_widget_get_preferred_height (priv->main_widget, minimum, natural);
+}
+
+static void
+gtk_overlay_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (widget);
+  GtkOverlayPrivate *priv = overlay->priv;
+  GtkAllocation main_alloc;
+  GSList *l;
+
+  GTK_WIDGET_CLASS (gtk_overlay_parent_class)->size_allocate (widget, allocation);
+
+  /* main widget allocation */
+  main_alloc.x = 0;
+  main_alloc.y = 0;
+  main_alloc.width = allocation->width;
+  main_alloc.height = allocation->height;
+
+  gtk_widget_size_allocate (overlay->priv->main_widget, &main_alloc);
+
+  /* if a relative widget exists place the floating widgets in relation to it */
+  if (priv->relative_widget)
+    gtk_widget_get_allocation (priv->relative_widget, &main_alloc);
+
+  for (l = priv->children; l != NULL; l = g_slist_next (l))
+    {
+      ChildContainer *container = l->data;
+      GtkWidget *child;
+      GtkRequisition req;
+      GtkAllocation alloc;
+      guint offset;
+      GtkAlign halign, valign;
+
+      child = child_container_get_child (container);
+
+      if (child == priv->main_widget)
+        continue;
+
+      gtk_widget_get_preferred_size (child, NULL, &req);
+      offset = gtk_overlay_child_get_offset (GTK_OVERLAY_CHILD (child));
+      halign = gtk_widget_get_halign (child);
+      valign = gtk_widget_get_valign (child);
+
+      /* FIXME: Add all the positions here */
+      switch (halign)
+        {
+          /* The gravity is treated as position and not as a gravity */
+          case GTK_ALIGN_END:
+            switch (valign)
+              {
+                case GTK_ALIGN_START:
+                  alloc.x = MAX (main_alloc.x, main_alloc.width - req.width - (gint) offset);
+                  alloc.y = 0;
+                  break;
+
+                case GTK_ALIGN_END:
+                  alloc.x = MAX (main_alloc.x, main_alloc.width - req.width - (gint) offset);
+                  alloc.y = MAX (main_alloc.y, main_alloc.height - req.height);
+                  break;
+
+                default:
+                  break;
+              }
+              break;
+
+          case GTK_ALIGN_START:
+            switch (valign)
+              {
+                case GTK_ALIGN_START:
+                  alloc.x = offset;
+                  alloc.y = 0;
+                  break;
+
+                case GTK_ALIGN_END:
+                  alloc.x = offset;
+                  alloc.y = MAX (main_alloc.y, main_alloc.height - req.height);
+                  break;
+
+                default:
+                  break;
+              }
+              break;
+
+          default:
+            alloc.x = 0;
+            alloc.y = 0;
+        }
+
+      alloc.width = MIN (main_alloc.width, req.width);
+      alloc.height = MIN (main_alloc.height, req.height);
+
+      gtk_widget_size_allocate (child, &alloc);
+    }
+}
+
+static GtkOverlayChild *
+get_overlay_child (GtkOverlay *overlay,
+                   GtkWidget  *widget)
+{
+  GSList *l;
+
+  for (l = overlay->priv->children; l != NULL; l = g_slist_next (l))
+    {
+      ChildContainer *container = l->data;
+
+      if (container->original == widget &&
+          GTK_IS_OVERLAY_CHILD (container->child))
+        {
+          return GTK_OVERLAY_CHILD (container->child);
+        }
+    }
+
+  return NULL;
+}
+
+static void
+overlay_add (GtkContainer *overlay,
+             GtkWidget    *widget)
+{
+  GtkOverlayChild *child;
+
+  /* check that the widget is not added yet */
+  child = get_overlay_child (GTK_OVERLAY (overlay), widget);
+
+  if (child == NULL)
+    add_toplevel_widget (GTK_OVERLAY (overlay),
+                         wrap_child_if_needed (widget),
+                         widget);
+}
+
+static void
+gtk_overlay_remove (GtkContainer *overlay,
+                    GtkWidget    *widget)
+{
+  GtkOverlayPrivate *priv = GTK_OVERLAY (overlay)->priv;
+  GSList *l;
+
+  for (l = priv->children; l != NULL; l = g_slist_next (l))
+    {
+      ChildContainer *container = l->data;
+      GtkWidget *original = container->original;
+
+      if (original == widget)
+        {
+          gtk_widget_unparent (widget);
+
+          if (container->child != NULL &&
+              original != container->child)
+            {
+              g_signal_handlers_disconnect_by_func (original,
+                                                    gtk_widget_destroy,
+                                                    container->child);
+
+              gtk_widget_destroy (container->child);
+            }
+
+          child_container_free (container);
+          priv->children = g_slist_delete_link (priv->children,
+                                                l);
+
+          break;
+        }
+    }
+}
+
+static void
+gtk_overlay_forall (GtkContainer *overlay,
+                    gboolean      include_internals,
+                    GtkCallback   callback,
+                    gpointer      callback_data)
+{
+  GtkOverlayPrivate *priv = GTK_OVERLAY (overlay)->priv;
+  GSList *children;
+
+  children = priv->children;
+
+  while (children)
+    {
+      ChildContainer *container = children->data;
+      children = children->next;
+      GtkWidget *child;
+
+      child = child_container_get_child (container);
+
+      (* callback) (child, callback_data);
+    }
+}
+
+static GType
+gtk_overlay_child_type (GtkContainer *overlay)
+{
+  return GTK_TYPE_WIDGET;
+}
+
+static void
+gtk_overlay_class_init (GtkOverlayClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+  object_class->dispose = gtk_overlay_dispose;
+  object_class->get_property = gtk_overlay_get_property;
+  object_class->set_property = gtk_overlay_set_property;
+
+  widget_class->realize = gtk_overlay_realize;
+  widget_class->get_preferred_width = gtk_overlay_get_preferred_width;
+  widget_class->get_preferred_height = gtk_overlay_get_preferred_height;
+  widget_class->size_allocate = gtk_overlay_size_allocate;
+
+  container_class->add = overlay_add;
+  container_class->remove = gtk_overlay_remove;
+  container_class->forall = gtk_overlay_forall;
+  container_class->child_type = gtk_overlay_child_type;
+
+  g_object_class_install_property (object_class, PROP_MAIN_WIDGET,
+                                   g_param_spec_object ("main-widget",
+                                                        "Main Widget",
+                                                        "The Main Widget",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_RELATIVE_WIDGET,
+                                   g_param_spec_object ("relative-widget",
+                                                        "Relative Widget",
+                                                        "Widget on which the floating widgets are placed",
+                                                        GTK_TYPE_WIDGET,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_STRINGS));
+
+  g_type_class_add_private (object_class, sizeof (GtkOverlayPrivate));
+}
+
+static void
+gtk_overlay_init (GtkOverlay *overlay)
+{
+  overlay->priv = G_TYPE_INSTANCE_GET_PRIVATE (overlay, GTK_TYPE_OVERLAY, GtkOverlayPrivate);
+
+  gtk_widget_set_app_paintable (GTK_WIDGET (overlay), TRUE);
+}
+
+/**
+ * gtk_overlay_new:
+ * @main_widget: a #GtkWidget
+ * @relative_widget: (allow-none): a #Gtkwidget
+ *
+ * Creates a new #GtkOverlay. If @relative_widget is not %NULL the floating
+ * widgets will be placed in relation to it, if not @main_widget will be use
+ * for this purpose.
+ *
+ * Returns: a new #GtkOverlay object.
+ */
+GtkWidget *
+gtk_overlay_new (GtkWidget *main_widget,
+                 GtkWidget *relative_widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (main_widget), NULL);
+
+  return GTK_WIDGET (g_object_new (GTK_TYPE_OVERLAY,
+                                   "main-widget", main_widget,
+                                   "relative-widget", relative_widget,
+                                   NULL));
+}
+
+/**
+ * gtk_overlay_add:
+ * @overlay: a #GtkOverlay
+ * @widget: a #GtkWidget to be added to the container
+ * @offset: offset for @widget
+ *
+ * Adds @widget to @overlay in a specific position.
+ */
+void
+gtk_overlay_add (GtkOverlay             *overlay,
+                 GtkWidget              *widget,
+                 guint                   offset)
+{
+  GtkOverlayChild *child;
+
+  g_return_if_fail (GTK_IS_OVERLAY (overlay));
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  gtk_container_add (GTK_CONTAINER (overlay), widget);
+
+  /* NOTE: can we improve this without exposing overlay child? */
+  child = get_overlay_child (overlay, widget);
+  g_assert (child != NULL);
+
+  gtk_overlay_child_set_offset (child, offset);
+}
diff --git a/gtk/gtkoverlay.h b/gtk/gtkoverlay.h
new file mode 100644
index 0000000..ead6cd7
--- /dev/null
+++ b/gtk/gtkoverlay.h
@@ -0,0 +1,81 @@
+/*
+ * gtkoverlay.h
+ * This file is part of gtk
+ *
+ * Copyright (C) 2011 - Ignacio Casal Quinteiro
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_OVERLAY_H__
+#define __GTK_OVERLAY_H__
+
+#include <gtk/gtkcontainer.h>
+#include "gtkoverlaychild.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_OVERLAY             (gtk_overlay_get_type ())
+#define GTK_OVERLAY(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OVERLAY, GtkOverlay))
+#define GTK_OVERLAY_CONST(obj)       (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OVERLAY, GtkOverlay const))
+#define GTK_OVERLAY_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_OVERLAY, GtkOverlayClass))
+#define GTK_IS_OVERLAY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_OVERLAY))
+#define GTK_IS_OVERLAY_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OVERLAY))
+#define GTK_OVERLAY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_OVERLAY, GtkOverlayClass))
+
+typedef struct _GtkOverlay         GtkOverlay;
+typedef struct _GtkOverlayClass    GtkOverlayClass;
+typedef struct _GtkOverlayPrivate  GtkOverlayPrivate;
+
+struct _GtkOverlay
+{
+  GtkContainer parent;
+
+  GtkOverlayPrivate *priv;
+};
+
+struct _GtkOverlayClass
+{
+  GtkContainerClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+  void (*_gtk_reserved8) (void);
+  void (*_gtk_reserved9) (void);
+};
+
+GType       gtk_overlay_get_type    (void) G_GNUC_CONST;
+
+GtkWidget  *gtk_overlay_new         (GtkWidget *main_widget,
+                                     GtkWidget *relative_widget);
+
+void        gtk_overlay_add         (GtkOverlay             *overlay,
+                                     GtkWidget              *widget,
+                                     guint                   offset);
+
+G_END_DECLS
+
+#endif /* __GTK_OVERLAY_H__ */
diff --git a/gtk/gtkoverlaychild.c b/gtk/gtkoverlaychild.c
new file mode 100644
index 0000000..1b8c71d
--- /dev/null
+++ b/gtk/gtkoverlaychild.c
@@ -0,0 +1,307 @@
+/*
+ * gtk-overlay-child.c
+ * This file is part of gtk
+ *
+ * Copyright (C) 2011 - Ignacio Casal Quinteiro
+ *
+ * gtk is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * gtk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "gtkoverlaychild.h"
+
+struct _GtkOverlayChildPrivate
+{
+	GBinding                 *binding;
+	guint                     offset;
+};
+
+enum
+{
+	PROP_0,
+	PROP_WIDGET,
+	PROP_OFFSET
+};
+
+G_DEFINE_TYPE (GtkOverlayChild, gtk_overlay_child, GTK_TYPE_BIN)
+
+static void
+gtk_overlay_child_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+	GtkOverlayChild *child = GTK_OVERLAY_CHILD (object);
+
+	switch (prop_id)
+	{
+		case PROP_WIDGET:
+			g_value_set_object (value, gtk_bin_get_child (GTK_BIN (child)));
+			break;
+		case PROP_OFFSET:
+			g_value_set_uint (value, child->priv->offset);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gtk_overlay_child_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+	GtkOverlayChild *child = GTK_OVERLAY_CHILD (object);
+
+	switch (prop_id)
+	{
+		case PROP_WIDGET:
+			gtk_container_add (GTK_CONTAINER (child),
+			                   g_value_get_object (value));
+			break;
+		case PROP_OFFSET:
+			child->priv->offset = g_value_get_uint (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gtk_overlay_child_realize (GtkWidget *widget)
+{
+	GdkWindowAttr attributes;
+	GdkWindow *parent_window;
+	GdkWindow *window;
+	GtkStyleContext *context;
+
+	gtk_widget_set_realized (widget, TRUE);
+
+	parent_window = gtk_widget_get_parent_window (widget);
+	context = gtk_widget_get_style_context (widget);
+
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.wclass = GDK_INPUT_OUTPUT;
+	attributes.event_mask = GDK_EXPOSURE_MASK;
+	attributes.width = 0;
+	attributes.height = 0;
+
+	window = gdk_window_new (parent_window, &attributes, 0);
+	gdk_window_set_user_data (window, widget);
+	gtk_widget_set_window (widget, window);
+	gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
+	gtk_style_context_set_background (context, window);
+}
+
+static void
+gtk_overlay_child_get_size (GtkWidget     *widget,
+                              GtkOrientation orientation,
+                              gint          *minimum,
+                              gint          *natural)
+{
+	GtkOverlayChild *overlay_child = GTK_OVERLAY_CHILD (widget);
+	GtkWidget *child;
+	gint child_min = 0, child_nat = 0;
+
+	child = gtk_bin_get_child (GTK_BIN (overlay_child));
+
+	if (child != NULL)
+	{
+		if (orientation == GTK_ORIENTATION_HORIZONTAL)
+		{
+			gtk_widget_get_preferred_width (child,
+			                                &child_min, &child_nat);
+		}
+		else
+		{
+			gtk_widget_get_preferred_height (child,
+			                                 &child_min, &child_nat);
+		}
+	}
+
+	*minimum = child_min;
+	*natural = child_nat;
+}
+
+static void
+gtk_overlay_child_get_preferred_width (GtkWidget *widget,
+                                         gint      *minimum,
+                                         gint      *natural)
+{
+	gtk_overlay_child_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum, natural);
+}
+
+static void
+gtk_overlay_child_get_preferred_height (GtkWidget *widget,
+                                          gint      *minimum,
+                                          gint      *natural)
+{
+	gtk_overlay_child_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum, natural);
+}
+
+static void
+gtk_overlay_child_size_allocate (GtkWidget     *widget,
+                                   GtkAllocation *allocation)
+{
+	GtkOverlayChild *overlay_child = GTK_OVERLAY_CHILD (widget);
+	GtkWidget *child;
+	GtkAllocation tmp;
+
+	tmp.width = allocation->width;
+	tmp.height = allocation->height;
+	tmp.x = tmp.y = 0;
+
+	GTK_WIDGET_CLASS (gtk_overlay_child_parent_class)->size_allocate (widget, allocation);
+
+	child = gtk_bin_get_child (GTK_BIN (overlay_child));
+
+	if (child != NULL)
+	{
+		gtk_widget_size_allocate (child, &tmp);
+	}
+}
+
+static void
+gtk_overlay_child_add (GtkContainer *container,
+                         GtkWidget    *widget)
+{
+	GtkOverlayChild *overlay_child = GTK_OVERLAY_CHILD (container);
+
+	overlay_child->priv->binding = g_object_bind_property (G_OBJECT (widget), "visible",
+							       G_OBJECT (container), "visible",
+							       G_BINDING_BIDIRECTIONAL);
+
+	GTK_CONTAINER_CLASS (gtk_overlay_child_parent_class)->add (container, widget);
+}
+
+static void
+gtk_overlay_child_remove (GtkContainer *container,
+                            GtkWidget    *widget)
+{
+	GtkOverlayChild *child = GTK_OVERLAY_CHILD (container);
+
+	g_object_unref (child->priv->binding);
+
+	GTK_CONTAINER_CLASS (gtk_overlay_child_parent_class)->remove (container, widget);
+}
+
+static void
+gtk_overlay_child_class_init (GtkOverlayChildClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+	GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+	
+	object_class->get_property = gtk_overlay_child_get_property;
+	object_class->set_property = gtk_overlay_child_set_property;
+
+	widget_class->realize = gtk_overlay_child_realize;
+	widget_class->get_preferred_width = gtk_overlay_child_get_preferred_width;
+	widget_class->get_preferred_height = gtk_overlay_child_get_preferred_height;
+	widget_class->size_allocate = gtk_overlay_child_size_allocate;
+
+	container_class->add = gtk_overlay_child_add;
+	container_class->remove = gtk_overlay_child_remove;
+
+	g_object_class_install_property (object_class, PROP_WIDGET,
+	                                 g_param_spec_object ("widget",
+	                                                      "Widget",
+	                                                      "The Widget",
+	                                                      GTK_TYPE_WIDGET,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_CONSTRUCT_ONLY |
+	                                                      G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_OFFSET,
+	                                 g_param_spec_uint ("offset",
+	                                                    "Offset",
+	                                                    "The Widget Offset",
+	                                                    0,
+	                                                    G_MAXUINT,
+	                                                    0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	g_type_class_add_private (object_class, sizeof (GtkOverlayChildPrivate));
+}
+
+static void
+gtk_overlay_child_init (GtkOverlayChild *child)
+{
+	child->priv = G_TYPE_INSTANCE_GET_PRIVATE (child,
+	                                           GTK_TYPE_OVERLAY_CHILD,
+	                                           GtkOverlayChildPrivate);
+
+	gtk_widget_set_has_window (GTK_WIDGET (child), TRUE);
+}
+
+/**
+ * gtk_overlay_child_new:
+ * @widget: a #GtkWidget
+ *
+ * Creates a new #GtkOverlayChild object
+ *
+ * Returns: a new #GtkOverlayChild object
+ */
+GtkOverlayChild *
+gtk_overlay_child_new (GtkWidget *widget)
+{
+	return g_object_new (GTK_TYPE_OVERLAY_CHILD,
+	                     "widget", widget,
+	                     NULL);
+}
+
+/**
+ * gtk_overlay_child_get_offset:
+ * @child: a #GtkOverlayChild
+ *
+ * Gets the offset for @child. The offset is usually used by #GtkOverlay
+ * to not place the widget directly in the border of the container
+ *
+ * Returns: the offset for @child
+ */
+guint
+gtk_overlay_child_get_offset (GtkOverlayChild *child)
+{
+	g_return_val_if_fail (GTK_IS_OVERLAY_CHILD (child), 0);
+
+	return child->priv->offset;
+}
+
+/**
+ * gtk_overlay_child_set_offset:
+ * @child: a #GtkOverlayChild
+ * @offset: the offset for @child
+ *
+ * Sets the new offset for @child
+ */
+void
+gtk_overlay_child_set_offset (GtkOverlayChild *child,
+                                guint              offset)
+{
+	g_return_if_fail (GTK_IS_OVERLAY_CHILD (child));
+
+	if (child->priv->offset != offset)
+	{
+		child->priv->offset = offset;
+
+		g_object_notify (G_OBJECT (child), "offset");
+	}
+}
+
+/* ex:set ts=8 noet: */
diff --git a/gtk/gtkoverlaychild.h b/gtk/gtkoverlaychild.h
new file mode 100644
index 0000000..9894ec8
--- /dev/null
+++ b/gtk/gtkoverlaychild.h
@@ -0,0 +1,70 @@
+/*
+ * gtk-overlay-child.h
+ * This file is part of gtk
+ *
+ * Copyright (C) 2011 - Ignacio Casal Quinteiro
+ *
+ * gtk is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * gtk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GTK_OVERLAY_CHILD_H__
+#define __GTK_OVERLAY_CHILD_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_OVERLAY_CHILD		(gtk_overlay_child_get_type ())
+#define GTK_OVERLAY_CHILD(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OVERLAY_CHILD, GtkOverlayChild))
+#define GTK_OVERLAY_CHILD_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OVERLAY_CHILD, GtkOverlayChild const))
+#define GTK_OVERLAY_CHILD_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_OVERLAY_CHILD, GtkOverlayChildClass))
+#define GTK_IS_OVERLAY_CHILD(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_OVERLAY_CHILD))
+#define GTK_IS_OVERLAY_CHILD_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OVERLAY_CHILD))
+#define GTK_OVERLAY_CHILD_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_OVERLAY_CHILD, GtkOverlayChildClass))
+
+typedef struct _GtkOverlayChild		GtkOverlayChild;
+typedef struct _GtkOverlayChildClass		GtkOverlayChildClass;
+typedef struct _GtkOverlayChildPrivate	GtkOverlayChildPrivate;
+
+struct _GtkOverlayChild
+{
+	GtkBin parent;
+
+	GtkOverlayChildPrivate *priv;
+};
+
+struct _GtkOverlayChildClass
+{
+	GtkBinClass parent_class;
+};
+
+GType                     gtk_overlay_child_get_type     (void) G_GNUC_CONST;
+
+GtkOverlayChild        *gtk_overlay_child_new          (GtkWidget *widget);
+
+guint                     gtk_overlay_child_get_offset   (GtkOverlayChild *child);
+
+void                      gtk_overlay_child_set_offset   (GtkOverlayChild *child,
+                                                            guint              offset);
+
+gboolean                  gtk_overlay_child_get_fixed    (GtkOverlayChild *child);
+
+void                      gtk_overlay_child_set_fixed    (GtkOverlayChild *child,
+                                                            gboolean           fixed);
+
+G_END_DECLS
+
+#endif /* __GTK_OVERLAY_CHILD_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]