/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */ /* * gcal-floating-container.c * Copyright (C) 2012 Erick Pérez Castellanos * * gnome-calendar is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * gnome-calendar 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "gcal-floating-container.h" struct _GcalFloatingContainerPrivate { guint border; }; static void gcal_floating_container_get_preferred_width (GtkWidget *widget, gint *minimum_width, gint *natural_width); static void gcal_floating_container_get_preferred_height_for_width (GtkWidget *widget, gint width, gint *minimum_height, gint *natural_height); static void gcal_floating_container_get_preferred_height (GtkWidget *widget, gint *minimum_height, gint *natural_height); static void gcal_floating_container_get_preferred_width_for_height (GtkWidget *widget, gint height, gint *minimum_width, gint *natural_width); static void gcal_floating_container_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gboolean gcal_floating_container_draw (GtkWidget *widget, cairo_t *cr); static void gcal_floating_container_realize (GtkWidget *widget); static void gcal_floating_container_style_updated (GtkWidget *widget); static void gcal_floating_container_add (GtkContainer *container, GtkWidget *child); static void gcal_floating_container_get_padding_and_border (GtkWidget *widget, GtkBorder *border); G_DEFINE_TYPE(GcalFloatingContainer, gcal_floating_container, GTK_TYPE_BIN) static void gcal_floating_container_class_init (GcalFloatingContainerClass *klass) { GtkWidgetClass* widget_class; GtkContainerClass *container_class; widget_class = GTK_WIDGET_CLASS (klass); container_class = GTK_CONTAINER_CLASS (klass); widget_class->get_preferred_width = gcal_floating_container_get_preferred_width; widget_class->get_preferred_height_for_width = gcal_floating_container_get_preferred_height_for_width; widget_class->get_preferred_height = gcal_floating_container_get_preferred_height; widget_class->get_preferred_width_for_height = gcal_floating_container_get_preferred_width_for_height; widget_class->size_allocate = gcal_floating_container_size_allocate; widget_class->draw = gcal_floating_container_draw; widget_class->realize = gcal_floating_container_realize; widget_class->style_updated = gcal_floating_container_style_updated; container_class->add = gcal_floating_container_add; g_type_class_add_private ((gpointer)klass, sizeof (GcalFloatingContainerPrivate)); } static void gcal_floating_container_init (GcalFloatingContainer *self) { gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCAL_TYPE_FLOATING_CONTAINER, GcalFloatingContainerPrivate); } static void gcal_floating_container_get_preferred_width (GtkWidget *widget, gint *minimum_width, gint *natural_width) { gint child_min, child_nat; GtkWidget *child; GtkBorder padding; gint minimum, natural; gcal_floating_container_get_padding_and_border (widget, &padding); minimum = 0; natural = 0; child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) { gtk_widget_get_preferred_width (child, &child_min, &child_nat); minimum += child_min; natural += child_nat; } minimum += padding.left + padding.right; natural += padding.left + padding.right; if (minimum_width) *minimum_width = minimum; if (natural_width) *natural_width = natural; } static void gcal_floating_container_get_preferred_height_for_width (GtkWidget *widget, gint width, gint *minimum_height, gint *natural_height) { gint child_min, child_nat, child_width; GtkWidget *child; GtkBorder padding; gint minimum; gint natural; gcal_floating_container_get_padding_and_border (widget, &padding); minimum = 0; natural = 0; child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) { child_width = width - padding.left - padding.top; gtk_widget_get_preferred_height_for_width (child, child_width, &child_min, &child_nat); minimum = MAX (minimum, child_min); natural = MAX (natural, child_nat); } minimum += padding.top + padding.top; natural += padding.top + padding.top; if (minimum_height) *minimum_height = minimum; if (natural_height) *natural_height = natural; } static void gcal_floating_container_get_preferred_height (GtkWidget *widget, gint *minimum_height, gint *natural_height) { gint child_min, child_nat; GtkWidget *child; GtkBorder padding; gint minimum; gint natural; gcal_floating_container_get_padding_and_border (widget, &padding); minimum = 0; natural = 0; child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) { gtk_widget_get_preferred_height (child, &child_min, &child_nat); minimum = child_min; natural = child_nat; } minimum += padding.top + padding.top; natural += padding.top + padding.top; if (minimum_height) *minimum_height = minimum; if (natural_height) *natural_height = natural; } static void gcal_floating_container_get_preferred_width_for_height (GtkWidget *widget, gint height, gint *minimum_width, gint *natural_width) { gint child_min, child_nat, child_height; GtkWidget *child; GtkBorder padding; gint minimum; gint natural; gcal_floating_container_get_padding_and_border (widget, &padding); minimum = 0; natural = 0; child_height = height - padding.top - padding.bottom; child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) { gtk_widget_get_preferred_width_for_height (child, child_height, &child_min, &child_nat); minimum += child_min; natural += child_nat; } minimum += padding.left + padding.right; natural += padding.left + padding.right; if (minimum_width) *minimum_width = minimum; if (natural_width) *natural_width = natural; } static void gcal_floating_container_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkAllocation child_allocation; GtkBorder padding; GtkWidget *child; gtk_widget_set_allocation (widget, allocation); gcal_floating_container_get_padding_and_border (widget, &padding); if (gtk_widget_get_realized (widget)) { gdk_window_move_resize (gtk_widget_get_window (widget), allocation->x, allocation->y, allocation->width, allocation->height); } child_allocation.x = padding.left; child_allocation.y = padding.top; child_allocation.height = MAX (1, allocation->height - padding.top - padding.bottom); child_allocation.width = MAX (1, allocation->width - padding.left - padding.right); child = gtk_bin_get_child (GTK_BIN (widget)); if (child && gtk_widget_get_visible (child)) gtk_widget_size_allocate (child, &child_allocation); } static gboolean gcal_floating_container_draw (GtkWidget *widget, cairo_t *cr) { GtkStyleContext *context; guint border_width; context = gtk_widget_get_style_context (widget); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); gtk_render_background (context, cr, border_width, border_width, gtk_widget_get_allocated_width (widget) - 2 * border_width, gtk_widget_get_allocated_height (widget) - 2 * border_width); gtk_render_frame (context, cr, border_width, border_width, gtk_widget_get_allocated_width (widget) - 2 * border_width, gtk_widget_get_allocated_height (widget) - 2 * border_width); if (GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->draw != NULL) GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->draw (widget, cr); return FALSE; } static void gcal_floating_container_realize (GtkWidget *widget) { GdkWindow *window; GtkWidget *child; gtk_widget_set_realized (widget, TRUE); window = gtk_widget_get_parent_window (widget); gtk_widget_set_window (widget, window); g_object_ref (window); child = gtk_bin_get_child (GTK_BIN (widget)); if (child) gtk_widget_set_parent_window (child, window); } static void gcal_floating_container_style_updated (GtkWidget *widget) { GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->style_updated (widget); if (gtk_widget_get_realized (widget)) gtk_style_context_set_background (gtk_widget_get_style_context (widget), gtk_widget_get_window (widget)); } static void gcal_floating_container_add (GtkContainer *container, GtkWidget *child) { g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == NULL); GTK_CONTAINER_CLASS (gcal_floating_container_parent_class)->add (container, child); } static void gcal_floating_container_get_padding_and_border (GtkWidget *widget, GtkBorder *border) { GtkStyleContext *context; GtkStateFlags state; GtkBorder tmp; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_style_context_get_padding (context, state, border); gtk_style_context_get_border (context, state, &tmp); border->top += tmp.top; border->right += tmp.right; border->bottom += tmp.bottom; border->left += tmp.left; } GtkWidget* gcal_floating_container_new (void) { return g_object_new (GCAL_TYPE_FLOATING_CONTAINER, NULL); }