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