Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* vim:expandtab:shiftwidth=4:tabstop=4: |
michael@0 | 3 | */ |
michael@0 | 4 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 7 | |
michael@0 | 8 | #include "mozcontainer.h" |
michael@0 | 9 | #include <gtk/gtk.h> |
michael@0 | 10 | #include <stdio.h> |
michael@0 | 11 | |
michael@0 | 12 | #ifdef ACCESSIBILITY |
michael@0 | 13 | #include <atk/atk.h> |
michael@0 | 14 | #include "maiRedundantObjectFactory.h" |
michael@0 | 15 | #endif |
michael@0 | 16 | |
michael@0 | 17 | /* init methods */ |
michael@0 | 18 | static void moz_container_class_init (MozContainerClass *klass); |
michael@0 | 19 | static void moz_container_init (MozContainer *container); |
michael@0 | 20 | |
michael@0 | 21 | /* widget class methods */ |
michael@0 | 22 | static void moz_container_map (GtkWidget *widget); |
michael@0 | 23 | static void moz_container_unmap (GtkWidget *widget); |
michael@0 | 24 | static void moz_container_realize (GtkWidget *widget); |
michael@0 | 25 | static void moz_container_size_allocate (GtkWidget *widget, |
michael@0 | 26 | GtkAllocation *allocation); |
michael@0 | 27 | |
michael@0 | 28 | /* container class methods */ |
michael@0 | 29 | static void moz_container_remove (GtkContainer *container, |
michael@0 | 30 | GtkWidget *child_widget); |
michael@0 | 31 | static void moz_container_forall (GtkContainer *container, |
michael@0 | 32 | gboolean include_internals, |
michael@0 | 33 | GtkCallback callback, |
michael@0 | 34 | gpointer callback_data); |
michael@0 | 35 | static void moz_container_add (GtkContainer *container, |
michael@0 | 36 | GtkWidget *widget); |
michael@0 | 37 | |
michael@0 | 38 | typedef struct _MozContainerChild MozContainerChild; |
michael@0 | 39 | |
michael@0 | 40 | struct _MozContainerChild { |
michael@0 | 41 | GtkWidget *widget; |
michael@0 | 42 | gint x; |
michael@0 | 43 | gint y; |
michael@0 | 44 | }; |
michael@0 | 45 | |
michael@0 | 46 | static void moz_container_allocate_child (MozContainer *container, |
michael@0 | 47 | MozContainerChild *child); |
michael@0 | 48 | static MozContainerChild * |
michael@0 | 49 | moz_container_get_child (MozContainer *container, GtkWidget *child); |
michael@0 | 50 | |
michael@0 | 51 | /* public methods */ |
michael@0 | 52 | |
michael@0 | 53 | GType |
michael@0 | 54 | moz_container_get_type(void) |
michael@0 | 55 | { |
michael@0 | 56 | static GType moz_container_type = 0; |
michael@0 | 57 | |
michael@0 | 58 | if (!moz_container_type) { |
michael@0 | 59 | static GTypeInfo moz_container_info = { |
michael@0 | 60 | sizeof(MozContainerClass), /* class_size */ |
michael@0 | 61 | NULL, /* base_init */ |
michael@0 | 62 | NULL, /* base_finalize */ |
michael@0 | 63 | (GClassInitFunc) moz_container_class_init, /* class_init */ |
michael@0 | 64 | NULL, /* class_destroy */ |
michael@0 | 65 | NULL, /* class_data */ |
michael@0 | 66 | sizeof(MozContainer), /* instance_size */ |
michael@0 | 67 | 0, /* n_preallocs */ |
michael@0 | 68 | (GInstanceInitFunc) moz_container_init, /* instance_init */ |
michael@0 | 69 | NULL, /* value_table */ |
michael@0 | 70 | }; |
michael@0 | 71 | |
michael@0 | 72 | moz_container_type = g_type_register_static (GTK_TYPE_CONTAINER, |
michael@0 | 73 | "MozContainer", |
michael@0 | 74 | &moz_container_info, 0); |
michael@0 | 75 | #ifdef ACCESSIBILITY |
michael@0 | 76 | /* Set a factory to return accessible object with ROLE_REDUNDANT for |
michael@0 | 77 | * MozContainer, so that gail won't send focus notification for it */ |
michael@0 | 78 | atk_registry_set_factory_type(atk_get_default_registry(), |
michael@0 | 79 | moz_container_type, |
michael@0 | 80 | mai_redundant_object_factory_get_type()); |
michael@0 | 81 | #endif |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | return moz_container_type; |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | GtkWidget * |
michael@0 | 88 | moz_container_new (void) |
michael@0 | 89 | { |
michael@0 | 90 | MozContainer *container; |
michael@0 | 91 | |
michael@0 | 92 | container = g_object_new (MOZ_CONTAINER_TYPE, NULL); |
michael@0 | 93 | |
michael@0 | 94 | return GTK_WIDGET(container); |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | void |
michael@0 | 98 | moz_container_put (MozContainer *container, GtkWidget *child_widget, |
michael@0 | 99 | gint x, gint y) |
michael@0 | 100 | { |
michael@0 | 101 | MozContainerChild *child; |
michael@0 | 102 | |
michael@0 | 103 | child = g_new (MozContainerChild, 1); |
michael@0 | 104 | |
michael@0 | 105 | child->widget = child_widget; |
michael@0 | 106 | child->x = x; |
michael@0 | 107 | child->y = y; |
michael@0 | 108 | |
michael@0 | 109 | /* printf("moz_container_put %p %p %d %d\n", (void *)container, |
michael@0 | 110 | (void *)child_widget, x, y); */ |
michael@0 | 111 | |
michael@0 | 112 | container->children = g_list_append (container->children, child); |
michael@0 | 113 | |
michael@0 | 114 | /* we assume that the caller of this function will have already set |
michael@0 | 115 | the parent GdkWindow because we can have many anonymous children. */ |
michael@0 | 116 | gtk_widget_set_parent(child_widget, GTK_WIDGET(container)); |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | void |
michael@0 | 120 | moz_container_move (MozContainer *container, GtkWidget *child_widget, |
michael@0 | 121 | gint x, gint y, gint width, gint height) |
michael@0 | 122 | { |
michael@0 | 123 | MozContainerChild *child; |
michael@0 | 124 | GtkAllocation new_allocation; |
michael@0 | 125 | |
michael@0 | 126 | child = moz_container_get_child (container, child_widget); |
michael@0 | 127 | |
michael@0 | 128 | child->x = x; |
michael@0 | 129 | child->y = y; |
michael@0 | 130 | |
michael@0 | 131 | new_allocation.x = x; |
michael@0 | 132 | new_allocation.y = y; |
michael@0 | 133 | new_allocation.width = width; |
michael@0 | 134 | new_allocation.height = height; |
michael@0 | 135 | |
michael@0 | 136 | /* printf("moz_container_move %p %p will allocate to %d %d %d %d\n", |
michael@0 | 137 | (void *)container, (void *)child_widget, |
michael@0 | 138 | new_allocation.x, new_allocation.y, |
michael@0 | 139 | new_allocation.width, new_allocation.height); */ |
michael@0 | 140 | |
michael@0 | 141 | gtk_widget_size_allocate(child_widget, &new_allocation); |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | /* static methods */ |
michael@0 | 145 | |
michael@0 | 146 | void |
michael@0 | 147 | moz_container_class_init (MozContainerClass *klass) |
michael@0 | 148 | { |
michael@0 | 149 | /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
michael@0 | 150 | GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */ |
michael@0 | 151 | GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); |
michael@0 | 152 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
michael@0 | 153 | |
michael@0 | 154 | widget_class->map = moz_container_map; |
michael@0 | 155 | widget_class->unmap = moz_container_unmap; |
michael@0 | 156 | widget_class->realize = moz_container_realize; |
michael@0 | 157 | widget_class->size_allocate = moz_container_size_allocate; |
michael@0 | 158 | |
michael@0 | 159 | container_class->remove = moz_container_remove; |
michael@0 | 160 | container_class->forall = moz_container_forall; |
michael@0 | 161 | container_class->add = moz_container_add; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | void |
michael@0 | 165 | moz_container_init (MozContainer *container) |
michael@0 | 166 | { |
michael@0 | 167 | gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE); |
michael@0 | 168 | gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE); |
michael@0 | 169 | gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | void |
michael@0 | 173 | moz_container_map (GtkWidget *widget) |
michael@0 | 174 | { |
michael@0 | 175 | MozContainer *container; |
michael@0 | 176 | GList *tmp_list; |
michael@0 | 177 | GtkWidget *tmp_child; |
michael@0 | 178 | |
michael@0 | 179 | g_return_if_fail (IS_MOZ_CONTAINER(widget)); |
michael@0 | 180 | container = MOZ_CONTAINER (widget); |
michael@0 | 181 | |
michael@0 | 182 | gtk_widget_set_mapped(widget, TRUE); |
michael@0 | 183 | |
michael@0 | 184 | tmp_list = container->children; |
michael@0 | 185 | while (tmp_list) { |
michael@0 | 186 | tmp_child = ((MozContainerChild *)tmp_list->data)->widget; |
michael@0 | 187 | |
michael@0 | 188 | if (gtk_widget_get_visible(tmp_child)) { |
michael@0 | 189 | if (!gtk_widget_get_mapped(tmp_child)) |
michael@0 | 190 | gtk_widget_map(tmp_child); |
michael@0 | 191 | } |
michael@0 | 192 | tmp_list = tmp_list->next; |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | if (gtk_widget_get_has_window (widget)) { |
michael@0 | 196 | gdk_window_show (gtk_widget_get_window(widget)); |
michael@0 | 197 | } |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | void |
michael@0 | 201 | moz_container_unmap (GtkWidget *widget) |
michael@0 | 202 | { |
michael@0 | 203 | g_return_if_fail (IS_MOZ_CONTAINER (widget)); |
michael@0 | 204 | |
michael@0 | 205 | gtk_widget_set_mapped(widget, FALSE); |
michael@0 | 206 | |
michael@0 | 207 | if (gtk_widget_get_has_window (widget)) { |
michael@0 | 208 | gdk_window_hide (gtk_widget_get_window(widget)); |
michael@0 | 209 | } |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | void |
michael@0 | 213 | moz_container_realize (GtkWidget *widget) |
michael@0 | 214 | { |
michael@0 | 215 | GdkWindow *parent = gtk_widget_get_parent_window (widget); |
michael@0 | 216 | GdkWindow *window; |
michael@0 | 217 | |
michael@0 | 218 | gtk_widget_set_realized(widget, TRUE); |
michael@0 | 219 | |
michael@0 | 220 | if (gtk_widget_get_has_window (widget)) { |
michael@0 | 221 | GdkWindowAttr attributes; |
michael@0 | 222 | gint attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y; |
michael@0 | 223 | GtkAllocation allocation; |
michael@0 | 224 | |
michael@0 | 225 | gtk_widget_get_allocation (widget, &allocation); |
michael@0 | 226 | attributes.event_mask = gtk_widget_get_events (widget); |
michael@0 | 227 | attributes.x = allocation.x; |
michael@0 | 228 | attributes.y = allocation.y; |
michael@0 | 229 | attributes.width = allocation.width; |
michael@0 | 230 | attributes.height = allocation.height; |
michael@0 | 231 | attributes.wclass = GDK_INPUT_OUTPUT; |
michael@0 | 232 | attributes.visual = gtk_widget_get_visual (widget); |
michael@0 | 233 | attributes.window_type = GDK_WINDOW_CHILD; |
michael@0 | 234 | |
michael@0 | 235 | #if (MOZ_WIDGET_GTK == 2) |
michael@0 | 236 | attributes.colormap = gtk_widget_get_colormap (widget); |
michael@0 | 237 | attributes_mask |= GDK_WA_COLORMAP; |
michael@0 | 238 | #endif |
michael@0 | 239 | |
michael@0 | 240 | window = gdk_window_new (parent, &attributes, attributes_mask); |
michael@0 | 241 | gdk_window_set_user_data (window, widget); |
michael@0 | 242 | #if (MOZ_WIDGET_GTK == 2) |
michael@0 | 243 | /* TODO GTK3? */ |
michael@0 | 244 | /* set the back pixmap to None so that you don't end up with the gtk |
michael@0 | 245 | default which is BlackPixel */ |
michael@0 | 246 | gdk_window_set_back_pixmap (window, NULL, FALSE); |
michael@0 | 247 | #endif |
michael@0 | 248 | } else { |
michael@0 | 249 | window = parent; |
michael@0 | 250 | g_object_ref (window); |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | gtk_widget_set_window (widget, window); |
michael@0 | 254 | |
michael@0 | 255 | #if (MOZ_WIDGET_GTK == 2) |
michael@0 | 256 | widget->style = gtk_style_attach (widget->style, widget->window); |
michael@0 | 257 | #endif |
michael@0 | 258 | } |
michael@0 | 259 | |
michael@0 | 260 | void |
michael@0 | 261 | moz_container_size_allocate (GtkWidget *widget, |
michael@0 | 262 | GtkAllocation *allocation) |
michael@0 | 263 | { |
michael@0 | 264 | MozContainer *container; |
michael@0 | 265 | GList *tmp_list; |
michael@0 | 266 | GtkAllocation tmp_allocation; |
michael@0 | 267 | GtkRequisition tmp_requisition; |
michael@0 | 268 | GtkWidget *tmp_child; |
michael@0 | 269 | |
michael@0 | 270 | g_return_if_fail (IS_MOZ_CONTAINER (widget)); |
michael@0 | 271 | |
michael@0 | 272 | /* printf("moz_container_size_allocate %p %d %d %d %d\n", |
michael@0 | 273 | (void *)widget, |
michael@0 | 274 | allocation->x, |
michael@0 | 275 | allocation->y, |
michael@0 | 276 | allocation->width, |
michael@0 | 277 | allocation->height); */ |
michael@0 | 278 | |
michael@0 | 279 | /* short circuit if you can */ |
michael@0 | 280 | container = MOZ_CONTAINER (widget); |
michael@0 | 281 | gtk_widget_get_allocation(widget, &tmp_allocation); |
michael@0 | 282 | if (!container->children && |
michael@0 | 283 | tmp_allocation.x == allocation->x && |
michael@0 | 284 | tmp_allocation.y == allocation->y && |
michael@0 | 285 | tmp_allocation.width == allocation->width && |
michael@0 | 286 | tmp_allocation.height == allocation->height) { |
michael@0 | 287 | return; |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | gtk_widget_set_allocation(widget, allocation); |
michael@0 | 291 | |
michael@0 | 292 | tmp_list = container->children; |
michael@0 | 293 | |
michael@0 | 294 | while (tmp_list) { |
michael@0 | 295 | MozContainerChild *child = tmp_list->data; |
michael@0 | 296 | |
michael@0 | 297 | moz_container_allocate_child (container, child); |
michael@0 | 298 | |
michael@0 | 299 | tmp_list = tmp_list->next; |
michael@0 | 300 | } |
michael@0 | 301 | |
michael@0 | 302 | if (gtk_widget_get_has_window (widget) && |
michael@0 | 303 | gtk_widget_get_realized (widget)) { |
michael@0 | 304 | |
michael@0 | 305 | gdk_window_move_resize(gtk_widget_get_window(widget), |
michael@0 | 306 | allocation->x, |
michael@0 | 307 | allocation->y, |
michael@0 | 308 | allocation->width, |
michael@0 | 309 | allocation->height); |
michael@0 | 310 | } |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | void |
michael@0 | 314 | moz_container_remove (GtkContainer *container, GtkWidget *child_widget) |
michael@0 | 315 | { |
michael@0 | 316 | MozContainerChild *child; |
michael@0 | 317 | MozContainer *moz_container; |
michael@0 | 318 | GdkWindow* parent_window; |
michael@0 | 319 | |
michael@0 | 320 | g_return_if_fail (IS_MOZ_CONTAINER(container)); |
michael@0 | 321 | g_return_if_fail (GTK_IS_WIDGET(child_widget)); |
michael@0 | 322 | |
michael@0 | 323 | moz_container = MOZ_CONTAINER(container); |
michael@0 | 324 | |
michael@0 | 325 | child = moz_container_get_child (moz_container, child_widget); |
michael@0 | 326 | g_return_if_fail (child); |
michael@0 | 327 | |
michael@0 | 328 | /* gtk_widget_unparent will remove the parent window (as well as the |
michael@0 | 329 | * parent widget), but, in Mozilla's window hierarchy, the parent window |
michael@0 | 330 | * may need to be kept because it may be part of a GdkWindow sub-hierarchy |
michael@0 | 331 | * that is being moved to another MozContainer. |
michael@0 | 332 | * |
michael@0 | 333 | * (In a conventional GtkWidget hierarchy, GdkWindows being reparented |
michael@0 | 334 | * would have their own GtkWidget and that widget would be the one being |
michael@0 | 335 | * reparented. In Mozilla's hierarchy, the parent_window needs to be |
michael@0 | 336 | * retained so that the GdkWindow sub-hierarchy is maintained.) |
michael@0 | 337 | */ |
michael@0 | 338 | parent_window = gtk_widget_get_parent_window(child_widget); |
michael@0 | 339 | if (parent_window) |
michael@0 | 340 | g_object_ref(parent_window); |
michael@0 | 341 | |
michael@0 | 342 | gtk_widget_unparent(child_widget); |
michael@0 | 343 | |
michael@0 | 344 | if (parent_window) { |
michael@0 | 345 | /* The child_widget will always still exist because g_signal_emit, |
michael@0 | 346 | * which invokes this function, holds a reference. |
michael@0 | 347 | * |
michael@0 | 348 | * If parent_window is the container's root window then it will not be |
michael@0 | 349 | * the parent_window if the child_widget is placed in another |
michael@0 | 350 | * container. |
michael@0 | 351 | */ |
michael@0 | 352 | if (parent_window != gtk_widget_get_window(GTK_WIDGET(container))) |
michael@0 | 353 | gtk_widget_set_parent_window(child_widget, parent_window); |
michael@0 | 354 | |
michael@0 | 355 | g_object_unref(parent_window); |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | moz_container->children = g_list_remove(moz_container->children, child); |
michael@0 | 359 | g_free(child); |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | void |
michael@0 | 363 | moz_container_forall (GtkContainer *container, gboolean include_internals, |
michael@0 | 364 | GtkCallback callback, gpointer callback_data) |
michael@0 | 365 | { |
michael@0 | 366 | MozContainer *moz_container; |
michael@0 | 367 | GList *tmp_list; |
michael@0 | 368 | |
michael@0 | 369 | g_return_if_fail (IS_MOZ_CONTAINER(container)); |
michael@0 | 370 | g_return_if_fail (callback != NULL); |
michael@0 | 371 | |
michael@0 | 372 | moz_container = MOZ_CONTAINER(container); |
michael@0 | 373 | |
michael@0 | 374 | tmp_list = moz_container->children; |
michael@0 | 375 | while (tmp_list) { |
michael@0 | 376 | MozContainerChild *child; |
michael@0 | 377 | child = tmp_list->data; |
michael@0 | 378 | tmp_list = tmp_list->next; |
michael@0 | 379 | (* callback) (child->widget, callback_data); |
michael@0 | 380 | } |
michael@0 | 381 | } |
michael@0 | 382 | |
michael@0 | 383 | static void |
michael@0 | 384 | moz_container_allocate_child (MozContainer *container, |
michael@0 | 385 | MozContainerChild *child) |
michael@0 | 386 | { |
michael@0 | 387 | GtkAllocation allocation; |
michael@0 | 388 | GtkRequisition requisition; |
michael@0 | 389 | |
michael@0 | 390 | gtk_widget_get_allocation (child->widget, &allocation); |
michael@0 | 391 | allocation.x = child->x; |
michael@0 | 392 | allocation.y = child->y; |
michael@0 | 393 | /* gtk_widget_get_child_requisition (child->widget, &requisition); */ |
michael@0 | 394 | /* gtk_widget_size_request (child->widget, &requisition); */ |
michael@0 | 395 | |
michael@0 | 396 | gtk_widget_size_allocate (child->widget, &allocation); |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | MozContainerChild * |
michael@0 | 400 | moz_container_get_child (MozContainer *container, GtkWidget *child_widget) |
michael@0 | 401 | { |
michael@0 | 402 | GList *tmp_list; |
michael@0 | 403 | |
michael@0 | 404 | tmp_list = container->children; |
michael@0 | 405 | while (tmp_list) { |
michael@0 | 406 | MozContainerChild *child; |
michael@0 | 407 | |
michael@0 | 408 | child = tmp_list->data; |
michael@0 | 409 | tmp_list = tmp_list->next; |
michael@0 | 410 | |
michael@0 | 411 | if (child->widget == child_widget) |
michael@0 | 412 | return child; |
michael@0 | 413 | } |
michael@0 | 414 | |
michael@0 | 415 | return NULL; |
michael@0 | 416 | } |
michael@0 | 417 | |
michael@0 | 418 | static void |
michael@0 | 419 | moz_container_add(GtkContainer *container, GtkWidget *widget) |
michael@0 | 420 | { |
michael@0 | 421 | moz_container_put(MOZ_CONTAINER(container), widget, 0, 0); |
michael@0 | 422 | } |
michael@0 | 423 |