Bug 1842773 - Part 34: Enable test262 tests. r=sfink
[gecko.git] / widget / gtk / MozContainer.cpp
blob8d24814d9d3355358cb948bab1eac1f17ddd6b7a
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "MozContainer.h"
10 #include <glib.h>
11 #include <gtk/gtk.h>
12 #include <stdio.h>
13 #include "mozilla/WidgetUtilsGtk.h"
15 #ifdef MOZ_LOGGING
16 # include "mozilla/Logging.h"
17 # include "nsTArray.h"
18 # include "Units.h"
19 extern mozilla::LazyLogModule gWidgetLog;
20 # define LOGCONTAINER(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
21 #else
22 # define LOGCONTAINER(args)
23 #endif /* MOZ_LOGGING */
25 /* init methods */
26 void moz_container_class_init(MozContainerClass* klass);
27 static void moz_container_init(MozContainer* container);
29 /* widget class methods */
30 static void moz_container_map(GtkWidget* widget);
31 void moz_container_unmap(GtkWidget* widget);
32 static void moz_container_size_allocate(GtkWidget* widget,
33 GtkAllocation* allocation);
34 static void moz_container_realize(GtkWidget* widget);
35 static void moz_container_unrealize(GtkWidget* widget);
37 /* container class methods */
38 static void moz_container_remove(GtkContainer* container,
39 GtkWidget* child_widget);
40 static void moz_container_forall(GtkContainer* container,
41 gboolean include_internals,
42 GtkCallback callback, gpointer callback_data);
43 static void moz_container_add(GtkContainer* container, GtkWidget* widget);
45 typedef struct _MozContainerChild MozContainerChild;
47 struct _MozContainerChild {
48 GtkWidget* widget;
49 gint x;
50 gint y;
53 static void moz_container_allocate_child(MozContainer* container,
54 MozContainerChild* child);
55 static MozContainerChild* moz_container_get_child(MozContainer* container,
56 GtkWidget* child);
58 /* public methods */
60 GType moz_container_get_type(void) {
61 static GType moz_container_type = 0;
63 if (!moz_container_type) {
64 static GTypeInfo moz_container_info = {
65 sizeof(MozContainerClass), /* class_size */
66 NULL, /* base_init */
67 NULL, /* base_finalize */
68 (GClassInitFunc)moz_container_class_init, /* class_init */
69 NULL, /* class_destroy */
70 NULL, /* class_data */
71 sizeof(MozContainer), /* instance_size */
72 0, /* n_preallocs */
73 (GInstanceInitFunc)moz_container_init, /* instance_init */
74 NULL, /* value_table */
77 moz_container_type =
78 g_type_register_static(GTK_TYPE_CONTAINER, "MozContainer",
79 &moz_container_info, static_cast<GTypeFlags>(0));
82 return moz_container_type;
85 GtkWidget* moz_container_new(void) {
86 MozContainer* container;
88 container =
89 static_cast<MozContainer*>(g_object_new(MOZ_CONTAINER_TYPE, nullptr));
91 return GTK_WIDGET(container);
94 void moz_container_put(MozContainer* container, GtkWidget* child_widget, gint x,
95 gint y) {
96 MozContainerChild* child;
98 child = g_new(MozContainerChild, 1);
100 child->widget = child_widget;
101 child->x = x;
102 child->y = y;
104 /* printf("moz_container_put %p %p %d %d\n", (void *)container,
105 (void *)child_widget, x, y); */
107 container->data.children = g_list_append(container->data.children, child);
109 /* we assume that the caller of this function will have already set
110 the parent GdkWindow because we can have many anonymous children. */
111 gtk_widget_set_parent(child_widget, GTK_WIDGET(container));
114 static void moz_container_destroy(GtkWidget* widget) {
115 auto* container = MOZ_CONTAINER(widget);
116 if (container->destroyed) {
117 return; // The destroy signal may run multiple times.
119 LOGCONTAINER(("moz_container_destroy() [%p]\n",
120 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget))));
121 container->destroyed = TRUE;
122 container->data.~Data();
125 void moz_container_class_init(MozContainerClass* klass) {
126 /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
127 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
128 GtkContainerClass* container_class = GTK_CONTAINER_CLASS(klass);
129 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
131 widget_class->realize = moz_container_realize;
132 widget_class->unrealize = moz_container_unrealize;
133 widget_class->destroy = moz_container_destroy;
135 #ifdef MOZ_WAYLAND
136 if (mozilla::widget::GdkIsWaylandDisplay()) {
137 widget_class->map = moz_container_wayland_map;
138 widget_class->size_allocate = moz_container_wayland_size_allocate;
139 widget_class->map_event = moz_container_wayland_map_event;
140 } else {
141 #endif
142 widget_class->map = moz_container_map;
143 widget_class->size_allocate = moz_container_size_allocate;
144 #ifdef MOZ_WAYLAND
146 #endif
148 container_class->remove = moz_container_remove;
149 container_class->forall = moz_container_forall;
150 container_class->add = moz_container_add;
153 void moz_container_init(MozContainer* container) {
154 container->destroyed = FALSE;
155 new (&container->data) MozContainer::Data();
156 gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE);
157 gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
158 LOGCONTAINER(("%s [%p]\n", __FUNCTION__,
159 (void*)moz_container_get_nsWindow(container)));
162 void moz_container_map(GtkWidget* widget) {
163 MozContainer* container;
164 GList* tmp_list;
165 GtkWidget* tmp_child;
167 g_return_if_fail(IS_MOZ_CONTAINER(widget));
168 container = MOZ_CONTAINER(widget);
170 LOGCONTAINER(("moz_container_map() [%p]",
171 (void*)moz_container_get_nsWindow(container)));
173 gtk_widget_set_mapped(widget, TRUE);
175 tmp_list = container->data.children;
176 while (tmp_list) {
177 tmp_child = ((MozContainerChild*)tmp_list->data)->widget;
179 if (gtk_widget_get_visible(tmp_child)) {
180 if (!gtk_widget_get_mapped(tmp_child)) gtk_widget_map(tmp_child);
182 tmp_list = tmp_list->next;
185 if (gtk_widget_get_has_window(widget)) {
186 gdk_window_show(gtk_widget_get_window(widget));
190 void moz_container_unmap(GtkWidget* widget) {
191 g_return_if_fail(IS_MOZ_CONTAINER(widget));
193 LOGCONTAINER(("moz_container_unmap() [%p]",
194 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget))));
196 gtk_widget_set_mapped(widget, FALSE);
198 if (gtk_widget_get_has_window(widget)) {
199 gdk_window_hide(gtk_widget_get_window(widget));
203 void moz_container_realize(GtkWidget* widget) {
204 GdkWindow* parent = gtk_widget_get_parent_window(widget);
205 GdkWindow* window;
207 gtk_widget_set_realized(widget, TRUE);
209 GdkWindowAttr attributes;
210 gint attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y;
211 GtkAllocation allocation;
213 gtk_widget_get_allocation(widget, &allocation);
214 attributes.event_mask = gtk_widget_get_events(widget);
215 attributes.x = allocation.x;
216 attributes.y = allocation.y;
217 attributes.width = allocation.width;
218 attributes.height = allocation.height;
219 attributes.wclass = GDK_INPUT_OUTPUT;
220 attributes.window_type = GDK_WINDOW_CHILD;
221 MozContainer* container = MOZ_CONTAINER(widget);
222 attributes.visual =
223 container->data.force_default_visual
224 ? gdk_screen_get_system_visual(gtk_widget_get_screen(widget))
225 : gtk_widget_get_visual(widget);
227 window = gdk_window_new(parent, &attributes, attributes_mask);
229 LOGCONTAINER(("moz_container_realize() [%p] GdkWindow %p\n",
230 (void*)moz_container_get_nsWindow(container), (void*)window));
232 gtk_widget_register_window(widget, window);
233 gtk_widget_set_window(widget, window);
236 void moz_container_unrealize(GtkWidget* widget) {
237 GdkWindow* window = gtk_widget_get_window(widget);
238 LOGCONTAINER(("moz_container_unrealize() [%p] GdkWindow %p\n",
239 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)),
240 (void*)window));
242 gtk_widget_unregister_window(widget, window);
243 gtk_widget_set_window(widget, nullptr);
244 gdk_window_destroy(window);
245 gtk_widget_set_realized(widget, false);
248 void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation) {
249 MozContainer* container;
250 GList* tmp_list;
251 GtkAllocation tmp_allocation;
253 g_return_if_fail(IS_MOZ_CONTAINER(widget));
255 LOGCONTAINER(("moz_container_size_allocate [%p] %d,%d -> %d x %d\n",
256 (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)),
257 allocation->x, allocation->y, allocation->width,
258 allocation->height));
260 /* short circuit if you can */
261 container = MOZ_CONTAINER(widget);
262 gtk_widget_get_allocation(widget, &tmp_allocation);
263 if (!container->data.children && tmp_allocation.x == allocation->x &&
264 tmp_allocation.y == allocation->y &&
265 tmp_allocation.width == allocation->width &&
266 tmp_allocation.height == allocation->height) {
267 return;
270 gtk_widget_set_allocation(widget, allocation);
272 tmp_list = container->data.children;
274 while (tmp_list) {
275 MozContainerChild* child = static_cast<MozContainerChild*>(tmp_list->data);
277 moz_container_allocate_child(container, child);
279 tmp_list = tmp_list->next;
282 if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
283 gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x,
284 allocation->y, allocation->width,
285 allocation->height);
289 void moz_container_remove(GtkContainer* container, GtkWidget* child_widget) {
290 MozContainerChild* child;
291 MozContainer* moz_container;
292 GdkWindow* parent_window;
294 g_return_if_fail(IS_MOZ_CONTAINER(container));
295 g_return_if_fail(GTK_IS_WIDGET(child_widget));
297 moz_container = MOZ_CONTAINER(container);
299 child = moz_container_get_child(moz_container, child_widget);
300 g_return_if_fail(child);
302 /* gtk_widget_unparent will remove the parent window (as well as the
303 * parent widget), but, in Mozilla's window hierarchy, the parent window
304 * may need to be kept because it may be part of a GdkWindow sub-hierarchy
305 * that is being moved to another MozContainer.
307 * (In a conventional GtkWidget hierarchy, GdkWindows being reparented
308 * would have their own GtkWidget and that widget would be the one being
309 * reparented. In Mozilla's hierarchy, the parent_window needs to be
310 * retained so that the GdkWindow sub-hierarchy is maintained.)
312 parent_window = gtk_widget_get_parent_window(child_widget);
313 if (parent_window) g_object_ref(parent_window);
315 gtk_widget_unparent(child_widget);
317 if (parent_window) {
318 /* The child_widget will always still exist because g_signal_emit,
319 * which invokes this function, holds a reference.
321 * If parent_window is the container's root window then it will not be
322 * the parent_window if the child_widget is placed in another
323 * container.
325 if (parent_window != gtk_widget_get_window(GTK_WIDGET(container))) {
326 gtk_widget_set_parent_window(child_widget, parent_window);
329 g_object_unref(parent_window);
332 moz_container->data.children =
333 g_list_remove(moz_container->data.children, child);
334 g_free(child);
337 void moz_container_forall(GtkContainer* container, gboolean include_internals,
338 GtkCallback callback, gpointer callback_data) {
339 g_return_if_fail(IS_MOZ_CONTAINER(container));
340 g_return_if_fail(callback);
342 MozContainer* moz_container = MOZ_CONTAINER(container);
344 GList* tmp_list = moz_container->data.children;
345 while (tmp_list) {
346 MozContainerChild* child;
347 child = static_cast<MozContainerChild*>(tmp_list->data);
348 tmp_list = tmp_list->next;
349 (*callback)(child->widget, callback_data);
353 static void moz_container_allocate_child(MozContainer* container,
354 MozContainerChild* child) {
355 GtkAllocation allocation;
357 gtk_widget_get_allocation(child->widget, &allocation);
358 allocation.x = child->x;
359 allocation.y = child->y;
361 gtk_widget_size_allocate(child->widget, &allocation);
364 MozContainerChild* moz_container_get_child(MozContainer* container,
365 GtkWidget* child_widget) {
366 GList* tmp_list = container->data.children;
367 while (tmp_list) {
368 MozContainerChild* child;
370 child = static_cast<MozContainerChild*>(tmp_list->data);
371 tmp_list = tmp_list->next;
373 if (child->widget == child_widget) return child;
375 return nullptr;
378 static void moz_container_add(GtkContainer* container, GtkWidget* widget) {
379 moz_container_put(MOZ_CONTAINER(container), widget, 0, 0);
382 void moz_container_force_default_visual(MozContainer* container) {
383 container->data.force_default_visual = true;
386 nsWindow* moz_container_get_nsWindow(MozContainer* container) {
387 gpointer user_data = g_object_get_data(G_OBJECT(container), "nsWindow");
388 return static_cast<nsWindow*>(user_data);
391 #undef LOGCONTAINER