X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkoverlay.c;h=de80637d071cf811365fc122ada5c42033eaae26;hb=HEAD;hp=b964fff53a0048067b7252c0f5ab6dc1b9afe973;hpb=003d80dbea8ce71d900a6f93b6bb29e5c5ada457;p=~andy%2Fgtk diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c index b964fff53..de80637d0 100644 --- a/gtk/gtkoverlay.c +++ b/gtk/gtkoverlay.c @@ -15,9 +15,7 @@ * 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. + * License along with this library. If not, see . */ #include "config.h" @@ -37,8 +35,8 @@ * * GtkOverlay is a container which contains a single main child, on top * of which it can place overlay widgets. The - * position of each overlay widget is determined by its #GtkWidget::halign - * and #GtkWidget::valign properties. E.g. a widget with both alignments + * position of each overlay widget is determined by its #GtkWidget:halign + * and #GtkWidget:valign properties. E.g. a widget with both alignments * set to %GTK_ALIGN_START will be placed at the top left corner of the * main widget, whereas an overlay with halign set to %GTK_ALIGN_CENTER * and valign set to %GTK_ALIGN_END will be placed a the bottom edge of @@ -107,7 +105,7 @@ gtk_overlay_create_child_window (GtkOverlay *overlay, window = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (window, overlay); + gtk_widget_register_window (widget, window); gtk_style_context_set_background (gtk_widget_get_style_context (widget), window); gtk_widget_set_parent_window (child, window); @@ -115,6 +113,129 @@ gtk_overlay_create_child_window (GtkOverlay *overlay, return window; } +static GtkAlign +effective_align (GtkAlign align, + GtkTextDirection direction) +{ + switch (align) + { + case GTK_ALIGN_START: + return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START; + case GTK_ALIGN_END: + return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END; + default: + return align; + } +} + +static void +gtk_overlay_get_main_widget_allocation (GtkOverlay *overlay, + GtkAllocation *main_alloc_out) +{ + GtkWidget *main_widget; + GtkAllocation main_alloc; + + main_widget = gtk_bin_get_child (GTK_BIN (overlay)); + + /* special-case scrolled windows */ + if (GTK_IS_SCROLLED_WINDOW (main_widget)) + { + GtkWidget *grandchild; + gint x, y; + gboolean res; + + grandchild = gtk_bin_get_child (GTK_BIN (main_widget)); + res = gtk_widget_translate_coordinates (grandchild, main_widget, 0, 0, &x, &y); + + if (res) + { + main_alloc.x = x; + main_alloc.y = y; + } + else + { + main_alloc.x = 0; + main_alloc.y = 0; + } + + main_alloc.width = gtk_widget_get_allocated_width (grandchild); + main_alloc.height = gtk_widget_get_allocated_height (grandchild); + } + else + { + main_alloc.x = 0; + main_alloc.y = 0; + main_alloc.width = gtk_widget_get_allocated_width (main_widget); + main_alloc.height = gtk_widget_get_allocated_height (main_widget); + } + + if (main_alloc_out) + *main_alloc_out = main_alloc; +} + +static void +gtk_overlay_child_update_style_classes (GtkOverlay *overlay, + GtkWidget *child, + GtkAllocation *child_allocation) +{ + GtkAllocation overlay_allocation, main_allocation; + GtkAlign valign, halign; + gboolean is_left, is_right, is_top, is_bottom; + gboolean has_left, has_right, has_top, has_bottom; + GtkStyleContext *context; + + context = gtk_widget_get_style_context (child); + has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT); + has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT); + has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP); + has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM); + + is_left = is_right = is_top = is_bottom = FALSE; + + gtk_overlay_get_main_widget_allocation (overlay, &main_allocation); + gtk_widget_get_allocation (GTK_WIDGET (overlay), &overlay_allocation); + + main_allocation.x += overlay_allocation.x; + main_allocation.y += overlay_allocation.y; + + halign = effective_align (gtk_widget_get_halign (child), + gtk_widget_get_direction (child)); + + if (halign == GTK_ALIGN_START) + is_left = (child_allocation->x == main_allocation.x); + else if (halign == GTK_ALIGN_END) + is_right = (child_allocation->x + child_allocation->width == + main_allocation.x + main_allocation.width); + + valign = gtk_widget_get_valign (child); + + if (valign == GTK_ALIGN_START) + is_top = (child_allocation->y == main_allocation.y); + else if (valign == GTK_ALIGN_END) + is_bottom = (child_allocation->y + child_allocation->height == + main_allocation.y + main_allocation.height); + + if (has_left && !is_left) + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT); + else if (!has_left && is_left) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); + + if (has_right && !is_right) + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT); + else if (!has_right && is_right) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); + + if (has_top && !is_top) + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP); + else if (!has_top && is_top) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP); + + if (has_bottom && !is_bottom) + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM); + else if (!has_bottom && is_bottom) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM); +} + static void gtk_overlay_child_allocate (GtkOverlay *overlay, GtkOverlayChild *child) @@ -165,6 +286,7 @@ gtk_overlay_child_allocate (GtkOverlay *overlay, allocation.x, allocation.y, allocation.width, allocation.height); + gtk_overlay_child_update_style_classes (overlay, child->widget, &allocation); gtk_widget_size_allocate (child->widget, &child_allocation); } @@ -229,56 +351,17 @@ gtk_overlay_size_allocate (GtkWidget *widget, } } -static GtkAlign -effective_align (GtkAlign align, - GtkTextDirection direction) -{ - switch (align) - { - case GTK_ALIGN_START: - return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START; - case GTK_ALIGN_END: - return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END; - default: - return align; - } -} - static gboolean gtk_overlay_get_child_position (GtkOverlay *overlay, GtkWidget *widget, GtkAllocation *alloc) { - GtkWidget *main_widget; GtkAllocation main_alloc; GtkRequisition req; GtkAlign halign; GtkTextDirection direction; - main_widget = gtk_bin_get_child (GTK_BIN (overlay)); - - /* special-case scrolled windows */ - if (GTK_IS_SCROLLED_WINDOW (main_widget)) - { - GtkWidget *grandchild; - gint x, y; - - grandchild = gtk_bin_get_child (GTK_BIN (main_widget)); - gtk_widget_translate_coordinates (grandchild, main_widget, 0, 0, &x, &y); - - main_alloc.x = x; - main_alloc.y = y; - main_alloc.width = gtk_widget_get_allocated_width (grandchild); - main_alloc.height = gtk_widget_get_allocated_height (grandchild); - } - else - { - main_alloc.x = 0; - main_alloc.y = 0; - main_alloc.width = gtk_widget_get_allocated_width (main_widget); - main_alloc.height = gtk_widget_get_allocated_height (main_widget); - } - + gtk_overlay_get_main_widget_allocation (overlay, &main_alloc); gtk_widget_get_preferred_size (widget, NULL, &req); alloc->x = main_alloc.x; @@ -340,7 +423,10 @@ gtk_overlay_realize (GtkWidget *widget) child = children->data; if (child->window == NULL) - child->window = gtk_overlay_create_child_window (overlay, child->widget); + { + child->window = gtk_overlay_create_child_window (overlay, child->widget); + gtk_overlay_child_allocate (overlay, child); + } } } @@ -357,7 +443,7 @@ gtk_overlay_unrealize (GtkWidget *widget) child = children->data; gtk_widget_set_parent_window (child->widget, NULL); - gdk_window_set_user_data (child->window, NULL); + gtk_widget_unregister_window (widget, child->window); gdk_window_destroy (child->window); child->window = NULL; } @@ -453,7 +539,7 @@ gtk_overlay_remove (GtkContainer *container, { if (child->window != NULL) { - gdk_window_set_user_data (child->window, NULL); + gtk_widget_unregister_window (GTK_WIDGET (container), child->window); gdk_window_destroy (child->window); } @@ -519,7 +605,7 @@ gtk_overlay_class_init (GtkOverlayClass *klass) * GtkOverlay::get-child-position: * @overlay: the #GtkOverlay * @widget: the child widget to position - * @allocation: (out): return location for the allocation + * @allocation: (out caller-allocates): return location for the allocation * * The ::get-child-position signal is emitted to determine * the position and size of any overlay child widgets. A @@ -605,7 +691,7 @@ gtk_overlay_new (void) * added with gtk_container_add(). * * The position at which @widget is placed is determined - * from its #GtkWidget::halign and #GtkWidget::valign properties. + * from its #GtkWidget:halign and #GtkWidget:valign properties. * * Since: 3.2 */ @@ -628,6 +714,7 @@ gtk_overlay_add_overlay (GtkOverlay *overlay, { child->window = gtk_overlay_create_child_window (overlay, widget); gtk_widget_set_parent (widget, GTK_WIDGET (overlay)); + gtk_overlay_child_allocate (overlay, child); } else gtk_widget_set_parent (widget, GTK_WIDGET (overlay));