/*
* gedit-overlay-child.c
* This file is part of gedit
*
* Copyright (C) 2011 - Ignacio Casal Quinteiro
*
* gedit 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.
*
* gedit 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 "gedit-overlay-child.h"
struct _GeditOverlayChildPrivate
{
GBinding *binding;
GeditOverlayChildPosition position;
guint offset;
};
enum
{
PROP_0,
PROP_WIDGET,
PROP_POSITION,
PROP_OFFSET
};
G_DEFINE_TYPE (GeditOverlayChild, gedit_overlay_child, GTK_TYPE_BIN)
static void
gedit_overlay_child_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GeditOverlayChild *child = GEDIT_OVERLAY_CHILD (object);
switch (prop_id)
{
case PROP_WIDGET:
g_value_set_object (value, gtk_bin_get_child (GTK_BIN (child)));
break;
case PROP_POSITION:
g_value_set_uint (value, child->priv->position);
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
gedit_overlay_child_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GeditOverlayChild *child = GEDIT_OVERLAY_CHILD (object);
switch (prop_id)
{
case PROP_WIDGET:
gtk_container_add (GTK_CONTAINER (child),
g_value_get_object (value));
break;
case PROP_POSITION:
child->priv->position = g_value_get_uint (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
gedit_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
gedit_overlay_child_get_size (GtkWidget *widget,
GtkOrientation orientation,
gint *minimum,
gint *natural)
{
GeditOverlayChild *overlay_child = GEDIT_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
gedit_overlay_child_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gedit_overlay_child_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum, natural);
}
static void
gedit_overlay_child_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
gedit_overlay_child_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum, natural);
}
static void
gedit_overlay_child_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GeditOverlayChild *overlay_child = GEDIT_OVERLAY_CHILD (widget);
GtkWidget *child;
GtkAllocation tmp;
tmp.width = allocation->width;
tmp.height = allocation->height;
tmp.x = tmp.y = 0;
GTK_WIDGET_CLASS (gedit_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
gedit_overlay_child_add (GtkContainer *container,
GtkWidget *widget)
{
GeditOverlayChild *overlay_child = GEDIT_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 (gedit_overlay_child_parent_class)->add (container, widget);
}
static void
gedit_overlay_child_remove (GtkContainer *container,
GtkWidget *widget)
{
GeditOverlayChild *child = GEDIT_OVERLAY_CHILD (container);
g_object_unref (child->priv->binding);
GTK_CONTAINER_CLASS (gedit_overlay_child_parent_class)->remove (container, widget);
}
static void
gedit_overlay_child_class_init (GeditOverlayChildClass *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 = gedit_overlay_child_get_property;
object_class->set_property = gedit_overlay_child_set_property;
widget_class->realize = gedit_overlay_child_realize;
widget_class->get_preferred_width = gedit_overlay_child_get_preferred_width;
widget_class->get_preferred_height = gedit_overlay_child_get_preferred_height;
widget_class->size_allocate = gedit_overlay_child_size_allocate;
container_class->add = gedit_overlay_child_add;
container_class->remove = gedit_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_POSITION,
g_param_spec_uint ("position",
"Position",
"The Widget Position",
1, GEDIT_OVERLAY_CHILD_POSITION_STATIC,
GEDIT_OVERLAY_CHILD_POSITION_STATIC,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
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 (GeditOverlayChildPrivate));
}
static void
gedit_overlay_child_init (GeditOverlayChild *child)
{
child->priv = G_TYPE_INSTANCE_GET_PRIVATE (child,
GEDIT_TYPE_OVERLAY_CHILD,
GeditOverlayChildPrivate);
gtk_widget_set_has_window (GTK_WIDGET (child), TRUE);
}
/**
* gedit_overlay_child_new:
* @widget: a #GtkWidget
*
* Creates a new #GeditOverlayChild object
*
* Returns: a new #GeditOverlayChild object
*/
GeditOverlayChild *
gedit_overlay_child_new (GtkWidget *widget)
{
return g_object_new (GEDIT_TYPE_OVERLAY_CHILD,
"widget", widget,
NULL);
}
/**
* gedit_overlay_child_get_position:
* @child: a #GeditOverlayChild
*
* Gets the position of the widget
*
* Returns: wether the child should be placed in a #GeditOverlay
*/
GeditOverlayChildPosition
gedit_overlay_child_get_position (GeditOverlayChild *child)
{
g_return_val_if_fail (GEDIT_IS_OVERLAY_CHILD (child), GEDIT_OVERLAY_CHILD_POSITION_STATIC);
return child->priv->position;
}
/**
* gedit_overlay_child_set_position:
* @child: a #GeditOverlayChild
* @position: a #GeditOverlayChildPosition
*
* Sets the new position for @child
*/
void
gedit_overlay_child_set_position (GeditOverlayChild *child,
GeditOverlayChildPosition position)
{
g_return_if_fail (GEDIT_IS_OVERLAY_CHILD (child));
if (child->priv->position != position)
{
child->priv->position = position;
g_object_notify (G_OBJECT (child), "position");
}
}
/**
* gedit_overlay_child_get_offset:
* @child: a #GeditOverlayChild
*
* Gets the offset for @child. The offset is usually used by #GeditOverlay
* to not place the widget directly in the border of the container
*
* Returns: the offset for @child
*/
guint
gedit_overlay_child_get_offset (GeditOverlayChild *child)
{
g_return_val_if_fail (GEDIT_IS_OVERLAY_CHILD (child), 0);
return child->priv->offset;
}
/**
* gedit_overlay_child_set_offset:
* @child: a #GeditOverlayChild
* @offset: the offset for @child
*
* Sets the new offset for @child
*/
void
gedit_overlay_child_set_offset (GeditOverlayChild *child,
guint offset)
{
g_return_if_fail (GEDIT_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: */