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