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