]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/win_gtk.c
(failed) attempts at fixing menu bar swapping
[wxWidgets.git] / src / gtk1 / win_gtk.c
CommitLineData
c67daf87 1/* ///////////////////////////////////////////////////////////////////////////
c67d8618 2// Name: win_gtk.c
ed673c6a
RR
3// Purpose: Native GTK+ widget for wxWindows, based on GtkLayout and
4// GtkFixed. It makes use of the gravity window property and
5// therefore does not work with GTK 1.0.
c801d85f 6// Author: Robert Roebling
c67d8618 7// Id: $Id$
01111366 8// Copyright: (c) 1998 Robert Roebling
bf3dab48 9// Licence: wxWindows licence
c67daf87 10/////////////////////////////////////////////////////////////////////////// */
c801d85f
KB
11
12#include "wx/gtk/win_gtk.h"
3fa056ab
JJ
13#ifdef __VMS
14#define gtk_widget_get_child_requisition gtk_widget_get_child_requisitio
15#define gtk_marshal_NONE__POINTER_POINTER gtk_marshal_NONE__POINTER_POINT
16#endif
034be888 17#include "gtk/gtksignal.h"
ed673c6a
RR
18#include "gtk/gtkprivate.h"
19#include "gdk/gdkx.h"
38c7b3d3 20
c801d85f
KB
21#ifdef __cplusplus
22extern "C" {
23#endif /* __cplusplus */
24
c916e13b
RR
25#include <X11/Xlib.h>
26#include <X11/Xutil.h>
27#include <X11/Xatom.h>
28
ed673c6a
RR
29#define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \
30 (y >= G_MINSHORT) && (y <= G_MAXSHORT))
31
da048e3d 32typedef struct _GtkPizzaAdjData GtkPizzaAdjData;
ed673c6a 33
bf3dab48 34struct _GtkPizzaAdjData
ed673c6a
RR
35{
36 gint dx;
37 gint dy;
38};
39
b6fa52db
RR
40static void gtk_pizza_class_init (GtkPizzaClass *klass);
41static void gtk_pizza_init (GtkPizza *pizza);
ed673c6a 42
b6fa52db
RR
43static void gtk_pizza_realize (GtkWidget *widget);
44static void gtk_pizza_unrealize (GtkWidget *widget);
ed673c6a 45
b6fa52db 46static void gtk_pizza_map (GtkWidget *widget);
ed673c6a 47
da048e3d 48static void gtk_pizza_size_request (GtkWidget *widget,
bf3dab48 49 GtkRequisition *requisition);
da048e3d 50static void gtk_pizza_size_allocate (GtkWidget *widget,
bf3dab48 51 GtkAllocation *allocation);
da048e3d 52static void gtk_pizza_draw (GtkWidget *widget,
bf3dab48 53 GdkRectangle *area);
da048e3d 54static gint gtk_pizza_expose (GtkWidget *widget,
bf3dab48 55 GdkEventExpose *event);
da048e3d 56static void gtk_pizza_add (GtkContainer *container,
bf3dab48 57 GtkWidget *widget);
da048e3d 58static void gtk_pizza_remove (GtkContainer *container,
bf3dab48 59 GtkWidget *widget);
b6fa52db
RR
60static void gtk_pizza_forall (GtkContainer *container,
61 gboolean include_internals,
62 GtkCallback callback,
63 gpointer callback_data);
ed673c6a 64
da048e3d 65static void gtk_pizza_position_child (GtkPizza *pizza,
b6fa52db 66 GtkPizzaChild *child);
da048e3d 67static void gtk_pizza_allocate_child (GtkPizza *pizza,
b6fa52db 68 GtkPizzaChild *child);
da048e3d 69static void gtk_pizza_position_children (GtkPizza *pizza);
ed673c6a 70
da048e3d 71static void gtk_pizza_adjust_allocations_recurse (GtkWidget *widget,
b6fa52db
RR
72 gpointer cb_data);
73static void gtk_pizza_adjust_allocations (GtkPizza *pizza,
74 gint dx,
75 gint dy);
ed673c6a
RR
76
77
b6fa52db
RR
78static void gtk_pizza_expose_area (GtkPizza *pizza,
79 gint x,
80 gint y,
81 gint width,
82 gint height);
da048e3d 83static void gtk_pizza_adjustment_changed (GtkAdjustment *adjustment,
b6fa52db 84 GtkPizza *pizza);
da048e3d 85static GdkFilterReturn gtk_pizza_filter (GdkXEvent *gdk_xevent,
b6fa52db
RR
86 GdkEvent *event,
87 gpointer data);
da048e3d 88static GdkFilterReturn gtk_pizza_main_filter (GdkXEvent *gdk_xevent,
b6fa52db
RR
89 GdkEvent *event,
90 gpointer data);
ed673c6a
RR
91
92
da048e3d 93static GtkType gtk_pizza_child_type (GtkContainer *container);
c801d85f 94
b6fa52db 95static void gtk_pizza_scroll_set_adjustments (GtkPizza *pizza,
bf3dab48
VZ
96 GtkAdjustment *hadj,
97 GtkAdjustment *vadj);
c801d85f
KB
98
99
034be888 100static GtkContainerClass *parent_class = NULL;
ed673c6a 101static gboolean gravity_works;
034be888 102
c801d85f 103guint
da048e3d 104gtk_pizza_get_type ()
c801d85f 105{
da048e3d 106 static guint pizza_type = 0;
c801d85f 107
da048e3d 108 if (!pizza_type)
c801d85f 109 {
da048e3d 110 GtkTypeInfo pizza_info =
053f9cc1 111 {
bf3dab48
VZ
112 "GtkPizza",
113 sizeof (GtkPizza),
114 sizeof (GtkPizzaClass),
115 (GtkClassInitFunc) gtk_pizza_class_init,
116 (GtkObjectInitFunc) gtk_pizza_init,
117 /* reserved_1 */ NULL,
053f9cc1
RR
118 /* reserved_2 */ NULL,
119 (GtkClassInitFunc) NULL,
053f9cc1 120 };
da048e3d 121 pizza_type = gtk_type_unique (gtk_container_get_type (), &pizza_info);
c801d85f 122 }
bf3dab48 123
da048e3d 124 return pizza_type;
c801d85f
KB
125}
126
127static void
da048e3d 128gtk_pizza_class_init (GtkPizzaClass *klass)
c801d85f 129{
053f9cc1
RR
130 GtkObjectClass *object_class;
131 GtkWidgetClass *widget_class;
132 GtkContainerClass *container_class;
c801d85f 133
053f9cc1
RR
134 object_class = (GtkObjectClass*) klass;
135 widget_class = (GtkWidgetClass*) klass;
136 container_class = (GtkContainerClass*) klass;
053f9cc1 137 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
c801d85f 138
da048e3d
RR
139 widget_class->map = gtk_pizza_map;
140 widget_class->realize = gtk_pizza_realize;
141 widget_class->unrealize = gtk_pizza_unrealize;
142 widget_class->size_request = gtk_pizza_size_request;
143 widget_class->size_allocate = gtk_pizza_size_allocate;
144 widget_class->draw = gtk_pizza_draw;
145 widget_class->expose_event = gtk_pizza_expose;
053f9cc1 146
da048e3d
RR
147 container_class->add = gtk_pizza_add;
148 container_class->remove = gtk_pizza_remove;
149 container_class->forall = gtk_pizza_forall;
38c7b3d3 150
da048e3d 151 container_class->child_type = gtk_pizza_child_type;
034be888 152
da048e3d 153 klass->set_scroll_adjustments = gtk_pizza_scroll_set_adjustments;
034be888 154
053f9cc1 155 widget_class->set_scroll_adjustments_signal =
034be888 156 gtk_signal_new ("set_scroll_adjustments",
bf3dab48
VZ
157 GTK_RUN_LAST,
158 object_class->type,
159 GTK_SIGNAL_OFFSET (GtkPizzaClass, set_scroll_adjustments),
160 gtk_marshal_NONE__POINTER_POINTER,
161 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
38c7b3d3
RR
162}
163
38c7b3d3 164static GtkType
da048e3d 165gtk_pizza_child_type (GtkContainer *container)
38c7b3d3 166{
053f9cc1 167 return GTK_TYPE_WIDGET;
c801d85f
KB
168}
169
170static void
da048e3d 171gtk_pizza_init (GtkPizza *pizza)
c801d85f 172{
da048e3d 173 GTK_WIDGET_UNSET_FLAGS (pizza, GTK_NO_WINDOW);
bf3dab48 174
da048e3d 175 pizza->shadow_type = GTK_MYSHADOW_NONE;
034be888 176
da048e3d 177 pizza->children = NULL;
bf3dab48 178
da048e3d
RR
179 pizza->width = 20;
180 pizza->height = 20;
ed673c6a 181
da048e3d 182 pizza->bin_window = NULL;
8e217128
RR
183
184 pizza->xoffset = 0;
185 pizza->yoffset = 0;
ed673c6a 186
da048e3d
RR
187 pizza->configure_serial = 0;
188 pizza->scroll_x = 0;
189 pizza->scroll_y = 0;
190 pizza->visibility = GDK_VISIBILITY_PARTIAL;
bf3dab48 191
da048e3d 192 pizza->clear_on_draw = TRUE;
b6fa52db 193 pizza->use_filter = TRUE;
c801d85f
KB
194}
195
196GtkWidget*
da048e3d 197gtk_pizza_new ()
c801d85f 198{
da048e3d 199 GtkPizza *pizza;
c801d85f 200
da048e3d 201 pizza = gtk_type_new (gtk_pizza_get_type ());
bf3dab48 202
da048e3d 203 return GTK_WIDGET (pizza);
c801d85f
KB
204}
205
bf3dab48 206static void
da048e3d 207gtk_pizza_scroll_set_adjustments (GtkPizza *pizza,
bf3dab48
VZ
208 GtkAdjustment *hadj,
209 GtkAdjustment *vadj)
034be888 210{
ed673c6a 211 /* We handle scrolling in the wxScrolledWindow, not here. */
034be888
RR
212}
213
bf3dab48 214void
b6fa52db 215gtk_pizza_set_shadow_type (GtkPizza *pizza,
0e09f76e 216 GtkMyShadowType type)
034be888 217{
da048e3d
RR
218 g_return_if_fail (pizza != NULL);
219 g_return_if_fail (GTK_IS_PIZZA (pizza));
034be888 220
da048e3d 221 if ((GtkMyShadowType) pizza->shadow_type != type)
034be888 222 {
da048e3d 223 pizza->shadow_type = type;
034be888 224
da048e3d 225 if (GTK_WIDGET_VISIBLE (pizza))
bf3dab48
VZ
226 {
227 gtk_widget_size_allocate (GTK_WIDGET (pizza), &(GTK_WIDGET (pizza)->allocation));
228 gtk_widget_queue_draw (GTK_WIDGET (pizza));
229 }
034be888
RR
230 }
231}
034be888 232
bf3dab48 233void
b6fa52db
RR
234gtk_pizza_set_clear (GtkPizza *pizza,
235 gboolean clear)
147bc491 236{
da048e3d
RR
237 g_return_if_fail (pizza != NULL);
238 g_return_if_fail (GTK_IS_PIZZA (pizza));
bf3dab48 239
da048e3d 240 pizza->clear_on_draw = clear;
bf3dab48
VZ
241}
242
0e09f76e 243void
b6fa52db
RR
244gtk_pizza_set_filter (GtkPizza *pizza,
245 gboolean use)
0e09f76e
RR
246{
247 g_return_if_fail (pizza != NULL);
248 g_return_if_fail (GTK_IS_PIZZA (pizza));
249
250 pizza->use_filter = use;
251}
252
c801d85f 253void
b6fa52db
RR
254gtk_pizza_put (GtkPizza *pizza,
255 GtkWidget *widget,
256 gint x,
257 gint y,
258 gint width,
259 gint height)
c801d85f 260{
da048e3d 261 GtkPizzaChild *child_info;
053f9cc1 262
da048e3d
RR
263 g_return_if_fail (pizza != NULL);
264 g_return_if_fail (GTK_IS_PIZZA (pizza));
053f9cc1
RR
265 g_return_if_fail (widget != NULL);
266
da048e3d 267 child_info = g_new (GtkPizzaChild, 1);
bf3dab48 268
053f9cc1
RR
269 child_info->widget = widget;
270 child_info->x = x;
271 child_info->y = y;
272 child_info->width = width;
273 child_info->height = height;
bf3dab48
VZ
274
275 pizza->children = g_list_append (pizza->children, child_info);
ed673c6a 276
da048e3d 277 gtk_widget_set_parent (widget, GTK_WIDGET (pizza));
c801d85f 278
da048e3d
RR
279 if (GTK_WIDGET_REALIZED (pizza))
280 gtk_widget_set_parent_window (widget, pizza->bin_window);
bf3dab48 281
ed673c6a
RR
282 if (!IS_ONSCREEN (x, y))
283 GTK_PRIVATE_SET_FLAG (widget, GTK_IS_OFFSCREEN);
c801d85f 284
0e09f76e 285/*
da048e3d 286 if (GTK_WIDGET_REALIZED (pizza))
053f9cc1 287 gtk_widget_realize (widget);
0e09f76e 288*/
c801d85f 289
ed673c6a 290 gtk_widget_set_usize (widget, width, height);
bf3dab48 291
0e09f76e 292/*
da048e3d 293 if (GTK_WIDGET_VISIBLE (pizza) && GTK_WIDGET_VISIBLE (widget))
326f9654 294 {
da048e3d 295 if (GTK_WIDGET_MAPPED (pizza))
bf3dab48
VZ
296 gtk_widget_map (widget);
297
ed673c6a 298 gtk_widget_queue_resize (widget);
326f9654 299 }
0e09f76e 300*/
c801d85f
KB
301}
302
303void
b6fa52db
RR
304gtk_pizza_move (GtkPizza *pizza,
305 GtkWidget *widget,
306 gint x,
307 gint y)
c801d85f 308{
da048e3d 309 GtkPizzaChild *child;
053f9cc1 310 GList *children;
c801d85f 311
da048e3d
RR
312 g_return_if_fail (pizza != NULL);
313 g_return_if_fail (GTK_IS_PIZZA (pizza));
053f9cc1 314 g_return_if_fail (widget != NULL);
c801d85f 315
da048e3d 316 children = pizza->children;
053f9cc1 317 while (children)
fdd3ed7a 318 {
053f9cc1
RR
319 child = children->data;
320 children = children->next;
bf3dab48 321
053f9cc1 322 if (child->widget == widget)
fdd3ed7a 323 {
bf3dab48
VZ
324 if ((child->x == x) && (child->y == y))
325 break;
326
ed673c6a
RR
327 child->x = x;
328 child->y = y;
bf3dab48
VZ
329
330 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (pizza))
331 gtk_widget_queue_resize (widget);
332 break;
333 }
fdd3ed7a
RR
334 }
335}
336
337void
b6fa52db
RR
338gtk_pizza_resize (GtkPizza *pizza,
339 GtkWidget *widget,
340 gint width,
341 gint height)
fdd3ed7a 342{
da048e3d 343 GtkPizzaChild *child;
053f9cc1 344 GList *children;
fdd3ed7a 345
da048e3d
RR
346 g_return_if_fail (pizza != NULL);
347 g_return_if_fail (GTK_IS_PIZZA (pizza));
053f9cc1 348 g_return_if_fail (widget != NULL);
fdd3ed7a 349
da048e3d 350 children = pizza->children;
053f9cc1 351 while (children)
fdd3ed7a 352 {
053f9cc1
RR
353 child = children->data;
354 children = children->next;
bf3dab48 355
053f9cc1 356 if (child->widget == widget)
fdd3ed7a 357 {
bf3dab48
VZ
358 if ((child->width == width) && (child->height == height))
359 break;
360
ed673c6a
RR
361 child->width = width;
362 child->height = height;
bf3dab48
VZ
363
364 gtk_widget_set_usize (widget, width, height);
365
da048e3d 366 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (pizza))
bf3dab48
VZ
367 gtk_widget_queue_resize (widget);
368 break;
369 }
fdd3ed7a
RR
370 }
371}
372
373void
b6fa52db
RR
374gtk_pizza_set_size (GtkPizza *pizza,
375 GtkWidget *widget,
376 gint x,
377 gint y,
378 gint width,
379 gint height)
fdd3ed7a 380{
da048e3d 381 GtkPizzaChild *child;
053f9cc1 382 GList *children;
fdd3ed7a 383
da048e3d
RR
384 g_return_if_fail (pizza != NULL);
385 g_return_if_fail (GTK_IS_PIZZA (pizza));
053f9cc1 386 g_return_if_fail (widget != NULL);
fdd3ed7a 387
da048e3d 388 children = pizza->children;
053f9cc1 389 while (children)
c801d85f 390 {
053f9cc1
RR
391 child = children->data;
392 children = children->next;
c801d85f 393
053f9cc1 394 if (child->widget == widget)
c801d85f 395 {
bf3dab48
VZ
396 if ((child->x == x) &&
397 (child->y == y) &&
398 (child->width == width) &&
399 (child->height == height)) return;
400
053f9cc1
RR
401 child->x = x;
402 child->y = y;
403 child->width = width;
404 child->height = height;
bf3dab48
VZ
405
406 gtk_widget_set_usize (widget, width, height);
407
da048e3d 408 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (pizza))
bf3dab48
VZ
409 gtk_widget_queue_resize (widget);
410
6d693bb4 411 return;
c801d85f
KB
412 }
413 }
414}
415
416static void
da048e3d 417gtk_pizza_map (GtkWidget *widget)
c801d85f 418{
da048e3d
RR
419 GtkPizza *pizza;
420 GtkPizzaChild *child;
053f9cc1 421 GList *children;
c801d85f 422
053f9cc1 423 g_return_if_fail (widget != NULL);
da048e3d 424 g_return_if_fail (GTK_IS_PIZZA (widget));
c801d85f 425
053f9cc1 426 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
da048e3d 427 pizza = GTK_PIZZA (widget);
c801d85f 428
da048e3d 429 children = pizza->children;
053f9cc1 430 while (children)
c801d85f 431 {
053f9cc1
RR
432 child = children->data;
433 children = children->next;
c801d85f 434
bf3dab48
VZ
435 if ( GTK_WIDGET_VISIBLE (child->widget) &&
436 !GTK_WIDGET_MAPPED (child->widget) &&
437 !GTK_WIDGET_IS_OFFSCREEN (child->widget))
438 {
439 gtk_widget_map (child->widget);
440 }
c801d85f 441 }
bf3dab48 442
053f9cc1 443 gdk_window_show (widget->window);
da048e3d 444 gdk_window_show (pizza->bin_window);
c801d85f
KB
445}
446
c801d85f 447static void
da048e3d 448gtk_pizza_realize (GtkWidget *widget)
c801d85f 449{
da048e3d 450 GtkPizza *pizza;
053f9cc1
RR
451 GdkWindowAttr attributes;
452 gint attributes_mask;
da048e3d 453 GtkPizzaChild *child;
ed673c6a 454 GList *children;
c801d85f 455
053f9cc1 456 g_return_if_fail (widget != NULL);
da048e3d 457 g_return_if_fail (GTK_IS_PIZZA (widget));
c801d85f 458
da048e3d 459 pizza = GTK_PIZZA (widget);
bf3dab48 460
053f9cc1 461 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
c801d85f 462
053f9cc1 463 attributes.window_type = GDK_WINDOW_CHILD;
bf3dab48 464
053f9cc1
RR
465 attributes.x = widget->allocation.x;
466 attributes.y = widget->allocation.y;
467 attributes.width = widget->allocation.width;
468 attributes.height = widget->allocation.height;
469
da048e3d 470 if (pizza->shadow_type == GTK_MYSHADOW_NONE)
053f9cc1 471 {
5e014a0c
RR
472 /* no border, no changes to sizes */
473 } else
da048e3d 474 if (pizza->shadow_type == GTK_MYSHADOW_THIN)
5e014a0c
RR
475 {
476 /* GTK_MYSHADOW_THIN == wxSIMPLE_BORDER */
477 attributes.x += 1;
478 attributes.y += 1;
479 attributes.width -= 2;
480 attributes.height -= 2;
481 } else
482 {
483 /* GTK_MYSHADOW_IN == wxSUNKEN_BORDER */
484 /* GTK_MYSHADOW_OUT == wxRAISED_BORDER */
053f9cc1
RR
485 attributes.x += 2;
486 attributes.y += 2;
487 attributes.width -= 4;
488 attributes.height -= 4;
489 }
bf3dab48 490
ed673c6a 491 /* minimal size */
053f9cc1
RR
492 if (attributes.width < 2) attributes.width = 2;
493 if (attributes.height < 2) attributes.height = 2;
bf3dab48 494
053f9cc1
RR
495 attributes.wclass = GDK_INPUT_OUTPUT;
496 attributes.visual = gtk_widget_get_visual (widget);
497 attributes.colormap = gtk_widget_get_colormap (widget);
bf3dab48 498 attributes.event_mask =
ed673c6a
RR
499 GDK_VISIBILITY_NOTIFY_MASK;
500 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
bf3dab48 501
c916e13b 502 widget->window = gdk_window_new(gtk_widget_get_parent_window (widget),
bf3dab48 503 &attributes, attributes_mask);
ed673c6a
RR
504 gdk_window_set_user_data (widget->window, widget);
505
506 attributes.x = 0;
507 attributes.y = 0;
bf3dab48 508
053f9cc1 509 attributes.event_mask = gtk_widget_get_events (widget);
bf3dab48
VZ
510 attributes.event_mask |=
511 GDK_EXPOSURE_MASK |
512 GDK_POINTER_MOTION_MASK |
053f9cc1 513 GDK_POINTER_MOTION_HINT_MASK |
bf3dab48
VZ
514 GDK_BUTTON_MOTION_MASK |
515 GDK_BUTTON1_MOTION_MASK |
516 GDK_BUTTON2_MOTION_MASK |
517 GDK_BUTTON3_MOTION_MASK |
518 GDK_BUTTON_PRESS_MASK |
519 GDK_BUTTON_RELEASE_MASK |
520 GDK_KEY_PRESS_MASK |
521 GDK_KEY_RELEASE_MASK |
522 GDK_ENTER_NOTIFY_MASK |
523 GDK_LEAVE_NOTIFY_MASK |
053f9cc1 524 GDK_FOCUS_CHANGE_MASK;
053f9cc1 525
c916e13b 526 pizza->bin_window = gdk_window_new(widget->window,
bf3dab48 527 &attributes, attributes_mask);
da048e3d 528 gdk_window_set_user_data (pizza->bin_window, widget);
bf3dab48 529
053f9cc1
RR
530 widget->style = gtk_style_attach (widget->style, widget->window);
531 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
b6fa52db 532 gtk_style_set_background (widget->style, pizza->bin_window, GTK_STATE_NORMAL );
bf3dab48 533
ed673c6a 534 /* add filters for intercepting visibility and expose events */
da048e3d
RR
535 gdk_window_add_filter (widget->window, gtk_pizza_main_filter, pizza);
536 gdk_window_add_filter (pizza->bin_window, gtk_pizza_filter, pizza);
ed673c6a
RR
537
538 /* we NEED gravity or we'll give up */
da048e3d 539 gravity_works = gdk_window_set_static_gravities (pizza->bin_window, TRUE);
ed673c6a
RR
540
541 /* cannot be done before realisation */
da048e3d 542 children = pizza->children;
ed673c6a
RR
543 while (children)
544 {
545 child = children->data;
546 children = children->next;
547
da048e3d 548 gtk_widget_set_parent_window (child->widget, pizza->bin_window);
ed673c6a
RR
549 }
550}
551
bf3dab48 552static void
da048e3d 553gtk_pizza_unrealize (GtkWidget *widget)
ed673c6a 554{
da048e3d 555 GtkPizza *pizza;
ed673c6a
RR
556
557 g_return_if_fail (widget != NULL);
da048e3d 558 g_return_if_fail (GTK_IS_PIZZA (widget));
ed673c6a 559
da048e3d 560 pizza = GTK_PIZZA (widget);
ed673c6a 561
da048e3d
RR
562 gdk_window_set_user_data (pizza->bin_window, NULL);
563 gdk_window_destroy (pizza->bin_window);
564 pizza->bin_window = NULL;
ed673c6a
RR
565
566 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
567 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
c801d85f
KB
568}
569
570static void
da048e3d 571gtk_pizza_size_request (GtkWidget *widget,
b6fa52db 572 GtkRequisition *requisition)
c801d85f 573{
da048e3d
RR
574 GtkPizza *pizza;
575 GtkPizzaChild *child;
053f9cc1
RR
576 GList *children;
577 GtkRequisition child_requisition;
bf3dab48 578
053f9cc1 579 g_return_if_fail (widget != NULL);
da048e3d 580 g_return_if_fail (GTK_IS_PIZZA (widget));
053f9cc1 581 g_return_if_fail (requisition != NULL);
c801d85f 582
da048e3d 583 pizza = GTK_PIZZA (widget);
bf3dab48 584
da048e3d 585 children = pizza->children;
053f9cc1 586 while (children)
c801d85f 587 {
053f9cc1
RR
588 child = children->data;
589 children = children->next;
c801d85f 590
053f9cc1 591 if (GTK_WIDGET_VISIBLE (child->widget))
bf3dab48 592 {
053f9cc1 593 gtk_widget_size_request (child->widget, &child_requisition);
bf3dab48 594 }
c801d85f 595 }
bf3dab48 596
053f9cc1
RR
597 /* request very little, I'm not sure if requesting nothing
598 will always have positive effects on stability... */
599 requisition->width = 2;
600 requisition->height = 2;
c801d85f
KB
601}
602
603static void
da048e3d 604gtk_pizza_size_allocate (GtkWidget *widget,
b6fa52db 605 GtkAllocation *allocation)
c801d85f 606{
da048e3d 607 GtkPizza *pizza;
053f9cc1 608 gint border;
ed673c6a 609 gint x,y,w,h;
da048e3d 610 GtkPizzaChild *child;
ed673c6a 611 GList *children;
c801d85f 612
053f9cc1 613 g_return_if_fail (widget != NULL);
da048e3d 614 g_return_if_fail (GTK_IS_PIZZA(widget));
053f9cc1 615 g_return_if_fail (allocation != NULL);
c801d85f 616
da048e3d 617 pizza = GTK_PIZZA (widget);
bf3dab48 618
227e5e99 619 widget->allocation = *allocation;
bf3dab48 620
da048e3d 621 if (pizza->shadow_type == GTK_MYSHADOW_NONE)
053f9cc1 622 border = 0;
5e014a0c 623 else
da048e3d 624 if (pizza->shadow_type == GTK_MYSHADOW_THIN)
5e014a0c 625 border = 1;
053f9cc1
RR
626 else
627 border = 2;
bf3dab48 628
ed673c6a
RR
629 x = allocation->x + border;
630 y = allocation->y + border;
631 w = allocation->width - border*2;
632 h = allocation->height - border*2;
034be888 633
053f9cc1
RR
634 if (GTK_WIDGET_REALIZED (widget))
635 {
ed673c6a 636 gdk_window_move_resize( widget->window, x, y, w, h );
da048e3d 637 gdk_window_move_resize( pizza->bin_window, 0, 0, w, h );
053f9cc1 638 }
bf3dab48 639
da048e3d 640 children = pizza->children;
6d693bb4
RR
641 while (children)
642 {
643 child = children->data;
644 children = children->next;
bf3dab48 645
da048e3d
RR
646 gtk_pizza_position_child (pizza, child);
647 gtk_pizza_allocate_child (pizza, child);
6d693bb4 648 }
c801d85f
KB
649}
650
651static void
da048e3d 652gtk_pizza_draw (GtkWidget *widget,
b6fa52db 653 GdkRectangle *area)
c801d85f 654{
b6fa52db
RR
655 /* We handle all draws events in window.cpp now. */
656 return;
c801d85f
KB
657}
658
c801d85f 659static gint
da048e3d 660gtk_pizza_expose (GtkWidget *widget,
b6fa52db 661 GdkEventExpose *event)
c801d85f 662{
b6fa52db 663 /* We handle all expose events in window.cpp now. */
ed673c6a 664 return FALSE;
c801d85f
KB
665}
666
667static void
da048e3d 668gtk_pizza_add (GtkContainer *container,
bf3dab48 669 GtkWidget *widget)
c801d85f 670{
ed673c6a 671 g_return_if_fail (container != NULL);
da048e3d 672 g_return_if_fail (GTK_IS_PIZZA (container));
ed673c6a 673 g_return_if_fail (widget != NULL);
c801d85f 674
da048e3d 675 gtk_pizza_put (GTK_PIZZA (container), widget, 0, 0, 20, 20 );
c801d85f
KB
676}
677
678static void
da048e3d 679gtk_pizza_remove (GtkContainer *container,
b6fa52db 680 GtkWidget *widget)
c801d85f 681{
da048e3d
RR
682 GtkPizza *pizza;
683 GtkPizzaChild *child;
ed673c6a 684 GList *children;
c801d85f 685
ed673c6a 686 g_return_if_fail (container != NULL);
da048e3d 687 g_return_if_fail (GTK_IS_PIZZA (container));
ed673c6a 688 g_return_if_fail (widget != NULL);
c801d85f 689
da048e3d 690 pizza = GTK_PIZZA (container);
c801d85f 691
da048e3d 692 children = pizza->children;
ed673c6a 693 while (children)
c801d85f 694 {
ed673c6a 695 child = children->data;
c801d85f 696
ed673c6a 697 if (child->widget == widget)
bf3dab48
VZ
698 {
699 gtk_widget_unparent (widget);
c801d85f 700
ed673c6a
RR
701 /* security checks */
702 g_return_if_fail (GTK_IS_WIDGET (widget));
bf3dab48
VZ
703
704 pizza->children = g_list_remove_link (pizza->children, children);
705 g_list_free (children);
706 g_free (child);
c801d85f 707
ed673c6a 708 /* security checks */
bf3dab48
VZ
709 g_return_if_fail (GTK_IS_WIDGET (widget));
710
ed673c6a 711 GTK_PRIVATE_UNSET_FLAG (widget, GTK_IS_OFFSCREEN);
bf3dab48
VZ
712
713 break;
714 }
c801d85f 715
ed673c6a 716 children = children->next;
c801d85f
KB
717 }
718}
719
720static void
da048e3d 721gtk_pizza_forall (GtkContainer *container,
b6fa52db
RR
722 gboolean include_internals,
723 GtkCallback callback,
724 gpointer callback_data)
c801d85f 725{
da048e3d
RR
726 GtkPizza *pizza;
727 GtkPizzaChild *child;
6d693bb4 728 GList *children;
c801d85f 729
6d693bb4 730 g_return_if_fail (container != NULL);
da048e3d 731 g_return_if_fail (GTK_IS_PIZZA (container));
6d693bb4 732 g_return_if_fail (callback != NULL);
c801d85f 733
da048e3d 734 pizza = GTK_PIZZA (container);
c801d85f 735
da048e3d 736 children = pizza->children;
6d693bb4 737 while (children)
c801d85f 738 {
6d693bb4
RR
739 child = children->data;
740 children = children->next;
c801d85f 741
6d693bb4 742 (* callback) (child->widget, callback_data);
c801d85f
KB
743 }
744}
745
746
ed673c6a
RR
747/* Operations on children
748 */
749
750static void
da048e3d 751gtk_pizza_position_child (GtkPizza *pizza,
b6fa52db 752 GtkPizzaChild *child)
ed673c6a 753{
6d693bb4
RR
754 gint x;
755 gint y;
ed673c6a 756
da048e3d
RR
757 x = child->x - pizza->xoffset;
758 y = child->y - pizza->yoffset;
ed673c6a 759
6d693bb4 760 if (IS_ONSCREEN (x,y))
ed673c6a 761 {
da048e3d 762 if (GTK_WIDGET_MAPPED (pizza) &&
bf3dab48
VZ
763 GTK_WIDGET_VISIBLE (child->widget))
764 {
765 if (!GTK_WIDGET_MAPPED (child->widget))
766 gtk_widget_map (child->widget);
767 }
ed673c6a 768
6d693bb4 769 if (GTK_WIDGET_IS_OFFSCREEN (child->widget))
bf3dab48 770 GTK_PRIVATE_UNSET_FLAG (child->widget, GTK_IS_OFFSCREEN);
ed673c6a 771 }
6d693bb4 772 else
ed673c6a 773 {
6d693bb4 774 if (!GTK_WIDGET_IS_OFFSCREEN (child->widget))
bf3dab48 775 GTK_PRIVATE_SET_FLAG (child->widget, GTK_IS_OFFSCREEN);
ed673c6a 776
6d693bb4 777 if (GTK_WIDGET_MAPPED (child->widget))
bf3dab48 778 gtk_widget_unmap (child->widget);
ed673c6a
RR
779 }
780}
781
782static void
da048e3d 783gtk_pizza_allocate_child (GtkPizza *pizza,
b6fa52db 784 GtkPizzaChild *child)
ed673c6a 785{
6d693bb4
RR
786 GtkAllocation allocation;
787 GtkRequisition requisition;
788
da048e3d
RR
789 allocation.x = child->x - pizza->xoffset;
790 allocation.y = child->y - pizza->yoffset;
6d693bb4
RR
791 gtk_widget_get_child_requisition (child->widget, &requisition);
792 allocation.width = requisition.width;
793 allocation.height = requisition.height;
bf3dab48 794
6d693bb4 795 gtk_widget_size_allocate (child->widget, &allocation);
ed673c6a
RR
796}
797
798static void
da048e3d 799gtk_pizza_position_children (GtkPizza *pizza)
ed673c6a 800{
6d693bb4 801 GList *tmp_list;
ed673c6a 802
da048e3d 803 tmp_list = pizza->children;
6d693bb4 804 while (tmp_list)
ed673c6a 805 {
da048e3d 806 GtkPizzaChild *child = tmp_list->data;
6d693bb4 807 tmp_list = tmp_list->next;
bf3dab48 808
da048e3d 809 gtk_pizza_position_child (pizza, child);
ed673c6a
RR
810 }
811}
812
813static void
da048e3d 814gtk_pizza_adjust_allocations_recurse (GtkWidget *widget,
bf3dab48 815 gpointer cb_data)
ed673c6a 816{
da048e3d 817 GtkPizzaAdjData *data = cb_data;
ed673c6a 818
6d693bb4
RR
819 widget->allocation.x += data->dx;
820 widget->allocation.y += data->dy;
ed673c6a 821
6d693bb4
RR
822 if (GTK_WIDGET_NO_WINDOW (widget) && GTK_IS_CONTAINER (widget))
823 {
bf3dab48
VZ
824 gtk_container_forall (GTK_CONTAINER (widget),
825 gtk_pizza_adjust_allocations_recurse,
826 cb_data);
6d693bb4 827 }
ed673c6a
RR
828}
829
830static void
da048e3d 831gtk_pizza_adjust_allocations (GtkPizza *pizza,
bf3dab48
VZ
832 gint dx,
833 gint dy)
ed673c6a 834{
0e09f76e
RR
835 GList *tmp_list;
836 GtkPizzaAdjData data;
ed673c6a 837
0e09f76e
RR
838 data.dx = dx;
839 data.dy = dy;
ed673c6a 840
0e09f76e
RR
841 tmp_list = pizza->children;
842 while (tmp_list)
ed673c6a 843 {
0e09f76e
RR
844 GtkPizzaChild *child = tmp_list->data;
845 tmp_list = tmp_list->next;
bf3dab48 846
0e09f76e
RR
847 child->widget->allocation.x += dx;
848 child->widget->allocation.y += dy;
ed673c6a 849
0e09f76e
RR
850 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
851 GTK_IS_CONTAINER (child->widget))
852 {
853 gtk_container_forall (GTK_CONTAINER (child->widget),
854 gtk_pizza_adjust_allocations_recurse,
855 &data);
856 }
ed673c6a
RR
857 }
858}
bf3dab48 859
ed673c6a
RR
860/* Callbacks */
861
862/* Send a synthetic expose event to the widget
863 */
864static void
da048e3d 865gtk_pizza_expose_area (GtkPizza *pizza,
bf3dab48 866 gint x, gint y, gint width, gint height)
ed673c6a 867{
0e09f76e 868 if (pizza->visibility == GDK_VISIBILITY_UNOBSCURED)
ed673c6a 869 {
0e09f76e 870 GdkEventExpose event;
bf3dab48 871
0e09f76e
RR
872 event.type = GDK_EXPOSE;
873 event.send_event = TRUE;
874 event.window = pizza->bin_window;
875 event.count = 0;
bf3dab48 876
0e09f76e
RR
877 event.area.x = x;
878 event.area.y = y;
879 event.area.width = width;
880 event.area.height = height;
bf3dab48 881
0e09f76e
RR
882 gdk_window_ref (event.window);
883 gtk_widget_event (GTK_WIDGET (pizza), (GdkEvent *)&event);
884 gdk_window_unref (event.window);
ed673c6a
RR
885 }
886}
887
888/* This function is used to find events to process while scrolling
889 */
890
bf3dab48
VZ
891static Bool
892gtk_pizza_expose_predicate (Display *display,
893 XEvent *xevent,
894 XPointer arg)
ed673c6a 895{
bf3dab48 896 if ((xevent->type == Expose) ||
ed673c6a
RR
897 ((xevent->xany.window == *(Window *)arg) &&
898 (xevent->type == ConfigureNotify)))
899 return True;
900 else
901 return False;
902}
903
904/* This is the main routine to do the scrolling. Scrolling is
905 * done by "Guffaw" scrolling, as in the Mozilla XFE, with
906 * a few modifications.
bf3dab48 907 *
ed673c6a
RR
908 * The main improvement is that we keep track of whether we
909 * are obscured or not. If not, we ignore the generated expose
910 * events and instead do the exposes ourself, without having
911 * to wait for a roundtrip to the server. This also provides
912 * a limited form of expose-event compression, since we do
913 * the affected area as one big chunk.
914 */
915
916void
da048e3d 917gtk_pizza_scroll (GtkPizza *pizza, gint dx, gint dy)
ed673c6a
RR
918{
919 GtkWidget *widget;
920 XEvent xevent;
921
922 gint x,y,w,h,border;
bf3dab48 923
da048e3d 924 widget = GTK_WIDGET (pizza);
ed673c6a 925
da048e3d
RR
926 pizza->xoffset += dx;
927 pizza->yoffset += dy;
ed673c6a 928
da048e3d 929 if (!GTK_WIDGET_MAPPED (pizza))
ed673c6a 930 {
da048e3d 931 gtk_pizza_position_children (pizza);
ed673c6a
RR
932 return;
933 }
934
da048e3d 935 gtk_pizza_adjust_allocations (pizza, -dx, -dy);
ed673c6a 936
da048e3d 937 if (pizza->shadow_type == GTK_MYSHADOW_NONE)
ed673c6a
RR
938 border = 0;
939 else
da048e3d 940 if (pizza->shadow_type == GTK_MYSHADOW_THIN)
ed673c6a
RR
941 border = 1;
942 else
943 border = 2;
bf3dab48 944
ed673c6a
RR
945 x = 0;
946 y = 0;
947 w = widget->allocation.width - 2*border;
948 h = widget->allocation.height - 2*border;
bf3dab48 949
ed673c6a
RR
950 if (dx > 0)
951 {
952 if (gravity_works)
bf3dab48
VZ
953 {
954 gdk_window_resize (pizza->bin_window,
955 w + dx,
956 h);
957 gdk_window_move (pizza->bin_window, x-dx, y);
958 gdk_window_move_resize (pizza->bin_window, x, y, w, h );
959 }
ed673c6a 960 else
bf3dab48
VZ
961 {
962 /* FIXME */
963 }
964
965 gtk_pizza_expose_area (pizza,
966 MAX ((gint)w - dx, 0),
967 0,
968 MIN (dx, w),
969 h);
ed673c6a
RR
970 }
971 else if (dx < 0)
972 {
973 if (gravity_works)
bf3dab48
VZ
974 {
975 gdk_window_move_resize (pizza->bin_window,
976 x + dx,
977 y,
978 w - dx,
979 h);
980 gdk_window_move (pizza->bin_window, x, y);
981 gdk_window_resize (pizza->bin_window, w, h );
982 }
ed673c6a 983 else
bf3dab48
VZ
984 {
985 /* FIXME */
986 }
ed673c6a 987
da048e3d 988 gtk_pizza_expose_area (pizza,
bf3dab48
VZ
989 0,
990 0,
991 MIN (-dx, w),
992 h);
ed673c6a
RR
993 }
994
995 if (dy > 0)
996 {
997 if (gravity_works)
bf3dab48
VZ
998 {
999 gdk_window_resize (pizza->bin_window, w, h + dy);
1000 gdk_window_move (pizza->bin_window, x, y-dy);
1001 gdk_window_move_resize (pizza->bin_window,
1002 x, y, w, h );
1003 }
ed673c6a 1004 else
bf3dab48
VZ
1005 {
1006 /* FIXME */
1007 }
1008
1009 gtk_pizza_expose_area (pizza,
1010 0,
1011 MAX ((gint)h - dy, 0),
1012 w,
1013 MIN (dy, h));
ed673c6a
RR
1014 }
1015 else if (dy < 0)
1016 {
1017 if (gravity_works)
bf3dab48
VZ
1018 {
1019 gdk_window_move_resize (pizza->bin_window,
1020 x, y+dy, w, h - dy );
1021 gdk_window_move (pizza->bin_window, x, y);
1022 gdk_window_resize (pizza->bin_window, w, h );
1023 }
ed673c6a 1024 else
bf3dab48
VZ
1025 {
1026 /* FIXME */
1027 }
1028 gtk_pizza_expose_area (pizza,
1029 0,
1030 0,
1031 w,
1032 MIN (-dy, (gint)h));
ed673c6a
RR
1033 }
1034
da048e3d 1035 gtk_pizza_position_children (pizza);
ed673c6a
RR
1036
1037 /* We have to make sure that all exposes from this scroll get
1038 * processed before we scroll again, or the expose events will
1039 * have invalid coordinates.
1040 *
1041 * We also do expose events for other windows, since otherwise
bf3dab48 1042 * their updating will fall behind the scrolling
ed673c6a
RR
1043 *
1044 * This also avoids a problem in pre-1.0 GTK where filters don't
1045 * have access to configure events that were compressed.
1046 */
1047
1048 gdk_flush();
da048e3d 1049 while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (pizza->bin_window),
bf3dab48
VZ
1050 &xevent,
1051 gtk_pizza_expose_predicate,
1052 (XPointer)&GDK_WINDOW_XWINDOW (pizza->bin_window)))
ed673c6a
RR
1053 {
1054 GdkEvent event;
1055 GtkWidget *event_widget;
1056
da048e3d 1057 if ((xevent.xany.window == GDK_WINDOW_XWINDOW (pizza->bin_window)) &&
bf3dab48
VZ
1058 (gtk_pizza_filter (&xevent, &event, pizza) == GDK_FILTER_REMOVE))
1059 continue;
1060
ed673c6a 1061 if (xevent.type == Expose)
bf3dab48
VZ
1062 {
1063 event.expose.window = gdk_window_lookup (xevent.xany.window);
1064 gdk_window_get_user_data (event.expose.window,
1065 (gpointer *)&event_widget);
1066
1067 if (event_widget)
1068 {
1069 event.expose.type = GDK_EXPOSE;
1070 event.expose.area.x = xevent.xexpose.x;
1071 event.expose.area.y = xevent.xexpose.y;
1072 event.expose.area.width = xevent.xexpose.width;
1073 event.expose.area.height = xevent.xexpose.height;
1074 event.expose.count = xevent.xexpose.count;
1075
1076 gdk_window_ref (event.expose.window);
1077 gtk_widget_event (event_widget, &event);
1078 gdk_window_unref (event.expose.window);
1079 }
1080 }
ed673c6a
RR
1081 }
1082}
1083
1084/* The main event filter. Actually, we probably don't really need
1085 * to install this as a filter at all, since we are calling it
1086 * directly above in the expose-handling hack. But in case scrollbars
1087 * are fixed up in some manner...
1088 *
1089 * This routine identifies expose events that are generated when
1090 * we've temporarily moved the bin_window_origin, and translates
1091 * them or discards them, depending on whether we are obscured
1092 * or not.
1093 */
bf3dab48 1094static GdkFilterReturn
da048e3d 1095gtk_pizza_filter (GdkXEvent *gdk_xevent,
bf3dab48
VZ
1096 GdkEvent *event,
1097 gpointer data)
ed673c6a 1098{
0e09f76e
RR
1099 XEvent *xevent;
1100 GtkPizza *pizza;
ed673c6a 1101
0e09f76e
RR
1102 xevent = (XEvent *)gdk_xevent;
1103
1104 pizza = GTK_PIZZA (data);
1105
b6fa52db
RR
1106 if (!pizza->use_filter)
1107 return GDK_FILTER_CONTINUE;
1108
ed673c6a
RR
1109 switch (xevent->type)
1110 {
1111 case Expose:
da048e3d 1112 if (xevent->xexpose.serial == pizza->configure_serial)
bf3dab48
VZ
1113 {
1114 if (pizza->visibility == GDK_VISIBILITY_UNOBSCURED)
1115 return GDK_FILTER_REMOVE;
1116 else
1117 {
1118 xevent->xexpose.x += pizza->scroll_x;
1119 xevent->xexpose.y += pizza->scroll_y;
1120
1121 break;
1122 }
1123 }
ed673c6a 1124 break;
bf3dab48 1125
ed673c6a
RR
1126 case ConfigureNotify:
1127 if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0))
bf3dab48
VZ
1128 {
1129 pizza->configure_serial = xevent->xconfigure.serial;
1130 pizza->scroll_x = xevent->xconfigure.x;
1131 pizza->scroll_y = xevent->xconfigure.y;
1132 }
ed673c6a
RR
1133 break;
1134 }
bf3dab48 1135
0e09f76e 1136 return GDK_FILTER_CONTINUE;
ed673c6a
RR
1137}
1138
1139/* Although GDK does have a GDK_VISIBILITY_NOTIFY event,
1140 * there is no corresponding event in GTK, so we have
1141 * to get the events from a filter
1142 */
bf3dab48 1143static GdkFilterReturn
da048e3d 1144gtk_pizza_main_filter (GdkXEvent *gdk_xevent,
bf3dab48
VZ
1145 GdkEvent *event,
1146 gpointer data)
ed673c6a 1147{
0e09f76e
RR
1148 XEvent *xevent;
1149 GtkPizza *pizza;
ed673c6a 1150
0e09f76e
RR
1151 xevent = (XEvent *)gdk_xevent;
1152 pizza = GTK_PIZZA (data);
b6fa52db
RR
1153
1154 if (!pizza->use_filter)
1155 return GDK_FILTER_CONTINUE;
ed673c6a 1156
0e09f76e 1157 if (xevent->type == VisibilityNotify)
ed673c6a 1158 {
0e09f76e 1159 switch (xevent->xvisibility.state)
bf3dab48 1160 {
0e09f76e
RR
1161 case VisibilityFullyObscured:
1162 pizza->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
1163 break;
ed673c6a 1164
0e09f76e
RR
1165 case VisibilityPartiallyObscured:
1166 pizza->visibility = GDK_VISIBILITY_PARTIAL;
1167 break;
ed673c6a 1168
0e09f76e
RR
1169 case VisibilityUnobscured:
1170 pizza->visibility = GDK_VISIBILITY_UNOBSCURED;
1171 break;
bf3dab48 1172 }
0e09f76e
RR
1173
1174 return GDK_FILTER_REMOVE;
ed673c6a
RR
1175 }
1176
0e09f76e 1177 return GDK_FILTER_CONTINUE;
ed673c6a
RR
1178}
1179
1180
1181
1182
c801d85f
KB
1183#ifdef __cplusplus
1184}
1185#endif /* __cplusplus */
1186