]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/win_gtk.c
Restored the ability to scroll.
[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 #include "gtk/gtkscrolledwindow.h"
14
15 #ifdef __cplusplus
16 extern "C" {
17 #endif /* __cplusplus */
18
19 static void gtk_myfixed_class_init (GtkMyFixedClass *klass);
20 static void gtk_myfixed_init (GtkMyFixed *myfixed);
21 static void gtk_myfixed_map (GtkWidget *widget);
22 #if (GTK_MINOR_VERSION == 0)
23 static void gtk_myfixed_unmap (GtkWidget *widget);
24 #endif
25 static void gtk_myfixed_realize (GtkWidget *widget);
26 static void gtk_myfixed_size_request (GtkWidget *widget,
27 GtkRequisition *requisition);
28 static void gtk_myfixed_size_allocate (GtkWidget *widget,
29 GtkAllocation *allocation);
30 static void gtk_myfixed_paint (GtkWidget *widget,
31 GdkRectangle *area);
32 static void gtk_myfixed_draw (GtkWidget *widget,
33 GdkRectangle *area);
34 static gint gtk_myfixed_expose (GtkWidget *widget,
35 GdkEventExpose *event);
36 static void gtk_myfixed_add (GtkContainer *container,
37 GtkWidget *widget);
38 static void gtk_myfixed_remove (GtkContainer *container,
39 GtkWidget *widget);
40 static void gtk_myfixed_foreach (GtkContainer *container,
41 #if (GTK_MINOR_VERSION > 0)
42 gboolean include_internals,
43 #endif
44 GtkCallback callback,
45 gpointer callback_data);
46 #if (GTK_MINOR_VERSION > 0)
47 static GtkType gtk_myfixed_child_type (GtkContainer *container);
48 #endif
49
50 #if (GTK_MINOR_VERSION > 0)
51 static void gtk_myfixed_scroll_set_adjustments (GtkMyFixed *myfixed,
52 GtkAdjustment *hadj,
53 GtkAdjustment *vadj);
54 #endif
55
56
57
58 static GtkContainerClass *parent_class = NULL;
59
60 guint
61 gtk_myfixed_get_type ()
62 {
63 static guint myfixed_type = 0;
64
65 if (!myfixed_type)
66 {
67 GtkTypeInfo myfixed_info =
68 {
69 "GtkMyFixed",
70 sizeof (GtkMyFixed),
71 sizeof (GtkMyFixedClass),
72 (GtkClassInitFunc) gtk_myfixed_class_init,
73 (GtkObjectInitFunc) gtk_myfixed_init,
74 #if (GTK_MINOR_VERSION > 0)
75 /* reserved_1 */ NULL,
76 /* reserved_2 */ NULL,
77 (GtkClassInitFunc) NULL,
78 #else
79 (GtkArgSetFunc) NULL,
80 (GtkArgGetFunc) NULL,
81 #endif
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
177 gtk_myfixed_scroll_set_adjustments (GtkMyFixed *myfixed,
178 GtkAdjustment *hadj,
179 GtkAdjustment *vadj)
180 {
181 /* OK, this is embarassing, but this function has to be here */
182 }
183
184 void
185 gtk_myfixed_set_shadow_type (GtkMyFixed *myfixed,
186 GtkShadowType type)
187 {
188 g_return_if_fail (myfixed != NULL);
189 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
190
191 if ((GtkShadowType) myfixed->shadow_type != type)
192 {
193 myfixed->shadow_type = type;
194
195 if (GTK_WIDGET_VISIBLE (myfixed))
196 {
197 gtk_widget_size_allocate (GTK_WIDGET (myfixed), &(GTK_WIDGET (myfixed)->allocation));
198 gtk_widget_queue_draw (GTK_WIDGET (myfixed));
199 }
200 }
201 }
202 #endif
203
204 void
205 gtk_myfixed_put (GtkMyFixed *myfixed,
206 GtkWidget *widget,
207 gint16 x,
208 gint16 y,
209 gint16 width,
210 gint16 height)
211 {
212 GtkMyFixedChild *child_info;
213
214 g_return_if_fail (myfixed != NULL);
215 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
216 g_return_if_fail (widget != NULL);
217
218 child_info = g_new (GtkMyFixedChild, 1);
219 child_info->widget = widget;
220 child_info->x = x;
221 child_info->y = y;
222 child_info->width = width;
223 child_info->height = height;
224
225 gtk_widget_set_parent (widget, GTK_WIDGET (myfixed));
226
227 myfixed->children = g_list_append (myfixed->children, child_info);
228
229 if (GTK_WIDGET_REALIZED (myfixed))
230 gtk_widget_realize (widget);
231
232 if (GTK_WIDGET_VISIBLE (myfixed) && GTK_WIDGET_VISIBLE (widget))
233 {
234 if (GTK_WIDGET_MAPPED (myfixed))
235 gtk_widget_map (widget);
236
237 gtk_widget_queue_resize (GTK_WIDGET (myfixed));
238 }
239 }
240
241 void
242 gtk_myfixed_move (GtkMyFixed *myfixed,
243 GtkWidget *widget,
244 gint16 x,
245 gint16 y)
246 {
247 GtkMyFixedChild *child;
248 GList *children;
249
250 g_return_if_fail (myfixed != NULL);
251 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
252 g_return_if_fail (widget != NULL);
253
254 children = myfixed->children;
255 while (children)
256 {
257 child = children->data;
258 children = children->next;
259
260 if (child->widget == widget)
261 {
262 gtk_myfixed_set_size( myfixed, widget, x, y, child->width, child->height );
263 break;
264 }
265 }
266 }
267
268 void
269 gtk_myfixed_resize (GtkMyFixed *myfixed,
270 GtkWidget *widget,
271 gint16 width,
272 gint16 height)
273 {
274 GtkMyFixedChild *child;
275 GList *children;
276
277 g_return_if_fail (myfixed != NULL);
278 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
279 g_return_if_fail (widget != NULL);
280
281 children = myfixed->children;
282 while (children)
283 {
284 child = children->data;
285 children = children->next;
286
287 if (child->widget == widget)
288 {
289 gtk_myfixed_set_size( myfixed, widget, child->x, child->y, width, height );
290 break;
291 }
292 }
293 }
294
295 void
296 gtk_myfixed_set_size (GtkMyFixed *myfixed,
297 GtkWidget *widget,
298 gint16 x,
299 gint16 y,
300 gint16 width,
301 gint16 height)
302 {
303 GtkMyFixedChild *child;
304 GList *children;
305 GtkAllocation child_allocation;
306
307 g_return_if_fail (myfixed != NULL);
308 g_return_if_fail (GTK_IS_MYFIXED (myfixed));
309 g_return_if_fail (widget != NULL);
310
311 children = myfixed->children;
312 while (children)
313 {
314 child = children->data;
315 children = children->next;
316
317 if (child->widget == widget)
318 {
319 if ((child->x == x) &&
320 (child->y == y) &&
321 (child->width == width) &&
322 (child->height == height)) return;
323
324 child->x = x;
325 child->y = y;
326 child->width = width;
327 child->height = height;
328
329 if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (myfixed))
330 {
331 if ( (child->width > 1) &&
332 (child->height > 1) &&
333 !(GTK_WIDGET_REALIZED(widget) && GTK_IS_NOTEBOOK(widget)) )
334 {
335 child_allocation.x = child->x;
336 child_allocation.y = child->y;
337 child_allocation.width = MAX( child->width, 1 );
338 child_allocation.height = MAX( child->height, 1 );
339
340 /* work around for GTK bug when moving widgets outside
341 the X window -> do NOT move them entirely outside */
342 if (child_allocation.y + child_allocation.height < 0)
343 child_allocation.y = -child_allocation.height;
344 if (child_allocation.x + child_allocation.width < 0)
345 child_allocation.x = -child_allocation.width;
346
347 gtk_widget_size_allocate (widget, &child_allocation);
348 }
349 else
350 {
351 gtk_widget_queue_resize (GTK_WIDGET (myfixed));
352 }
353 }
354 break;
355 }
356 }
357 }
358
359 static void
360 gtk_myfixed_map (GtkWidget *widget)
361 {
362 GtkMyFixed *myfixed;
363 GtkMyFixedChild *child;
364 GList *children;
365
366 g_return_if_fail (widget != NULL);
367 g_return_if_fail (GTK_IS_MYFIXED (widget));
368
369 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
370 myfixed = GTK_MYFIXED (widget);
371
372 children = myfixed->children;
373 while (children)
374 {
375 child = children->data;
376 children = children->next;
377
378 if (GTK_WIDGET_VISIBLE (child->widget) && !GTK_WIDGET_MAPPED (child->widget))
379 gtk_widget_map (child->widget);
380 }
381
382 gdk_window_show (widget->window);
383 }
384
385 #if (GTK_MINOR_VERSION == 0)
386 static void
387 gtk_myfixed_unmap (GtkWidget *widget)
388 {
389 g_return_if_fail (widget != NULL);
390 g_return_if_fail (GTK_IS_MYFIXED (widget));
391
392 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
393 }
394 #endif
395
396 static void
397 gtk_myfixed_realize (GtkWidget *widget)
398 {
399 GtkMyFixed *myfixed;
400 GdkWindowAttr attributes;
401 gint attributes_mask;
402
403 g_return_if_fail (widget != NULL);
404 g_return_if_fail (GTK_IS_MYFIXED (widget));
405
406 myfixed = GTK_MYFIXED (widget);
407
408 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
409
410 attributes.window_type = GDK_WINDOW_CHILD;
411
412 #if (GTK_MINOR_VERSION > 0)
413 attributes.x = widget->allocation.x;
414 attributes.y = widget->allocation.y;
415 attributes.width = widget->allocation.width;
416 attributes.height = widget->allocation.height;
417
418 if (myfixed->shadow_type != GTK_SHADOW_NONE)
419 {
420 attributes.x += 2;
421 attributes.y += 2;
422 attributes.width -= 4;
423 attributes.height -= 4;
424 }
425
426 if (attributes.width < 2) attributes.width = 2;
427 if (attributes.height < 2) attributes.height = 2;
428 #else
429 attributes.x = widget->allocation.x;
430 attributes.y = widget->allocation.y;
431 attributes.width = 32000;
432 attributes.height = 32000;
433 #endif
434 attributes.wclass = GDK_INPUT_OUTPUT;
435 attributes.visual = gtk_widget_get_visual (widget);
436 attributes.colormap = gtk_widget_get_colormap (widget);
437 attributes.event_mask = gtk_widget_get_events (widget);
438 attributes.event_mask |=
439 GDK_EXPOSURE_MASK |
440 GDK_POINTER_MOTION_MASK |
441 GDK_POINTER_MOTION_HINT_MASK |
442 GDK_BUTTON_MOTION_MASK |
443 GDK_BUTTON1_MOTION_MASK |
444 GDK_BUTTON2_MOTION_MASK |
445 GDK_BUTTON3_MOTION_MASK |
446 GDK_BUTTON_PRESS_MASK |
447 GDK_BUTTON_RELEASE_MASK |
448 GDK_KEY_PRESS_MASK |
449 GDK_KEY_RELEASE_MASK |
450 GDK_ENTER_NOTIFY_MASK |
451 GDK_LEAVE_NOTIFY_MASK |
452 GDK_FOCUS_CHANGE_MASK;
453 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
454
455 widget->window = gdk_window_new( gtk_widget_get_parent_window (widget), &attributes,
456 attributes_mask);
457 gdk_window_set_user_data (widget->window, widget);
458
459 widget->style = gtk_style_attach (widget->style, widget->window);
460 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
461 }
462
463 static void
464 gtk_myfixed_size_request (GtkWidget *widget,
465 GtkRequisition *requisition)
466 {
467 GtkMyFixed *myfixed;
468 GtkMyFixedChild *child;
469 GList *children;
470 GtkRequisition child_requisition;
471
472 g_return_if_fail (widget != NULL);
473 g_return_if_fail (GTK_IS_MYFIXED (widget));
474 g_return_if_fail (requisition != NULL);
475
476 myfixed = GTK_MYFIXED (widget);
477
478 children = myfixed->children;
479 while (children)
480 {
481 child = children->data;
482 children = children->next;
483
484 if (GTK_WIDGET_VISIBLE (child->widget))
485 {
486 gtk_widget_size_request (child->widget, &child_requisition);
487 }
488 }
489
490 /* request very little, I'm not sure if requesting nothing
491 will always have positive effects on stability... */
492 requisition->width = 2;
493 requisition->height = 2;
494 }
495
496 static void
497 gtk_myfixed_size_allocate (GtkWidget *widget,
498 GtkAllocation *allocation)
499 {
500 GtkMyFixed *myfixed;
501 gint border;
502 GtkMyFixedChild *child;
503 GtkAllocation child_allocation;
504 GList *children;
505
506 g_return_if_fail (widget != NULL);
507 g_return_if_fail (GTK_IS_MYFIXED(widget));
508 g_return_if_fail (allocation != NULL);
509
510 myfixed = GTK_MYFIXED (widget);
511
512 widget->allocation = *allocation;
513 #if (GTK_MINOR_VERSION > 0)
514 if (myfixed->shadow_type == GTK_SHADOW_NONE)
515 border = 0;
516 else
517 border = 2;
518 #else
519 border = 0;
520 #endif
521
522 if (GTK_WIDGET_REALIZED (widget))
523 {
524 gdk_window_move_resize( widget->window,
525 allocation->x+border, allocation->y+border,
526 #if (GTK_MINOR_VERSION > 0)
527 allocation->width-border*2, allocation->height-border*2
528 #else
529 32000, 32000
530 #endif
531 );
532 }
533
534 children = myfixed->children;
535 while (children)
536 {
537 child = children->data;
538 children = children->next;
539
540 if (GTK_WIDGET_VISIBLE (child->widget))
541 {
542 /* please look at the text in wxWindow::DoSetSize() on why the
543 test GTK_WIDGET_REALIZED() has to be here */
544 /* if (GTK_IS_NOTEBOOK(child->widget) && !GTK_WIDGET_REALIZED(child->widget))
545 {
546 gtk_widget_queue_resize( child->widget );
547 }
548 else */
549 {
550 child_allocation.x = child->x;
551 child_allocation.y = child->y;
552 child_allocation.width = MAX( child->width, 1 );
553 child_allocation.height = MAX( child->height, 1 );
554
555 /* work around for GTK bug when moving widgets outside
556 the X window -> do NOT move them entirely outside */
557 if (child_allocation.y + child_allocation.height < 0)
558 child_allocation.y = -child_allocation.height;
559 if (child_allocation.x + child_allocation.width < 0)
560 child_allocation.x = -child_allocation.width;
561
562 gtk_widget_size_allocate (child->widget, &child_allocation);
563 }
564 }
565 }
566 }
567
568 static void
569 gtk_myfixed_paint (GtkWidget *widget,
570 GdkRectangle *area)
571 {
572 g_return_if_fail (widget != NULL);
573 g_return_if_fail (GTK_IS_MYFIXED (widget));
574 g_return_if_fail (area != NULL);
575
576 if (GTK_WIDGET_DRAWABLE (widget))
577 gdk_window_clear_area (widget->window,
578 area->x, area->y,
579 area->width, area->height);
580 }
581
582 static void
583 gtk_myfixed_draw (GtkWidget *widget,
584 GdkRectangle *area)
585 {
586 GtkMyFixed *myfixed;
587 GtkMyFixedChild *child;
588 GdkRectangle child_area;
589 GList *children;
590
591 g_return_if_fail (widget != NULL);
592 g_return_if_fail (GTK_IS_MYFIXED (widget));
593
594 if (GTK_WIDGET_DRAWABLE (widget))
595 {
596 myfixed = GTK_MYFIXED (widget);
597 gtk_myfixed_paint (widget, area);
598
599 children = myfixed->children;
600 while (children)
601 {
602 child = children->data;
603 children = children->next;
604
605 if (gtk_widget_intersect (child->widget, area, &child_area))
606 gtk_widget_draw (child->widget, &child_area);
607 }
608 }
609 }
610
611 static gint
612 gtk_myfixed_expose (GtkWidget *widget,
613 GdkEventExpose *event)
614 {
615 GtkMyFixed *myfixed;
616 GtkMyFixedChild *child;
617 GdkEventExpose child_event;
618 GList *children;
619
620 g_return_val_if_fail (widget != NULL, FALSE);
621 g_return_val_if_fail (GTK_IS_MYFIXED (widget), FALSE);
622 g_return_val_if_fail (event != NULL, FALSE);
623
624 if (GTK_WIDGET_DRAWABLE (widget))
625 {
626 myfixed = GTK_MYFIXED (widget);
627
628 child_event = *event;
629
630 children = myfixed->children;
631 while (children)
632 {
633 child = children->data;
634 children = children->next;
635
636 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
637 gtk_widget_intersect (child->widget, &event->area,
638 &child_event.area))
639 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
640 }
641 }
642
643 return FALSE;
644 }
645
646 static void
647 gtk_myfixed_add (GtkContainer *container,
648 GtkWidget *widget)
649 {
650 g_return_if_fail (container != NULL);
651 g_return_if_fail (GTK_IS_MYFIXED (container));
652 g_return_if_fail (widget != NULL);
653
654 gtk_myfixed_put (GTK_MYFIXED (container), widget, 0, 0, 20, 20 );
655 }
656
657 static void
658 gtk_myfixed_remove (GtkContainer *container,
659 GtkWidget *widget)
660 {
661 GtkMyFixed *myfixed;
662 GtkMyFixedChild *child;
663 GList *children;
664
665 g_return_if_fail (container != NULL);
666 g_return_if_fail (GTK_IS_MYFIXED (container));
667 g_return_if_fail (widget != NULL);
668
669 myfixed = GTK_MYFIXED (container);
670
671 children = myfixed->children;
672 while (children)
673 {
674 child = children->data;
675
676 if (child->widget == widget)
677 {
678 gboolean was_visible = GTK_WIDGET_VISIBLE (widget);
679
680 gtk_widget_unparent (widget);
681
682 myfixed->children = g_list_remove_link (myfixed->children, children);
683 g_list_free (children);
684 g_free (child);
685
686 if (was_visible && GTK_WIDGET_VISIBLE (container))
687 gtk_widget_queue_resize (GTK_WIDGET (container));
688
689 break;
690 }
691
692 children = children->next;
693 }
694 }
695
696 static void
697 gtk_myfixed_foreach (GtkContainer *container,
698 #if (GTK_MINOR_VERSION > 0)
699 gboolean include_internals,
700 #endif
701 GtkCallback callback,
702 gpointer callback_data)
703 {
704 GtkMyFixed *myfixed;
705 GtkMyFixedChild *child;
706 GList *children;
707
708 g_return_if_fail (container != NULL);
709 g_return_if_fail (GTK_IS_MYFIXED (container));
710 g_return_if_fail (callback != NULL);
711
712 myfixed = GTK_MYFIXED (container);
713
714 children = myfixed->children;
715 while (children)
716 {
717 child = children->data;
718 children = children->next;
719
720 (* callback) (child->widget, callback_data);
721 }
722 }
723
724
725 #ifdef __cplusplus
726 }
727 #endif /* __cplusplus */
728