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