]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/win_gtk.c
wxSlider should now display int values,
[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
6d693bb4 396 return;
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
227e5e99 605 widget->allocation = *allocation;
ed673c6a 606
5e014a0c 607 if (myfixed->shadow_type == GTK_MYSHADOW_NONE)
053f9cc1 608 border = 0;
5e014a0c
RR
609 else
610 if (myfixed->shadow_type == GTK_MYSHADOW_THIN)
611 border = 1;
053f9cc1
RR
612 else
613 border = 2;
ed673c6a
RR
614
615 x = allocation->x + border;
616 y = allocation->y + border;
617 w = allocation->width - border*2;
618 h = allocation->height - border*2;
034be888 619
053f9cc1
RR
620 if (GTK_WIDGET_REALIZED (widget))
621 {
ed673c6a
RR
622 gdk_window_move_resize( widget->window, x, y, w, h );
623 gdk_window_move_resize( myfixed->bin_window, 0, 0, w, h );
053f9cc1 624 }
6d693bb4
RR
625
626 children = myfixed->children;
627 while (children)
628 {
629 child = children->data;
630 children = children->next;
631
632 gtk_myfixed_position_child (myfixed, child);
633 gtk_myfixed_allocate_child (myfixed, child);
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
c801d85f
KB
669static gint
670gtk_myfixed_expose (GtkWidget *widget,
fdd3ed7a 671 GdkEventExpose *event)
c801d85f 672{
ed673c6a
RR
673 GtkMyFixed *myfixed;
674 GtkMyFixedChild *child;
675 GdkEventExpose child_event;
676 GList *children;
c801d85f 677
ed673c6a
RR
678 g_return_val_if_fail (widget != NULL, FALSE);
679 g_return_val_if_fail (GTK_IS_MYFIXED (widget), FALSE);
680 g_return_val_if_fail (event != NULL, FALSE);
681
682 myfixed = GTK_MYFIXED (widget);
c801d85f 683
ed673c6a
RR
684/*
685 if (event->window == widget->window)
c801d85f 686 {
ed673c6a
RR
687 gtk_myfixed_draw_border( myfixed );
688 return FALSE;
689 }
690*/
c801d85f 691
ed673c6a
RR
692 if (event->window != myfixed->bin_window)
693 return FALSE;
c801d85f 694
ed673c6a
RR
695 children = myfixed->children;
696 while (children)
697 {
698 child = children->data;
699 children = children->next;
c801d85f 700
ed673c6a
RR
701 child_event = *event;
702
703 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
704 GTK_WIDGET_DRAWABLE (child->widget) &&
705 gtk_widget_intersect (child->widget, &event->area, &child_event.area))
706 {
c801d85f
KB
707 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
708 }
709 }
710
ed673c6a 711 return FALSE;
c801d85f
KB
712}
713
714static void
715gtk_myfixed_add (GtkContainer *container,
716 GtkWidget *widget)
717{
ed673c6a
RR
718 g_return_if_fail (container != NULL);
719 g_return_if_fail (GTK_IS_MYFIXED (container));
720 g_return_if_fail (widget != NULL);
c801d85f 721
ed673c6a 722 gtk_myfixed_put (GTK_MYFIXED (container), widget, 0, 0, 20, 20 );
c801d85f
KB
723}
724
725static void
726gtk_myfixed_remove (GtkContainer *container,
ed673c6a 727 GtkWidget *widget)
c801d85f 728{
ed673c6a
RR
729 GtkMyFixed *myfixed;
730 GtkMyFixedChild *child;
731 GList *children;
c801d85f 732
ed673c6a
RR
733 g_return_if_fail (container != NULL);
734 g_return_if_fail (GTK_IS_MYFIXED (container));
735 g_return_if_fail (widget != NULL);
c801d85f 736
ed673c6a 737 myfixed = GTK_MYFIXED (container);
c801d85f 738
ed673c6a
RR
739 children = myfixed->children;
740 while (children)
c801d85f 741 {
ed673c6a 742 child = children->data;
c801d85f 743
ed673c6a 744 if (child->widget == widget)
c801d85f 745 {
ed673c6a 746 gtk_widget_unparent (widget);
c801d85f 747
ed673c6a
RR
748 /* security checks */
749 g_return_if_fail (GTK_IS_WIDGET (widget));
5fd11f09 750
ed673c6a
RR
751 myfixed->children = g_list_remove_link (myfixed->children, children);
752 g_list_free (children);
753 g_free (child);
c801d85f 754
ed673c6a
RR
755 /* security checks */
756 g_return_if_fail (GTK_IS_WIDGET (widget));
757
758 GTK_PRIVATE_UNSET_FLAG (widget, GTK_IS_OFFSCREEN);
759
760 break;
c801d85f
KB
761 }
762
ed673c6a 763 children = children->next;
c801d85f
KB
764 }
765}
766
767static void
ed673c6a 768gtk_myfixed_forall (GtkContainer *container,
75ed1d15 769 gboolean include_internals,
c801d85f
KB
770 GtkCallback callback,
771 gpointer callback_data)
772{
6d693bb4
RR
773 GtkMyFixed *myfixed;
774 GtkMyFixedChild *child;
775 GList *children;
c801d85f 776
6d693bb4
RR
777 g_return_if_fail (container != NULL);
778 g_return_if_fail (GTK_IS_MYFIXED (container));
779 g_return_if_fail (callback != NULL);
c801d85f 780
6d693bb4 781 myfixed = GTK_MYFIXED (container);
c801d85f 782
6d693bb4
RR
783 children = myfixed->children;
784 while (children)
c801d85f 785 {
6d693bb4
RR
786 child = children->data;
787 children = children->next;
c801d85f 788
6d693bb4 789 (* callback) (child->widget, callback_data);
c801d85f
KB
790 }
791}
792
793
ed673c6a
RR
794/* Operations on children
795 */
796
797static void
798gtk_myfixed_position_child (GtkMyFixed *myfixed,
799 GtkMyFixedChild *child)
800{
6d693bb4
RR
801 gint x;
802 gint y;
ed673c6a 803
6d693bb4
RR
804 x = child->x - myfixed->xoffset;
805 y = child->y - myfixed->yoffset;
ed673c6a 806
6d693bb4 807 if (IS_ONSCREEN (x,y))
ed673c6a 808 {
6d693bb4 809 if (GTK_WIDGET_MAPPED (myfixed) &&
ed673c6a
RR
810 GTK_WIDGET_VISIBLE (child->widget))
811 {
6d693bb4
RR
812 if (!GTK_WIDGET_MAPPED (child->widget))
813 gtk_widget_map (child->widget);
ed673c6a
RR
814 }
815
6d693bb4
RR
816 if (GTK_WIDGET_IS_OFFSCREEN (child->widget))
817 GTK_PRIVATE_UNSET_FLAG (child->widget, GTK_IS_OFFSCREEN);
ed673c6a 818 }
6d693bb4 819 else
ed673c6a 820 {
6d693bb4
RR
821 if (!GTK_WIDGET_IS_OFFSCREEN (child->widget))
822 GTK_PRIVATE_SET_FLAG (child->widget, GTK_IS_OFFSCREEN);
ed673c6a 823
6d693bb4
RR
824 if (GTK_WIDGET_MAPPED (child->widget))
825 gtk_widget_unmap (child->widget);
ed673c6a
RR
826 }
827}
828
829static void
830gtk_myfixed_allocate_child (GtkMyFixed *myfixed,
831 GtkMyFixedChild *child)
832{
6d693bb4
RR
833 GtkAllocation allocation;
834 GtkRequisition requisition;
835
836 allocation.x = child->x - myfixed->xoffset;
837 allocation.y = child->y - myfixed->yoffset;
838 gtk_widget_get_child_requisition (child->widget, &requisition);
839 allocation.width = requisition.width;
840 allocation.height = requisition.height;
ed673c6a 841
6d693bb4 842 gtk_widget_size_allocate (child->widget, &allocation);
ed673c6a
RR
843}
844
845static void
846gtk_myfixed_position_children (GtkMyFixed *myfixed)
847{
6d693bb4 848 GList *tmp_list;
ed673c6a 849
6d693bb4
RR
850 tmp_list = myfixed->children;
851 while (tmp_list)
ed673c6a 852 {
6d693bb4
RR
853 GtkMyFixedChild *child = tmp_list->data;
854 tmp_list = tmp_list->next;
ed673c6a 855
6d693bb4 856 gtk_myfixed_position_child (myfixed, child);
ed673c6a
RR
857 }
858}
859
860static void
861gtk_myfixed_adjust_allocations_recurse (GtkWidget *widget,
862 gpointer cb_data)
863{
6d693bb4 864 GtkMyFixedAdjData *data = cb_data;
ed673c6a 865
6d693bb4
RR
866 widget->allocation.x += data->dx;
867 widget->allocation.y += data->dy;
ed673c6a 868
6d693bb4
RR
869 if (GTK_WIDGET_NO_WINDOW (widget) && GTK_IS_CONTAINER (widget))
870 {
871 gtk_container_forall (GTK_CONTAINER (widget),
ed673c6a
RR
872 gtk_myfixed_adjust_allocations_recurse,
873 cb_data);
6d693bb4 874 }
ed673c6a
RR
875}
876
877static void
878gtk_myfixed_adjust_allocations (GtkMyFixed *myfixed,
879 gint dx,
880 gint dy)
881{
882 GList *tmp_list;
883 GtkMyFixedAdjData data;
884
885 data.dx = dx;
886 data.dy = dy;
887
888 tmp_list = myfixed->children;
889 while (tmp_list)
890 {
891 GtkMyFixedChild *child = tmp_list->data;
892 tmp_list = tmp_list->next;
893
894 child->widget->allocation.x += dx;
895 child->widget->allocation.y += dy;
896
897 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
898 GTK_IS_CONTAINER (child->widget))
899 gtk_container_forall (GTK_CONTAINER (child->widget),
900 gtk_myfixed_adjust_allocations_recurse,
901 &data);
902 }
903}
904
905/* Callbacks */
906
907/* Send a synthetic expose event to the widget
908 */
909static void
910gtk_myfixed_expose_area (GtkMyFixed *myfixed,
911 gint x, gint y, gint width, gint height)
912{
913 if (myfixed->visibility == GDK_VISIBILITY_UNOBSCURED)
914 {
915 GdkEventExpose event;
916
917 event.type = GDK_EXPOSE;
918 event.send_event = TRUE;
919 event.window = myfixed->bin_window;
920 event.count = 0;
921
922 event.area.x = x;
923 event.area.y = y;
924 event.area.width = width;
925 event.area.height = height;
926
927 gdk_window_ref (event.window);
928 gtk_widget_event (GTK_WIDGET (myfixed), (GdkEvent *)&event);
929 gdk_window_unref (event.window);
930 }
931}
932
933/* This function is used to find events to process while scrolling
934 */
935
936static Bool
937gtk_myfixed_expose_predicate (Display *display,
938 XEvent *xevent,
939 XPointer arg)
940{
941 if ((xevent->type == Expose) ||
942 ((xevent->xany.window == *(Window *)arg) &&
943 (xevent->type == ConfigureNotify)))
944 return True;
945 else
946 return False;
947}
948
949/* This is the main routine to do the scrolling. Scrolling is
950 * done by "Guffaw" scrolling, as in the Mozilla XFE, with
951 * a few modifications.
952 *
953 * The main improvement is that we keep track of whether we
954 * are obscured or not. If not, we ignore the generated expose
955 * events and instead do the exposes ourself, without having
956 * to wait for a roundtrip to the server. This also provides
957 * a limited form of expose-event compression, since we do
958 * the affected area as one big chunk.
959 */
960
961void
962gtk_myfixed_scroll (GtkMyFixed *myfixed, gint dx, gint dy)
963{
964 GtkWidget *widget;
965 XEvent xevent;
966
967 gint x,y,w,h,border;
968
969 widget = GTK_WIDGET (myfixed);
970
971 myfixed->xoffset += dx;
972 myfixed->yoffset += dy;
973
974 if (!GTK_WIDGET_MAPPED (myfixed))
975 {
976 gtk_myfixed_position_children (myfixed);
977 return;
978 }
979
980 gtk_myfixed_adjust_allocations (myfixed, -dx, -dy);
981
982 if (myfixed->shadow_type == GTK_MYSHADOW_NONE)
983 border = 0;
984 else
985 if (myfixed->shadow_type == GTK_MYSHADOW_THIN)
986 border = 1;
987 else
988 border = 2;
989
990 x = 0;
991 y = 0;
992 w = widget->allocation.width - 2*border;
993 h = widget->allocation.height - 2*border;
994
995 if (dx > 0)
996 {
997 if (gravity_works)
998 {
999 gdk_window_resize (myfixed->bin_window,
1000 w + dx,
1001 h);
1002 gdk_window_move (myfixed->bin_window, x-dx, y);
1003 gdk_window_move_resize (myfixed->bin_window, x, y, w, h );
1004 }
1005 else
1006 {
1007 /* FIXME */
1008 }
1009
1010 gtk_myfixed_expose_area (myfixed,
1011 MAX ((gint)w - dx, 0),
1012 0,
1013 MIN (dx, w),
1014 h);
1015 }
1016 else if (dx < 0)
1017 {
1018 if (gravity_works)
1019 {
1020 gdk_window_move_resize (myfixed->bin_window,
1021 x + dx,
1022 y,
1023 w - dx,
1024 h);
1025 gdk_window_move (myfixed->bin_window, x, y);
1026 gdk_window_resize (myfixed->bin_window, w, h );
1027 }
1028 else
1029 {
1030 /* FIXME */
1031 }
1032
1033 gtk_myfixed_expose_area (myfixed,
1034 0,
1035 0,
1036 MIN (-dx, w),
1037 h);
1038 }
1039
1040 if (dy > 0)
1041 {
1042 if (gravity_works)
1043 {
1044 gdk_window_resize (myfixed->bin_window, w, h + dy);
1045 gdk_window_move (myfixed->bin_window, x, y-dy);
1046 gdk_window_move_resize (myfixed->bin_window,
1047 x, y, w, h );
1048 }
1049 else
1050 {
1051 /* FIXME */
1052 }
1053
1054 gtk_myfixed_expose_area (myfixed,
1055 0,
1056 MAX ((gint)h - dy, 0),
1057 w,
1058 MIN (dy, h));
1059 }
1060 else if (dy < 0)
1061 {
1062 if (gravity_works)
1063 {
1064 gdk_window_move_resize (myfixed->bin_window,
1065 x, y+dy, w, h - dy );
1066 gdk_window_move (myfixed->bin_window, x, y);
1067 gdk_window_resize (myfixed->bin_window, w, h );
1068 }
1069 else
1070 {
1071 /* FIXME */
1072 }
1073 gtk_myfixed_expose_area (myfixed,
1074 0,
1075 0,
1076 w,
1077 MIN (-dy, (gint)h));
1078 }
1079
1080 gtk_myfixed_position_children (myfixed);
1081
1082 /* We have to make sure that all exposes from this scroll get
1083 * processed before we scroll again, or the expose events will
1084 * have invalid coordinates.
1085 *
1086 * We also do expose events for other windows, since otherwise
1087 * their updating will fall behind the scrolling
1088 *
1089 * This also avoids a problem in pre-1.0 GTK where filters don't
1090 * have access to configure events that were compressed.
1091 */
1092
1093 gdk_flush();
1094 while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (myfixed->bin_window),
1095 &xevent,
1096 gtk_myfixed_expose_predicate,
1097 (XPointer)&GDK_WINDOW_XWINDOW (myfixed->bin_window)))
1098 {
1099 GdkEvent event;
1100 GtkWidget *event_widget;
1101
1102 if ((xevent.xany.window == GDK_WINDOW_XWINDOW (myfixed->bin_window)) &&
1103 (gtk_myfixed_filter (&xevent, &event, myfixed) == GDK_FILTER_REMOVE))
1104 continue;
1105
1106 if (xevent.type == Expose)
1107 {
1108 event.expose.window = gdk_window_lookup (xevent.xany.window);
1109 gdk_window_get_user_data (event.expose.window,
1110 (gpointer *)&event_widget);
1111
1112 if (event_widget)
1113 {
1114 event.expose.type = GDK_EXPOSE;
1115 event.expose.area.x = xevent.xexpose.x;
1116 event.expose.area.y = xevent.xexpose.y;
1117 event.expose.area.width = xevent.xexpose.width;
1118 event.expose.area.height = xevent.xexpose.height;
1119 event.expose.count = xevent.xexpose.count;
1120
1121 gdk_window_ref (event.expose.window);
1122 gtk_widget_event (event_widget, &event);
1123 gdk_window_unref (event.expose.window);
1124 }
1125 }
1126 }
1127}
1128
1129/* The main event filter. Actually, we probably don't really need
1130 * to install this as a filter at all, since we are calling it
1131 * directly above in the expose-handling hack. But in case scrollbars
1132 * are fixed up in some manner...
1133 *
1134 * This routine identifies expose events that are generated when
1135 * we've temporarily moved the bin_window_origin, and translates
1136 * them or discards them, depending on whether we are obscured
1137 * or not.
1138 */
1139static GdkFilterReturn
1140gtk_myfixed_filter (GdkXEvent *gdk_xevent,
1141 GdkEvent *event,
1142 gpointer data)
1143{
1144 XEvent *xevent;
1145 GtkMyFixed *myfixed;
1146
1147 xevent = (XEvent *)gdk_xevent;
1148 myfixed = GTK_MYFIXED (data);
1149
1150 switch (xevent->type)
1151 {
1152 case Expose:
1153 if (xevent->xexpose.serial == myfixed->configure_serial)
1154 {
1155 if (myfixed->visibility == GDK_VISIBILITY_UNOBSCURED)
1156 return GDK_FILTER_REMOVE;
1157 else
1158 {
1159 xevent->xexpose.x += myfixed->scroll_x;
1160 xevent->xexpose.y += myfixed->scroll_y;
1161
1162 break;
1163 }
1164 }
1165 break;
1166
1167 case ConfigureNotify:
1168 if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0))
1169 {
1170 myfixed->configure_serial = xevent->xconfigure.serial;
1171 myfixed->scroll_x = xevent->xconfigure.x;
1172 myfixed->scroll_y = xevent->xconfigure.y;
1173 }
1174 break;
1175 }
1176
1177 return GDK_FILTER_CONTINUE;
1178}
1179
1180/* Although GDK does have a GDK_VISIBILITY_NOTIFY event,
1181 * there is no corresponding event in GTK, so we have
1182 * to get the events from a filter
1183 */
1184static GdkFilterReturn
1185gtk_myfixed_main_filter (GdkXEvent *gdk_xevent,
1186 GdkEvent *event,
1187 gpointer data)
1188{
1189 XEvent *xevent;
1190 GtkMyFixed *myfixed;
1191
1192 xevent = (XEvent *)gdk_xevent;
1193 myfixed = GTK_MYFIXED (data);
1194
1195 if (xevent->type == VisibilityNotify)
1196 {
1197 switch (xevent->xvisibility.state)
1198 {
1199 case VisibilityFullyObscured:
1200 myfixed->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
1201 break;
1202
1203 case VisibilityPartiallyObscured:
1204 myfixed->visibility = GDK_VISIBILITY_PARTIAL;
1205 break;
1206
1207 case VisibilityUnobscured:
1208 myfixed->visibility = GDK_VISIBILITY_UNOBSCURED;
1209 break;
1210 }
1211
1212 return GDK_FILTER_REMOVE;
1213 }
1214
1215
1216 return GDK_FILTER_CONTINUE;
1217}
1218
1219
1220
1221
c801d85f
KB
1222#ifdef __cplusplus
1223}
1224#endif /* __cplusplus */
1225