michael@0: /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim:expandtab:shiftwidth=4:tabstop=4: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozcontainer.h" michael@0: #include michael@0: #include michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: #include michael@0: #include "maiRedundantObjectFactory.h" michael@0: #endif michael@0: michael@0: /* init methods */ michael@0: static void moz_container_class_init (MozContainerClass *klass); michael@0: static void moz_container_init (MozContainer *container); michael@0: michael@0: /* widget class methods */ michael@0: static void moz_container_map (GtkWidget *widget); michael@0: static void moz_container_unmap (GtkWidget *widget); michael@0: static void moz_container_realize (GtkWidget *widget); michael@0: static void moz_container_size_allocate (GtkWidget *widget, michael@0: GtkAllocation *allocation); michael@0: michael@0: /* container class methods */ michael@0: static void moz_container_remove (GtkContainer *container, michael@0: GtkWidget *child_widget); michael@0: static void moz_container_forall (GtkContainer *container, michael@0: gboolean include_internals, michael@0: GtkCallback callback, michael@0: gpointer callback_data); michael@0: static void moz_container_add (GtkContainer *container, michael@0: GtkWidget *widget); michael@0: michael@0: typedef struct _MozContainerChild MozContainerChild; michael@0: michael@0: struct _MozContainerChild { michael@0: GtkWidget *widget; michael@0: gint x; michael@0: gint y; michael@0: }; michael@0: michael@0: static void moz_container_allocate_child (MozContainer *container, michael@0: MozContainerChild *child); michael@0: static MozContainerChild * michael@0: moz_container_get_child (MozContainer *container, GtkWidget *child); michael@0: michael@0: /* public methods */ michael@0: michael@0: GType michael@0: moz_container_get_type(void) michael@0: { michael@0: static GType moz_container_type = 0; michael@0: michael@0: if (!moz_container_type) { michael@0: static GTypeInfo moz_container_info = { michael@0: sizeof(MozContainerClass), /* class_size */ michael@0: NULL, /* base_init */ michael@0: NULL, /* base_finalize */ michael@0: (GClassInitFunc) moz_container_class_init, /* class_init */ michael@0: NULL, /* class_destroy */ michael@0: NULL, /* class_data */ michael@0: sizeof(MozContainer), /* instance_size */ michael@0: 0, /* n_preallocs */ michael@0: (GInstanceInitFunc) moz_container_init, /* instance_init */ michael@0: NULL, /* value_table */ michael@0: }; michael@0: michael@0: moz_container_type = g_type_register_static (GTK_TYPE_CONTAINER, michael@0: "MozContainer", michael@0: &moz_container_info, 0); michael@0: #ifdef ACCESSIBILITY michael@0: /* Set a factory to return accessible object with ROLE_REDUNDANT for michael@0: * MozContainer, so that gail won't send focus notification for it */ michael@0: atk_registry_set_factory_type(atk_get_default_registry(), michael@0: moz_container_type, michael@0: mai_redundant_object_factory_get_type()); michael@0: #endif michael@0: } michael@0: michael@0: return moz_container_type; michael@0: } michael@0: michael@0: GtkWidget * michael@0: moz_container_new (void) michael@0: { michael@0: MozContainer *container; michael@0: michael@0: container = g_object_new (MOZ_CONTAINER_TYPE, NULL); michael@0: michael@0: return GTK_WIDGET(container); michael@0: } michael@0: michael@0: void michael@0: moz_container_put (MozContainer *container, GtkWidget *child_widget, michael@0: gint x, gint y) michael@0: { michael@0: MozContainerChild *child; michael@0: michael@0: child = g_new (MozContainerChild, 1); michael@0: michael@0: child->widget = child_widget; michael@0: child->x = x; michael@0: child->y = y; michael@0: michael@0: /* printf("moz_container_put %p %p %d %d\n", (void *)container, michael@0: (void *)child_widget, x, y); */ michael@0: michael@0: container->children = g_list_append (container->children, child); michael@0: michael@0: /* we assume that the caller of this function will have already set michael@0: the parent GdkWindow because we can have many anonymous children. */ michael@0: gtk_widget_set_parent(child_widget, GTK_WIDGET(container)); michael@0: } michael@0: michael@0: void michael@0: moz_container_move (MozContainer *container, GtkWidget *child_widget, michael@0: gint x, gint y, gint width, gint height) michael@0: { michael@0: MozContainerChild *child; michael@0: GtkAllocation new_allocation; michael@0: michael@0: child = moz_container_get_child (container, child_widget); michael@0: michael@0: child->x = x; michael@0: child->y = y; michael@0: michael@0: new_allocation.x = x; michael@0: new_allocation.y = y; michael@0: new_allocation.width = width; michael@0: new_allocation.height = height; michael@0: michael@0: /* printf("moz_container_move %p %p will allocate to %d %d %d %d\n", michael@0: (void *)container, (void *)child_widget, michael@0: new_allocation.x, new_allocation.y, michael@0: new_allocation.width, new_allocation.height); */ michael@0: michael@0: gtk_widget_size_allocate(child_widget, &new_allocation); michael@0: } michael@0: michael@0: /* static methods */ michael@0: michael@0: void michael@0: moz_container_class_init (MozContainerClass *klass) michael@0: { michael@0: /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass); michael@0: GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */ michael@0: GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); michael@0: GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); michael@0: michael@0: widget_class->map = moz_container_map; michael@0: widget_class->unmap = moz_container_unmap; michael@0: widget_class->realize = moz_container_realize; michael@0: widget_class->size_allocate = moz_container_size_allocate; michael@0: michael@0: container_class->remove = moz_container_remove; michael@0: container_class->forall = moz_container_forall; michael@0: container_class->add = moz_container_add; michael@0: } michael@0: michael@0: void michael@0: moz_container_init (MozContainer *container) michael@0: { michael@0: gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE); michael@0: gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE); michael@0: gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE); michael@0: } michael@0: michael@0: void michael@0: moz_container_map (GtkWidget *widget) michael@0: { michael@0: MozContainer *container; michael@0: GList *tmp_list; michael@0: GtkWidget *tmp_child; michael@0: michael@0: g_return_if_fail (IS_MOZ_CONTAINER(widget)); michael@0: container = MOZ_CONTAINER (widget); michael@0: michael@0: gtk_widget_set_mapped(widget, TRUE); michael@0: michael@0: tmp_list = container->children; michael@0: while (tmp_list) { michael@0: tmp_child = ((MozContainerChild *)tmp_list->data)->widget; michael@0: michael@0: if (gtk_widget_get_visible(tmp_child)) { michael@0: if (!gtk_widget_get_mapped(tmp_child)) michael@0: gtk_widget_map(tmp_child); michael@0: } michael@0: tmp_list = tmp_list->next; michael@0: } michael@0: michael@0: if (gtk_widget_get_has_window (widget)) { michael@0: gdk_window_show (gtk_widget_get_window(widget)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: moz_container_unmap (GtkWidget *widget) michael@0: { michael@0: g_return_if_fail (IS_MOZ_CONTAINER (widget)); michael@0: michael@0: gtk_widget_set_mapped(widget, FALSE); michael@0: michael@0: if (gtk_widget_get_has_window (widget)) { michael@0: gdk_window_hide (gtk_widget_get_window(widget)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: moz_container_realize (GtkWidget *widget) michael@0: { michael@0: GdkWindow *parent = gtk_widget_get_parent_window (widget); michael@0: GdkWindow *window; michael@0: michael@0: gtk_widget_set_realized(widget, TRUE); michael@0: michael@0: if (gtk_widget_get_has_window (widget)) { michael@0: GdkWindowAttr attributes; michael@0: gint attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y; michael@0: GtkAllocation allocation; michael@0: michael@0: gtk_widget_get_allocation (widget, &allocation); michael@0: attributes.event_mask = gtk_widget_get_events (widget); michael@0: attributes.x = allocation.x; michael@0: attributes.y = allocation.y; michael@0: attributes.width = allocation.width; michael@0: attributes.height = allocation.height; michael@0: attributes.wclass = GDK_INPUT_OUTPUT; michael@0: attributes.visual = gtk_widget_get_visual (widget); michael@0: attributes.window_type = GDK_WINDOW_CHILD; michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: attributes.colormap = gtk_widget_get_colormap (widget); michael@0: attributes_mask |= GDK_WA_COLORMAP; michael@0: #endif michael@0: michael@0: window = gdk_window_new (parent, &attributes, attributes_mask); michael@0: gdk_window_set_user_data (window, widget); michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: /* TODO GTK3? */ michael@0: /* set the back pixmap to None so that you don't end up with the gtk michael@0: default which is BlackPixel */ michael@0: gdk_window_set_back_pixmap (window, NULL, FALSE); michael@0: #endif michael@0: } else { michael@0: window = parent; michael@0: g_object_ref (window); michael@0: } michael@0: michael@0: gtk_widget_set_window (widget, window); michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: widget->style = gtk_style_attach (widget->style, widget->window); michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: moz_container_size_allocate (GtkWidget *widget, michael@0: GtkAllocation *allocation) michael@0: { michael@0: MozContainer *container; michael@0: GList *tmp_list; michael@0: GtkAllocation tmp_allocation; michael@0: GtkRequisition tmp_requisition; michael@0: GtkWidget *tmp_child; michael@0: michael@0: g_return_if_fail (IS_MOZ_CONTAINER (widget)); michael@0: michael@0: /* printf("moz_container_size_allocate %p %d %d %d %d\n", michael@0: (void *)widget, michael@0: allocation->x, michael@0: allocation->y, michael@0: allocation->width, michael@0: allocation->height); */ michael@0: michael@0: /* short circuit if you can */ michael@0: container = MOZ_CONTAINER (widget); michael@0: gtk_widget_get_allocation(widget, &tmp_allocation); michael@0: if (!container->children && michael@0: tmp_allocation.x == allocation->x && michael@0: tmp_allocation.y == allocation->y && michael@0: tmp_allocation.width == allocation->width && michael@0: tmp_allocation.height == allocation->height) { michael@0: return; michael@0: } michael@0: michael@0: gtk_widget_set_allocation(widget, allocation); michael@0: michael@0: tmp_list = container->children; michael@0: michael@0: while (tmp_list) { michael@0: MozContainerChild *child = tmp_list->data; michael@0: michael@0: moz_container_allocate_child (container, child); michael@0: michael@0: tmp_list = tmp_list->next; michael@0: } michael@0: michael@0: if (gtk_widget_get_has_window (widget) && michael@0: gtk_widget_get_realized (widget)) { michael@0: michael@0: gdk_window_move_resize(gtk_widget_get_window(widget), michael@0: allocation->x, michael@0: allocation->y, michael@0: allocation->width, michael@0: allocation->height); michael@0: } michael@0: } michael@0: michael@0: void michael@0: moz_container_remove (GtkContainer *container, GtkWidget *child_widget) michael@0: { michael@0: MozContainerChild *child; michael@0: MozContainer *moz_container; michael@0: GdkWindow* parent_window; michael@0: michael@0: g_return_if_fail (IS_MOZ_CONTAINER(container)); michael@0: g_return_if_fail (GTK_IS_WIDGET(child_widget)); michael@0: michael@0: moz_container = MOZ_CONTAINER(container); michael@0: michael@0: child = moz_container_get_child (moz_container, child_widget); michael@0: g_return_if_fail (child); michael@0: michael@0: /* gtk_widget_unparent will remove the parent window (as well as the michael@0: * parent widget), but, in Mozilla's window hierarchy, the parent window michael@0: * may need to be kept because it may be part of a GdkWindow sub-hierarchy michael@0: * that is being moved to another MozContainer. michael@0: * michael@0: * (In a conventional GtkWidget hierarchy, GdkWindows being reparented michael@0: * would have their own GtkWidget and that widget would be the one being michael@0: * reparented. In Mozilla's hierarchy, the parent_window needs to be michael@0: * retained so that the GdkWindow sub-hierarchy is maintained.) michael@0: */ michael@0: parent_window = gtk_widget_get_parent_window(child_widget); michael@0: if (parent_window) michael@0: g_object_ref(parent_window); michael@0: michael@0: gtk_widget_unparent(child_widget); michael@0: michael@0: if (parent_window) { michael@0: /* The child_widget will always still exist because g_signal_emit, michael@0: * which invokes this function, holds a reference. michael@0: * michael@0: * If parent_window is the container's root window then it will not be michael@0: * the parent_window if the child_widget is placed in another michael@0: * container. michael@0: */ michael@0: if (parent_window != gtk_widget_get_window(GTK_WIDGET(container))) michael@0: gtk_widget_set_parent_window(child_widget, parent_window); michael@0: michael@0: g_object_unref(parent_window); michael@0: } michael@0: michael@0: moz_container->children = g_list_remove(moz_container->children, child); michael@0: g_free(child); michael@0: } michael@0: michael@0: void michael@0: moz_container_forall (GtkContainer *container, gboolean include_internals, michael@0: GtkCallback callback, gpointer callback_data) michael@0: { michael@0: MozContainer *moz_container; michael@0: GList *tmp_list; michael@0: michael@0: g_return_if_fail (IS_MOZ_CONTAINER(container)); michael@0: g_return_if_fail (callback != NULL); michael@0: michael@0: moz_container = MOZ_CONTAINER(container); michael@0: michael@0: tmp_list = moz_container->children; michael@0: while (tmp_list) { michael@0: MozContainerChild *child; michael@0: child = tmp_list->data; michael@0: tmp_list = tmp_list->next; michael@0: (* callback) (child->widget, callback_data); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: moz_container_allocate_child (MozContainer *container, michael@0: MozContainerChild *child) michael@0: { michael@0: GtkAllocation allocation; michael@0: GtkRequisition requisition; michael@0: michael@0: gtk_widget_get_allocation (child->widget, &allocation); michael@0: allocation.x = child->x; michael@0: allocation.y = child->y; michael@0: /* gtk_widget_get_child_requisition (child->widget, &requisition); */ michael@0: /* gtk_widget_size_request (child->widget, &requisition); */ michael@0: michael@0: gtk_widget_size_allocate (child->widget, &allocation); michael@0: } michael@0: michael@0: MozContainerChild * michael@0: moz_container_get_child (MozContainer *container, GtkWidget *child_widget) michael@0: { michael@0: GList *tmp_list; michael@0: michael@0: tmp_list = container->children; michael@0: while (tmp_list) { michael@0: MozContainerChild *child; michael@0: michael@0: child = tmp_list->data; michael@0: tmp_list = tmp_list->next; michael@0: michael@0: if (child->widget == child_widget) michael@0: return child; michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: static void michael@0: moz_container_add(GtkContainer *container, GtkWidget *widget) michael@0: { michael@0: moz_container_put(MOZ_CONTAINER(container), widget, 0, 0); michael@0: } michael@0: