Fox around a bug in GTK's GtkNotebook
[wxWidgets.git] / src / gtk1 / win_gtk.c
1 /* ///////////////////////////////////////////////////////////////////////////
2 // Name: win_gtk.c
3 // Purpose: native GTK+ widget for wxWindows
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////// */
9
10 #include "wx/gtk/win_gtk.h"
11 #include "gtk/gtksignal.h"
12 #include "gtk/gtknotebook.h"
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif /* __cplusplus */
17
18 static void gtk_myfixed_class_init (GtkMyFixedClass *klass);
19 static void gtk_myfixed_init (GtkMyFixed *myfixed);
20 static void gtk_myfixed_map (GtkWidget *widget);
21 #if (GTK_MINOR_VERSION == 0)
22 static void gtk_myfixed_unmap (GtkWidget *widget);
23 #endif
24 static void gtk_myfixed_realize (GtkWidget *widget);
25 static void gtk_myfixed_size_request (GtkWidget *widget,
26 GtkRequisition *requisition);
27 static void gtk_myfixed_size_allocate (GtkWidget *widget,
28 GtkAllocation *allocation);
29 static void gtk_myfixed_paint (GtkWidget *widget,
30 GdkRectangle *area);
31 static void gtk_myfixed_draw (GtkWidget *widget,
32 GdkRectangle *area);
33 static gint gtk_myfixed_expose (GtkWidget *widget,
34 GdkEventExpose *event);
35 static void gtk_myfixed_add (GtkContainer *container,
36 GtkWidget *widget);
37 static void gtk_myfixed_remove (GtkContainer *container,
38 GtkWidget *widget);
39 static void gtk_myfixed_foreach (GtkContainer *container,
40 #if (GTK_MINOR_VERSION > 0)
41 gboolean include_internals,
42 #endif
43 GtkCallback callback,
44 gpointer callback_data);
45 #if (GTK_MINOR_VERSION > 0)
46 static GtkType gtk_myfixed_child_type (GtkContainer *container);
47 #endif
48
49 #if (GTK_MINOR_VERSION > 0)
50 static void gtk_myfixed_scroll_set_adjustments (GtkMyFixed *myfixed,
51 GtkAdjustment *hadj,
52 GtkAdjustment *vadj);
53 #endif
54
55
56
57 static GtkContainerClass *parent_class = NULL;
58
59 guint
60 gtk_myfixed_get_type ()
61 {
62 static guint myfixed_type = 0;
63
64 if (!myfixed_type)
65 {
66 GtkTypeInfo myfixed_info =
67 {
68 "GtkMyFixed",
69 sizeof (GtkMyFixed),
70 sizeof (GtkMyFixedClass),
71 (GtkClassInitFunc) gtk_myfixed_class_init,
72 (GtkObjectInitFunc) gtk_myfixed_init,
73 #if (GTK_MINOR_VERSION > 0)
74 /* reserved_1 */ NULL,
75 /* reserved_2 */ NULL,
76 (GtkClassInitFunc) NULL,
77 #else
78 (GtkArgSetFunc) NULL,
79 (GtkArgGetFunc) NULL,
80 #endif
81 };
82
83 myfixed_type = gtk_type_unique (gtk_container_get_type (), &myfixed_info);
84 }
85
86 return myfixed_type;
87 }
88
89 static void
90 gtk_myfixed_class_init (GtkMyFixedClass *klass)
91 {
92 GtkObjectClass *object_class;
93 GtkWidgetClass *widget_class;
94 GtkContainerClass *container_class;
95
96 object_class = (GtkObjectClass*) klass;
97 widget_class = (GtkWidgetClass*) klass;
98 container_class = (GtkContainerClass*) klass;
99
100 #if (GTK_MINOR_VERSION > 0)
101 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
102 #else
103 parent_class = gtk_type_class (gtk_container_get_type ());
104 #endif
105
106 widget_class->map = gtk_myfixed_map;
107 #if (GTK_MINOR_VERSION == 0)
108 widget_class->unmap = gtk_myfixed_unmap;
109 #endif
110 widget_class->realize = gtk_myfixed_realize;
111 widget_class->size_request = gtk_myfixed_size_request;
112 widget_class->size_allocate = gtk_myfixed_size_allocate;
113 widget_class->draw = gtk_myfixed_draw;
114 widget_class->expose_event = gtk_myfixed_expose;
115
116 container_class->add = gtk_myfixed_add;
117 container_class->remove = gtk_myfixed_remove;
118 #if (GTK_MINOR_VERSION > 0)
119 container_class->forall = gtk_myfixed_foreach;
120 #else
121 container_class->foreach = gtk_myfixed_foreach;
122 #endif
123
124 #if (GTK_MINOR_VERSION > 0)
125 container_class->child_type = gtk_myfixed_child_type;
126 #endif
127
128 #if (GTK_MINOR_VERSION > 0)
129 klass->set_scroll_adjustments = gtk_myfixed_scroll_set_adjustments;
130
131 widget_class->set_scroll_adjustments_signal =
132 gtk_signal_new ("set_scroll_adjustments",
133 GTK_RUN_LAST,
134 object_class->type,
135 GTK_SIGNAL_OFFSET (GtkMyFixedClass, set_scroll_adjustments),
136 gtk_marshal_NONE__POINTER_POINTER,
137 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
138 #endif
139 }
140
141 #if (GTK_MINOR_VERSION > 0)
142 static GtkType
143 gtk_myfixed_child_type (GtkContainer *container)
144 {
145 return GTK_TYPE_WIDGET;
146 }
147 #endif
148
149 static void
150 gtk_myfixed_init (GtkMyFixed *myfixed)
151 {
152 GTK_WIDGET_UNSET_FLAGS (myfixed, GTK_NO_WINDOW);
153
154 #if (GTK_MINOR_VERSION == 0)
155 GTK_WIDGET_SET_FLAGS (myfixed, GTK_BASIC);
156 #endif
157
158 #if (GTK_MINOR_VERSION > 0)
159 myfixed->shadow_type = GTK_SHADOW_NONE;
160 #endif
161
162 myfixed->children = NULL;
163 }
164
165 GtkWidget*
166 gtk_myfixed_new ()
167 {
168 GtkMyFixed *myfixed;
169
170 myfixed = gtk_type_new (gtk_myfixed_get_type ());
171
172 return GTK_WIDGET (myfixed);
173 }
174
175 #if (GTK_MINOR_VERSION > 0)
176 void gtk_myfixed_scroll_set_adjustments (GtkMyFixed *myfixed,
177 GtkAdjustment *hadj,
178 GtkAdjustment *vadj)
179 {
180 /* OK, this is embarassing, but this function has to be here */
181 }
182
183 void
184 gtk_myfixed_set_shadow_type (GtkMyFixed *myfixed,
185 GtkShadowType type)
186 {
187 g_return_if_fail (myfixed != NULL);
188 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
189
190 if ((GtkShadowType) myfixed->shadow_type != type)
191 {
192 myfixed->shadow_type = type;
193
194 if (GTK_WIDGET_VISIBLE (myfixed))
195 {
196 gtk_widget_size_allocate (GTK_WIDGET (myfixed), &(GTK_WIDGET (myfixed)->allocation));
197 gtk_widget_queue_draw (GTK_WIDGET (myfixed));
198 }
199 }
200 }
201 #endif
202
203 void
204 gtk_myfixed_put (GtkMyFixed *myfixed,
205 GtkWidget *widget,
206 gint16 x,
207 gint16 y)
208 {
209 GtkMyFixedChild *child_info;
210
211 g_return_if_fail (myfixed != NULL);
212 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
213 g_return_if_fail (widget != NULL);
214
215 child_info = g_new (GtkMyFixedChild, 1);
216 child_info->widget = widget;
217 child_info->x = x;
218 child_info->y = y;
219
220 gtk_widget_set_parent (widget, GTK_WIDGET (myfixed));
221
222 myfixed->children = g_list_append (myfixed->children, child_info);
223
224 if (GTK_WIDGET_REALIZED (myfixed) && !GTK_WIDGET_REALIZED (widget))
225 gtk_widget_realize (widget);
226
227 if (GTK_WIDGET_MAPPED (myfixed) && !GTK_WIDGET_MAPPED (widget))
228 gtk_widget_map (widget);
229
230 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (myfixed))
231 gtk_widget_queue_resize (GTK_WIDGET (myfixed));
232 }
233
234 void
235 gtk_myfixed_move (GtkMyFixed *myfixed,
236 GtkWidget *widget,
237 gint16 x,
238 gint16 y)
239 {
240 GtkMyFixedChild *child;
241 GList *children;
242
243 g_return_if_fail (myfixed != NULL);
244 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
245 g_return_if_fail (widget != NULL);
246
247 children = myfixed->children;
248 while (children)
249 {
250 child = children->data;
251 children = children->next;
252
253 if (child->widget == widget)
254 {
255 if ((child->x == x) && (child->y == y)) return;
256
257 child->x = x;
258 child->y = y;
259
260 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (myfixed))
261 gtk_widget_queue_resize (GTK_WIDGET (myfixed));
262
263 break;
264 }
265 }
266 }
267
268 static void
269 gtk_myfixed_map (GtkWidget *widget)
270 {
271 GtkMyFixed *myfixed;
272 GtkMyFixedChild *child;
273 GList *children;
274
275 g_return_if_fail (widget != NULL);
276 g_return_if_fail (GTK_IS_MYFIXED (widget));
277
278 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
279 myfixed = GTK_MYFIXED (widget);
280
281 gdk_window_show (widget->window);
282
283 children = myfixed->children;
284 while (children)
285 {
286 child = children->data;
287 children = children->next;
288
289 if (GTK_WIDGET_VISIBLE (child->widget) &&
290 !GTK_WIDGET_MAPPED (child->widget))
291 gtk_widget_map (child->widget);
292 }
293 }
294
295 #if (GTK_MINOR_VERSION == 0)
296 static void
297 gtk_myfixed_unmap (GtkWidget *widget)
298 {
299 g_return_if_fail (widget != NULL);
300 g_return_if_fail (GTK_IS_MYFIXED (widget));
301
302 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
303 }
304 #endif
305
306 static void
307 gtk_myfixed_realize (GtkWidget *widget)
308 {
309 GtkMyFixed *myfixed;
310 GdkWindowAttr attributes;
311 gint attributes_mask;
312
313 g_return_if_fail (widget != NULL);
314 g_return_if_fail (GTK_IS_MYFIXED (widget));
315
316 myfixed = GTK_MYFIXED (widget);
317
318 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
319
320 attributes.window_type = GDK_WINDOW_CHILD;
321
322 #if (GTK_MINOR_VERSION > 0)
323 attributes.x = widget->allocation.x;
324 attributes.y = widget->allocation.y;
325 attributes.width = widget->allocation.width;
326 attributes.height = widget->allocation.height;
327
328 if (myfixed->shadow_type != GTK_SHADOW_NONE)
329 {
330 attributes.x += 2;
331 attributes.y += 2;
332 attributes.width -= 4;
333 attributes.height -= 4;
334 }
335
336 if (attributes.width < 2) attributes.width = 2;
337 if (attributes.height < 2) attributes.height = 2;
338 #else
339 attributes.x = widget->allocation.x;
340 attributes.y = widget->allocation.y;
341 attributes.width = 32000;
342 attributes.height = 32000;
343 #endif
344 attributes.wclass = GDK_INPUT_OUTPUT;
345 attributes.visual = gtk_widget_get_visual (widget);
346 attributes.colormap = gtk_widget_get_colormap (widget);
347 attributes.event_mask = gtk_widget_get_events (widget);
348 attributes.event_mask |=
349 GDK_EXPOSURE_MASK |
350 GDK_POINTER_MOTION_MASK |
351 GDK_POINTER_MOTION_HINT_MASK |
352 GDK_BUTTON_MOTION_MASK |
353 GDK_BUTTON1_MOTION_MASK |
354 GDK_BUTTON2_MOTION_MASK |
355 GDK_BUTTON3_MOTION_MASK |
356 GDK_BUTTON_PRESS_MASK |
357 GDK_BUTTON_RELEASE_MASK |
358 GDK_KEY_PRESS_MASK |
359 GDK_KEY_RELEASE_MASK |
360 GDK_ENTER_NOTIFY_MASK |
361 GDK_LEAVE_NOTIFY_MASK |
362 GDK_FOCUS_CHANGE_MASK;
363
364 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
365
366 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes,
367 attributes_mask);
368 gdk_window_set_user_data (widget->window, widget);
369
370 widget->style = gtk_style_attach (widget->style, widget->window);
371 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
372 }
373
374 static void
375 gtk_myfixed_size_request (GtkWidget *widget,
376 GtkRequisition *requisition)
377 {
378 GtkMyFixed *myfixed;
379 GtkMyFixedChild *child;
380 GList *children;
381
382 g_return_if_fail (widget != NULL);
383 g_return_if_fail (GTK_IS_MYFIXED (widget));
384 g_return_if_fail (requisition != NULL);
385
386 myfixed = GTK_MYFIXED (widget);
387
388 /*
389 requisition->width = 0;
390 requisition->height = 0;
391 */
392 requisition->width = widget->requisition.width;
393 requisition->height = widget->requisition.height;
394
395 children = myfixed->children;
396 while (children)
397 {
398 child = children->data;
399 children = children->next;
400
401 if (GTK_WIDGET_VISIBLE (child->widget))
402 {
403 gtk_widget_size_request (child->widget, &child->widget->requisition);
404 }
405 }
406 }
407
408 static void
409 gtk_myfixed_size_allocate (GtkWidget *widget,
410 GtkAllocation *allocation)
411 {
412 GtkMyFixed *myfixed;
413 gint border;
414 GtkMyFixedChild *child;
415 GtkAllocation child_allocation;
416 GList *children;
417
418 g_return_if_fail (widget != NULL);
419 g_return_if_fail (GTK_IS_MYFIXED(widget));
420 g_return_if_fail (allocation != NULL);
421
422 myfixed = GTK_MYFIXED (widget);
423
424 widget->allocation = *allocation;
425 #if (GTK_MINOR_VERSION > 0)
426 if (myfixed->shadow_type == GTK_SHADOW_NONE)
427 border = 0;
428 else
429 border = 2;
430 #else
431 border = 0;
432 #endif
433
434 if (GTK_WIDGET_REALIZED (widget))
435 {
436 gdk_window_move_resize( widget->window,
437 allocation->x+border, allocation->y+border,
438 #if (GTK_MINOR_VERSION > 0)
439 allocation->width-border*2, allocation->height-border*2
440 #else
441 32000, 32000
442 #endif
443 );
444 }
445
446 children = myfixed->children;
447 while (children)
448 {
449 child = children->data;
450 children = children->next;
451
452 /* please look at the text in wxWindow::DoSetSize() on why the
453 test GTK_WIDGET_REALIZED() has to be here */
454 if (GTK_WIDGET_VISIBLE (child->widget) &&
455 !(!GTK_WIDGET_REALIZED(child->widget) &&
456 GTK_IS_NOTEBOOK(child->widget) ))
457 {
458 child_allocation.x = child->x;
459 child_allocation.y = child->y;
460 child_allocation.width = child->widget->requisition.width;
461 child_allocation.height = child->widget->requisition.height;
462 gtk_widget_size_allocate (child->widget, &child_allocation);
463 }
464 }
465 }
466
467 static void
468 gtk_myfixed_paint (GtkWidget *widget,
469 GdkRectangle *area)
470 {
471 g_return_if_fail (widget != NULL);
472 g_return_if_fail (GTK_IS_MYFIXED (widget));
473 g_return_if_fail (area != NULL);
474
475 if (GTK_WIDGET_DRAWABLE (widget))
476 gdk_window_clear_area (widget->window,
477 area->x, area->y,
478 area->width, area->height);
479 }
480
481 static void
482 gtk_myfixed_draw (GtkWidget *widget,
483 GdkRectangle *area)
484 {
485 GtkMyFixed *myfixed;
486 GtkMyFixedChild *child;
487 GdkRectangle child_area;
488 GList *children;
489
490 g_return_if_fail (widget != NULL);
491 g_return_if_fail (GTK_IS_MYFIXED (widget));
492
493 if (GTK_WIDGET_DRAWABLE (widget))
494 {
495 myfixed = GTK_MYFIXED (widget);
496 gtk_myfixed_paint (widget, area);
497
498 children = myfixed->children;
499 while (children)
500 {
501 child = children->data;
502 children = children->next;
503
504 if (gtk_widget_intersect (child->widget, area, &child_area))
505 gtk_widget_draw (child->widget, &child_area);
506 }
507 }
508 }
509
510 static gint
511 gtk_myfixed_expose (GtkWidget *widget,
512 GdkEventExpose *event)
513 {
514 GtkMyFixed *myfixed;
515 GtkMyFixedChild *child;
516 GdkEventExpose child_event;
517 GList *children;
518
519 g_return_val_if_fail (widget != NULL, FALSE);
520 g_return_val_if_fail (GTK_IS_MYFIXED (widget), FALSE);
521 g_return_val_if_fail (event != NULL, FALSE);
522
523 if (GTK_WIDGET_DRAWABLE (widget))
524 {
525 myfixed = GTK_MYFIXED (widget);
526
527 child_event = *event;
528
529 children = myfixed->children;
530 while (children)
531 {
532 child = children->data;
533 children = children->next;
534
535 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
536 gtk_widget_intersect (child->widget, &event->area,
537 &child_event.area))
538 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
539 }
540 }
541
542 return FALSE;
543 }
544
545 static void
546 gtk_myfixed_add (GtkContainer *container,
547 GtkWidget *widget)
548 {
549 g_return_if_fail (container != NULL);
550 g_return_if_fail (GTK_IS_MYFIXED (container));
551 g_return_if_fail (widget != NULL);
552
553 gtk_myfixed_put (GTK_MYFIXED (container), widget, 0, 0);
554 }
555
556 static void
557 gtk_myfixed_remove (GtkContainer *container,
558 GtkWidget *widget)
559 {
560 GtkMyFixed *myfixed;
561 GtkMyFixedChild *child;
562 GList *children;
563
564 g_return_if_fail (container != NULL);
565 g_return_if_fail (GTK_IS_MYFIXED (container));
566 g_return_if_fail (widget != NULL);
567
568 myfixed = GTK_MYFIXED (container);
569
570 children = myfixed->children;
571 while (children)
572 {
573 child = children->data;
574
575 if (child->widget == widget)
576 {
577 gtk_widget_unparent (widget);
578
579 myfixed->children = g_list_remove_link (myfixed->children, children);
580 g_list_free (children);
581 g_free (child);
582
583 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
584 gtk_widget_queue_resize (GTK_WIDGET (container));
585
586 break;
587 }
588
589 children = children->next;
590 }
591 }
592
593 static void
594 gtk_myfixed_foreach (GtkContainer *container,
595 #if (GTK_MINOR_VERSION > 0)
596 gboolean include_internals,
597 #endif
598 GtkCallback callback,
599 gpointer callback_data)
600 {
601 GtkMyFixed *myfixed;
602 GtkMyFixedChild *child;
603 GList *children;
604
605 g_return_if_fail (container != NULL);
606 g_return_if_fail (GTK_IS_MYFIXED (container));
607 g_return_if_fail (callback != NULL);
608
609 myfixed = GTK_MYFIXED (container);
610
611 children = myfixed->children;
612 while (children)
613 {
614 child = children->data;
615 children = children->next;
616
617 (* callback) (child->widget, callback_data);
618 }
619 }
620
621
622 #ifdef __cplusplus
623 }
624 #endif /* __cplusplus */
625