1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gtk/mozcontainer.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,423 @@ 1.4 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:expandtab:shiftwidth=4:tabstop=4: 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "mozcontainer.h" 1.12 +#include <gtk/gtk.h> 1.13 +#include <stdio.h> 1.14 + 1.15 +#ifdef ACCESSIBILITY 1.16 +#include <atk/atk.h> 1.17 +#include "maiRedundantObjectFactory.h" 1.18 +#endif 1.19 + 1.20 +/* init methods */ 1.21 +static void moz_container_class_init (MozContainerClass *klass); 1.22 +static void moz_container_init (MozContainer *container); 1.23 + 1.24 +/* widget class methods */ 1.25 +static void moz_container_map (GtkWidget *widget); 1.26 +static void moz_container_unmap (GtkWidget *widget); 1.27 +static void moz_container_realize (GtkWidget *widget); 1.28 +static void moz_container_size_allocate (GtkWidget *widget, 1.29 + GtkAllocation *allocation); 1.30 + 1.31 +/* container class methods */ 1.32 +static void moz_container_remove (GtkContainer *container, 1.33 + GtkWidget *child_widget); 1.34 +static void moz_container_forall (GtkContainer *container, 1.35 + gboolean include_internals, 1.36 + GtkCallback callback, 1.37 + gpointer callback_data); 1.38 +static void moz_container_add (GtkContainer *container, 1.39 + GtkWidget *widget); 1.40 + 1.41 +typedef struct _MozContainerChild MozContainerChild; 1.42 + 1.43 +struct _MozContainerChild { 1.44 + GtkWidget *widget; 1.45 + gint x; 1.46 + gint y; 1.47 +}; 1.48 + 1.49 +static void moz_container_allocate_child (MozContainer *container, 1.50 + MozContainerChild *child); 1.51 +static MozContainerChild * 1.52 +moz_container_get_child (MozContainer *container, GtkWidget *child); 1.53 + 1.54 +/* public methods */ 1.55 + 1.56 +GType 1.57 +moz_container_get_type(void) 1.58 +{ 1.59 + static GType moz_container_type = 0; 1.60 + 1.61 + if (!moz_container_type) { 1.62 + static GTypeInfo moz_container_info = { 1.63 + sizeof(MozContainerClass), /* class_size */ 1.64 + NULL, /* base_init */ 1.65 + NULL, /* base_finalize */ 1.66 + (GClassInitFunc) moz_container_class_init, /* class_init */ 1.67 + NULL, /* class_destroy */ 1.68 + NULL, /* class_data */ 1.69 + sizeof(MozContainer), /* instance_size */ 1.70 + 0, /* n_preallocs */ 1.71 + (GInstanceInitFunc) moz_container_init, /* instance_init */ 1.72 + NULL, /* value_table */ 1.73 + }; 1.74 + 1.75 + moz_container_type = g_type_register_static (GTK_TYPE_CONTAINER, 1.76 + "MozContainer", 1.77 + &moz_container_info, 0); 1.78 +#ifdef ACCESSIBILITY 1.79 + /* Set a factory to return accessible object with ROLE_REDUNDANT for 1.80 + * MozContainer, so that gail won't send focus notification for it */ 1.81 + atk_registry_set_factory_type(atk_get_default_registry(), 1.82 + moz_container_type, 1.83 + mai_redundant_object_factory_get_type()); 1.84 +#endif 1.85 + } 1.86 + 1.87 + return moz_container_type; 1.88 +} 1.89 + 1.90 +GtkWidget * 1.91 +moz_container_new (void) 1.92 +{ 1.93 + MozContainer *container; 1.94 + 1.95 + container = g_object_new (MOZ_CONTAINER_TYPE, NULL); 1.96 + 1.97 + return GTK_WIDGET(container); 1.98 +} 1.99 + 1.100 +void 1.101 +moz_container_put (MozContainer *container, GtkWidget *child_widget, 1.102 + gint x, gint y) 1.103 +{ 1.104 + MozContainerChild *child; 1.105 + 1.106 + child = g_new (MozContainerChild, 1); 1.107 + 1.108 + child->widget = child_widget; 1.109 + child->x = x; 1.110 + child->y = y; 1.111 + 1.112 + /* printf("moz_container_put %p %p %d %d\n", (void *)container, 1.113 + (void *)child_widget, x, y); */ 1.114 + 1.115 + container->children = g_list_append (container->children, child); 1.116 + 1.117 + /* we assume that the caller of this function will have already set 1.118 + the parent GdkWindow because we can have many anonymous children. */ 1.119 + gtk_widget_set_parent(child_widget, GTK_WIDGET(container)); 1.120 +} 1.121 + 1.122 +void 1.123 +moz_container_move (MozContainer *container, GtkWidget *child_widget, 1.124 + gint x, gint y, gint width, gint height) 1.125 +{ 1.126 + MozContainerChild *child; 1.127 + GtkAllocation new_allocation; 1.128 + 1.129 + child = moz_container_get_child (container, child_widget); 1.130 + 1.131 + child->x = x; 1.132 + child->y = y; 1.133 + 1.134 + new_allocation.x = x; 1.135 + new_allocation.y = y; 1.136 + new_allocation.width = width; 1.137 + new_allocation.height = height; 1.138 + 1.139 + /* printf("moz_container_move %p %p will allocate to %d %d %d %d\n", 1.140 + (void *)container, (void *)child_widget, 1.141 + new_allocation.x, new_allocation.y, 1.142 + new_allocation.width, new_allocation.height); */ 1.143 + 1.144 + gtk_widget_size_allocate(child_widget, &new_allocation); 1.145 +} 1.146 + 1.147 +/* static methods */ 1.148 + 1.149 +void 1.150 +moz_container_class_init (MozContainerClass *klass) 1.151 +{ 1.152 + /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 1.153 + GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */ 1.154 + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); 1.155 + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); 1.156 + 1.157 + widget_class->map = moz_container_map; 1.158 + widget_class->unmap = moz_container_unmap; 1.159 + widget_class->realize = moz_container_realize; 1.160 + widget_class->size_allocate = moz_container_size_allocate; 1.161 + 1.162 + container_class->remove = moz_container_remove; 1.163 + container_class->forall = moz_container_forall; 1.164 + container_class->add = moz_container_add; 1.165 +} 1.166 + 1.167 +void 1.168 +moz_container_init (MozContainer *container) 1.169 +{ 1.170 + gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE); 1.171 + gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE); 1.172 + gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE); 1.173 +} 1.174 + 1.175 +void 1.176 +moz_container_map (GtkWidget *widget) 1.177 +{ 1.178 + MozContainer *container; 1.179 + GList *tmp_list; 1.180 + GtkWidget *tmp_child; 1.181 + 1.182 + g_return_if_fail (IS_MOZ_CONTAINER(widget)); 1.183 + container = MOZ_CONTAINER (widget); 1.184 + 1.185 + gtk_widget_set_mapped(widget, TRUE); 1.186 + 1.187 + tmp_list = container->children; 1.188 + while (tmp_list) { 1.189 + tmp_child = ((MozContainerChild *)tmp_list->data)->widget; 1.190 + 1.191 + if (gtk_widget_get_visible(tmp_child)) { 1.192 + if (!gtk_widget_get_mapped(tmp_child)) 1.193 + gtk_widget_map(tmp_child); 1.194 + } 1.195 + tmp_list = tmp_list->next; 1.196 + } 1.197 + 1.198 + if (gtk_widget_get_has_window (widget)) { 1.199 + gdk_window_show (gtk_widget_get_window(widget)); 1.200 + } 1.201 +} 1.202 + 1.203 +void 1.204 +moz_container_unmap (GtkWidget *widget) 1.205 +{ 1.206 + g_return_if_fail (IS_MOZ_CONTAINER (widget)); 1.207 + 1.208 + gtk_widget_set_mapped(widget, FALSE); 1.209 + 1.210 + if (gtk_widget_get_has_window (widget)) { 1.211 + gdk_window_hide (gtk_widget_get_window(widget)); 1.212 + } 1.213 +} 1.214 + 1.215 +void 1.216 +moz_container_realize (GtkWidget *widget) 1.217 +{ 1.218 + GdkWindow *parent = gtk_widget_get_parent_window (widget); 1.219 + GdkWindow *window; 1.220 + 1.221 + gtk_widget_set_realized(widget, TRUE); 1.222 + 1.223 + if (gtk_widget_get_has_window (widget)) { 1.224 + GdkWindowAttr attributes; 1.225 + gint attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y; 1.226 + GtkAllocation allocation; 1.227 + 1.228 + gtk_widget_get_allocation (widget, &allocation); 1.229 + attributes.event_mask = gtk_widget_get_events (widget); 1.230 + attributes.x = allocation.x; 1.231 + attributes.y = allocation.y; 1.232 + attributes.width = allocation.width; 1.233 + attributes.height = allocation.height; 1.234 + attributes.wclass = GDK_INPUT_OUTPUT; 1.235 + attributes.visual = gtk_widget_get_visual (widget); 1.236 + attributes.window_type = GDK_WINDOW_CHILD; 1.237 + 1.238 +#if (MOZ_WIDGET_GTK == 2) 1.239 + attributes.colormap = gtk_widget_get_colormap (widget); 1.240 + attributes_mask |= GDK_WA_COLORMAP; 1.241 +#endif 1.242 + 1.243 + window = gdk_window_new (parent, &attributes, attributes_mask); 1.244 + gdk_window_set_user_data (window, widget); 1.245 +#if (MOZ_WIDGET_GTK == 2) 1.246 + /* TODO GTK3? */ 1.247 + /* set the back pixmap to None so that you don't end up with the gtk 1.248 + default which is BlackPixel */ 1.249 + gdk_window_set_back_pixmap (window, NULL, FALSE); 1.250 +#endif 1.251 + } else { 1.252 + window = parent; 1.253 + g_object_ref (window); 1.254 + } 1.255 + 1.256 + gtk_widget_set_window (widget, window); 1.257 + 1.258 +#if (MOZ_WIDGET_GTK == 2) 1.259 + widget->style = gtk_style_attach (widget->style, widget->window); 1.260 +#endif 1.261 +} 1.262 + 1.263 +void 1.264 +moz_container_size_allocate (GtkWidget *widget, 1.265 + GtkAllocation *allocation) 1.266 +{ 1.267 + MozContainer *container; 1.268 + GList *tmp_list; 1.269 + GtkAllocation tmp_allocation; 1.270 + GtkRequisition tmp_requisition; 1.271 + GtkWidget *tmp_child; 1.272 + 1.273 + g_return_if_fail (IS_MOZ_CONTAINER (widget)); 1.274 + 1.275 + /* printf("moz_container_size_allocate %p %d %d %d %d\n", 1.276 + (void *)widget, 1.277 + allocation->x, 1.278 + allocation->y, 1.279 + allocation->width, 1.280 + allocation->height); */ 1.281 + 1.282 + /* short circuit if you can */ 1.283 + container = MOZ_CONTAINER (widget); 1.284 + gtk_widget_get_allocation(widget, &tmp_allocation); 1.285 + if (!container->children && 1.286 + tmp_allocation.x == allocation->x && 1.287 + tmp_allocation.y == allocation->y && 1.288 + tmp_allocation.width == allocation->width && 1.289 + tmp_allocation.height == allocation->height) { 1.290 + return; 1.291 + } 1.292 + 1.293 + gtk_widget_set_allocation(widget, allocation); 1.294 + 1.295 + tmp_list = container->children; 1.296 + 1.297 + while (tmp_list) { 1.298 + MozContainerChild *child = tmp_list->data; 1.299 + 1.300 + moz_container_allocate_child (container, child); 1.301 + 1.302 + tmp_list = tmp_list->next; 1.303 + } 1.304 + 1.305 + if (gtk_widget_get_has_window (widget) && 1.306 + gtk_widget_get_realized (widget)) { 1.307 + 1.308 + gdk_window_move_resize(gtk_widget_get_window(widget), 1.309 + allocation->x, 1.310 + allocation->y, 1.311 + allocation->width, 1.312 + allocation->height); 1.313 + } 1.314 +} 1.315 + 1.316 +void 1.317 +moz_container_remove (GtkContainer *container, GtkWidget *child_widget) 1.318 +{ 1.319 + MozContainerChild *child; 1.320 + MozContainer *moz_container; 1.321 + GdkWindow* parent_window; 1.322 + 1.323 + g_return_if_fail (IS_MOZ_CONTAINER(container)); 1.324 + g_return_if_fail (GTK_IS_WIDGET(child_widget)); 1.325 + 1.326 + moz_container = MOZ_CONTAINER(container); 1.327 + 1.328 + child = moz_container_get_child (moz_container, child_widget); 1.329 + g_return_if_fail (child); 1.330 + 1.331 + /* gtk_widget_unparent will remove the parent window (as well as the 1.332 + * parent widget), but, in Mozilla's window hierarchy, the parent window 1.333 + * may need to be kept because it may be part of a GdkWindow sub-hierarchy 1.334 + * that is being moved to another MozContainer. 1.335 + * 1.336 + * (In a conventional GtkWidget hierarchy, GdkWindows being reparented 1.337 + * would have their own GtkWidget and that widget would be the one being 1.338 + * reparented. In Mozilla's hierarchy, the parent_window needs to be 1.339 + * retained so that the GdkWindow sub-hierarchy is maintained.) 1.340 + */ 1.341 + parent_window = gtk_widget_get_parent_window(child_widget); 1.342 + if (parent_window) 1.343 + g_object_ref(parent_window); 1.344 + 1.345 + gtk_widget_unparent(child_widget); 1.346 + 1.347 + if (parent_window) { 1.348 + /* The child_widget will always still exist because g_signal_emit, 1.349 + * which invokes this function, holds a reference. 1.350 + * 1.351 + * If parent_window is the container's root window then it will not be 1.352 + * the parent_window if the child_widget is placed in another 1.353 + * container. 1.354 + */ 1.355 + if (parent_window != gtk_widget_get_window(GTK_WIDGET(container))) 1.356 + gtk_widget_set_parent_window(child_widget, parent_window); 1.357 + 1.358 + g_object_unref(parent_window); 1.359 + } 1.360 + 1.361 + moz_container->children = g_list_remove(moz_container->children, child); 1.362 + g_free(child); 1.363 +} 1.364 + 1.365 +void 1.366 +moz_container_forall (GtkContainer *container, gboolean include_internals, 1.367 + GtkCallback callback, gpointer callback_data) 1.368 +{ 1.369 + MozContainer *moz_container; 1.370 + GList *tmp_list; 1.371 + 1.372 + g_return_if_fail (IS_MOZ_CONTAINER(container)); 1.373 + g_return_if_fail (callback != NULL); 1.374 + 1.375 + moz_container = MOZ_CONTAINER(container); 1.376 + 1.377 + tmp_list = moz_container->children; 1.378 + while (tmp_list) { 1.379 + MozContainerChild *child; 1.380 + child = tmp_list->data; 1.381 + tmp_list = tmp_list->next; 1.382 + (* callback) (child->widget, callback_data); 1.383 + } 1.384 +} 1.385 + 1.386 +static void 1.387 +moz_container_allocate_child (MozContainer *container, 1.388 + MozContainerChild *child) 1.389 +{ 1.390 + GtkAllocation allocation; 1.391 + GtkRequisition requisition; 1.392 + 1.393 + gtk_widget_get_allocation (child->widget, &allocation); 1.394 + allocation.x = child->x; 1.395 + allocation.y = child->y; 1.396 + /* gtk_widget_get_child_requisition (child->widget, &requisition); */ 1.397 + /* gtk_widget_size_request (child->widget, &requisition); */ 1.398 + 1.399 + gtk_widget_size_allocate (child->widget, &allocation); 1.400 +} 1.401 + 1.402 +MozContainerChild * 1.403 +moz_container_get_child (MozContainer *container, GtkWidget *child_widget) 1.404 +{ 1.405 + GList *tmp_list; 1.406 + 1.407 + tmp_list = container->children; 1.408 + while (tmp_list) { 1.409 + MozContainerChild *child; 1.410 + 1.411 + child = tmp_list->data; 1.412 + tmp_list = tmp_list->next; 1.413 + 1.414 + if (child->widget == child_widget) 1.415 + return child; 1.416 + } 1.417 + 1.418 + return NULL; 1.419 +} 1.420 + 1.421 +static void 1.422 +moz_container_add(GtkContainer *container, GtkWidget *widget) 1.423 +{ 1.424 + moz_container_put(MOZ_CONTAINER(container), widget, 0, 0); 1.425 +} 1.426 +