1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
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"
13 #include "mozilla/WidgetUtilsGtk.h"
16 # include "mozilla/Logging.h"
17 # include "nsTArray.h"
19 extern mozilla::LazyLogModule gWidgetLog
;
20 # define LOGCONTAINER(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
22 # define LOGCONTAINER(args)
23 #endif /* MOZ_LOGGING */
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
{
53 static void moz_container_allocate_child(MozContainer
* container
,
54 MozContainerChild
* child
);
55 static MozContainerChild
* moz_container_get_child(MozContainer
* container
,
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 */
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 */
73 (GInstanceInitFunc
)moz_container_init
, /* instance_init */
74 NULL
, /* value_table */
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
;
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
,
96 MozContainerChild
* child
;
98 child
= g_new(MozContainerChild
, 1);
100 child
->widget
= child_widget
;
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
;
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
;
142 widget_class
->map
= moz_container_map
;
143 widget_class
->size_allocate
= moz_container_size_allocate
;
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
;
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
;
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
);
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
);
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
)),
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
;
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
) {
270 gtk_widget_set_allocation(widget
, allocation
);
272 tmp_list
= container
->data
.children
;
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
,
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
);
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
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
);
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
;
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
;
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
;
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
);