1 /* /////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Native GTK+ widget for wxWidgets, based on GtkLayout and 
   4 //              GtkFixed. It makes use of the gravity window property and 
   5 //              therefore does not work with GTK 1.0. 
   6 // Author:      Robert Roebling 
   8 // Copyright:   (c) 1998 Robert Roebling 
   9 // Licence:     wxWidgets licence 
  10 /////////////////////////////////////////////////////////////////////////// */ 
  13 #define XCheckIfEvent XCHECKIFEVENT 
  17 #include "wx/gtk/win_gtk.h" 
  18 #include "gtk/gtksignal.h" 
  19 #include "gtk/gtkprivate.h" 
  24 #endif /* __cplusplus */ 
  29 #include <X11/Xutil.h> 
  30 #include <X11/Xatom.h> 
  32 #define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \ 
  33                           (y >= G_MINSHORT) && (y <= G_MAXSHORT)) 
  37 typedef struct _GtkPizzaAdjData  GtkPizzaAdjData
; 
  39 struct _GtkPizzaAdjData
 
  45 static void gtk_pizza_class_init    (GtkPizzaClass    
*klass
); 
  46 static void gtk_pizza_init          (GtkPizza         
*pizza
); 
  48 static void gtk_pizza_realize       (GtkWidget        
*widget
); 
  49 static void gtk_pizza_unrealize     (GtkWidget        
*widget
); 
  51 static void gtk_pizza_map           (GtkWidget        
*widget
); 
  53 static void gtk_pizza_size_request  (GtkWidget        
*widget
, 
  54                                      GtkRequisition   
*requisition
); 
  55 static void gtk_pizza_size_allocate (GtkWidget        
*widget
, 
  56                                      GtkAllocation    
*allocation
); 
  58 static void gtk_pizza_draw          (GtkWidget        
*widget
, 
  60 #endif /* __WXGTK20__ */ 
  61 static gint 
gtk_pizza_expose        (GtkWidget        
*widget
, 
  62                                      GdkEventExpose   
*event
); 
  63 static void gtk_pizza_style_set     (GtkWidget 
*widget
, 
  64                                      GtkStyle  
*previous_style
); 
  65 static void gtk_pizza_add           (GtkContainer     
*container
, 
  67 static void gtk_pizza_remove        (GtkContainer     
*container
, 
  69 static void gtk_pizza_forall        (GtkContainer     
*container
, 
  70                                      gboolean          include_internals
, 
  72                                      gpointer          callback_data
); 
  74 static void     gtk_pizza_allocate_child     (GtkPizza      
*pizza
, 
  75                                               GtkPizzaChild 
*child
); 
  76 static void     gtk_pizza_adjust_allocations_recurse (GtkWidget 
*widget
, 
  80 static void     gtk_pizza_position_child     (GtkPizza      
*pizza
, 
  81                                               GtkPizzaChild 
*child
); 
  82 static void     gtk_pizza_position_children  (GtkPizza      
*pizza
); 
  84 static GdkFilterReturn 
gtk_pizza_filter      (GdkXEvent      
*gdk_xevent
, 
  87 static GdkFilterReturn 
gtk_pizza_main_filter (GdkXEvent      
*gdk_xevent
, 
  90 #endif /* __WXGTK20__ */ 
  92 static GtkType 
gtk_pizza_child_type (GtkContainer     
*container
); 
  94 static void  gtk_pizza_scroll_set_adjustments (GtkPizza      
*pizza
, 
 100        GtkContainerClass 
*pizza_parent_class 
= NULL
; 
 102 static GtkContainerClass 
*pizza_parent_class 
= NULL
; 
 106 static gboolean gravity_works
; 
 110 gtk_pizza_get_type () 
 112     static GtkType pizza_type 
= 0; 
 118         static const GTypeInfo pizza_info 
= 
 120             sizeof (GtkPizzaClass
), 
 121             NULL
,           /* base_init */ 
 122             NULL
,           /* base_finalize */ 
 123             (GClassInitFunc
) gtk_pizza_class_init
, 
 124             NULL
,           /* class_finalize */ 
 125             NULL
,           /* class_data */ 
 127             16,             /* n_preallocs */ 
 128             (GInstanceInitFunc
) gtk_pizza_init
, 
 130         pizza_type 
= g_type_register_static (GTK_TYPE_CONTAINER
, "GtkPizza", &pizza_info
, (GTypeFlags
)0); 
 132         GtkTypeInfo pizza_info 
= 
 136             sizeof (GtkPizzaClass
), 
 137             (GtkClassInitFunc
) gtk_pizza_class_init
, 
 138             (GtkObjectInitFunc
) gtk_pizza_init
, 
 139             /* reserved_1 */ NULL
, 
 140             /* reserved_2 */ NULL
, 
 141             (GtkClassInitFunc
) NULL
, 
 143         pizza_type 
= gtk_type_unique (gtk_container_get_type (), &pizza_info
); 
 151 /* Marshaller needed for set_scroll_adjustments signal, 
 152    generated with GLib-2.4.6 glib-genmarshal */ 
 153 #define g_marshal_value_peek_object(v)   g_value_get_object (v) 
 155 g_cclosure_user_marshal_VOID__OBJECT_OBJECT (GClosure     
*closure
, 
 156                                              GValue       
*return_value
, 
 157                                              guint         n_param_values
, 
 158                                              const GValue 
*param_values
, 
 159                                              gpointer      invocation_hint
, 
 160                                              gpointer      marshal_data
) 
 162   typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT
) (gpointer     data1
, 
 166   register GMarshalFunc_VOID__OBJECT_OBJECT callback
; 
 167   register GCClosure 
*cc 
= (GCClosure
*) closure
; 
 168   register gpointer data1
, data2
; 
 170   g_return_if_fail (n_param_values 
== 3); 
 172   if (G_CCLOSURE_SWAP_DATA (closure
)) 
 174       data1 
= closure
->data
; 
 175       data2 
= g_value_peek_pointer (param_values 
+ 0); 
 179       data1 
= g_value_peek_pointer (param_values 
+ 0); 
 180       data2 
= closure
->data
; 
 182   callback 
= (GMarshalFunc_VOID__OBJECT_OBJECT
) (marshal_data 
? marshal_data 
: cc
->callback
); 
 185             g_marshal_value_peek_object (param_values 
+ 1), 
 186             g_marshal_value_peek_object (param_values 
+ 2), 
 189 #endif /* __WXGTK20__ */ 
 192 gtk_pizza_class_init (GtkPizzaClass 
*klass
) 
 194     GtkObjectClass 
*object_class
; 
 195     GtkWidgetClass 
*widget_class
; 
 196     GtkContainerClass 
*container_class
; 
 198     object_class 
= (GtkObjectClass
*) klass
; 
 199     widget_class 
= (GtkWidgetClass
*) klass
; 
 200     container_class 
= (GtkContainerClass
*) klass
; 
 201     pizza_parent_class 
= gtk_type_class (GTK_TYPE_CONTAINER
); 
 203     widget_class
->map 
= gtk_pizza_map
; 
 204     widget_class
->realize 
= gtk_pizza_realize
; 
 205     widget_class
->unrealize 
= gtk_pizza_unrealize
; 
 206     widget_class
->size_request 
= gtk_pizza_size_request
; 
 207     widget_class
->size_allocate 
= gtk_pizza_size_allocate
; 
 209     widget_class
->draw 
= gtk_pizza_draw
; 
 211     widget_class
->expose_event 
= gtk_pizza_expose
; 
 212     widget_class
->style_set 
= gtk_pizza_style_set
; 
 214     container_class
->add 
= gtk_pizza_add
; 
 215     container_class
->remove 
= gtk_pizza_remove
; 
 216     container_class
->forall 
= gtk_pizza_forall
; 
 218     container_class
->child_type 
= gtk_pizza_child_type
; 
 220     klass
->set_scroll_adjustments 
= gtk_pizza_scroll_set_adjustments
; 
 222     widget_class
->set_scroll_adjustments_signal 
= 
 225             "set_scroll_adjustments", 
 226             G_TYPE_FROM_CLASS(object_class
), 
 228             G_STRUCT_OFFSET(GtkPizzaClass
, set_scroll_adjustments
), 
 231             g_cclosure_user_marshal_VOID__OBJECT_OBJECT
, 
 235             GTK_TYPE_ADJUSTMENT
); 
 237     gtk_signal_new ("set_scroll_adjustments", 
 240                     GTK_SIGNAL_OFFSET (GtkPizzaClass
, set_scroll_adjustments
), 
 241                     gtk_marshal_NONE__POINTER_POINTER
, 
 242                     GTK_TYPE_NONE
, 2, GTK_TYPE_ADJUSTMENT
, GTK_TYPE_ADJUSTMENT
); 
 243 #endif /* __WXGTK20__ */ 
 247 gtk_pizza_child_type (GtkContainer     
*container
) 
 249     return GTK_TYPE_WIDGET
; 
 253 gtk_pizza_init (GtkPizza 
*pizza
) 
 255     GTK_WIDGET_UNSET_FLAGS (pizza
, GTK_NO_WINDOW
); 
 257     pizza
->shadow_type 
= GTK_MYSHADOW_NONE
; 
 259     pizza
->children 
= NULL
; 
 264     pizza
->bin_window 
= NULL
; 
 269     pizza
->configure_serial 
= 0; 
 272     pizza
->visibility 
= GDK_VISIBILITY_PARTIAL
; 
 274     pizza
->clear_on_draw 
= TRUE
; 
 275     pizza
->use_filter 
= TRUE
; 
 276     pizza
->external_expose 
= FALSE
; 
 284     pizza 
= gtk_type_new (gtk_pizza_get_type ()); 
 286     return GTK_WIDGET (pizza
); 
 290 gtk_pizza_scroll_set_adjustments (GtkPizza     
*pizza
, 
 294    /* We handle scrolling in the wxScrolledWindow, not here. */ 
 298 gtk_pizza_set_shadow_type (GtkPizza        
*pizza
, 
 299                            GtkMyShadowType  type
) 
 301     g_return_if_fail (pizza 
!= NULL
); 
 302     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 304     if ((GtkMyShadowType
) pizza
->shadow_type 
!= type
) 
 306         pizza
->shadow_type 
= type
; 
 308         if (GTK_WIDGET_VISIBLE (pizza
)) 
 310             gtk_widget_size_allocate (GTK_WIDGET (pizza
), &(GTK_WIDGET (pizza
)->allocation
)); 
 311             gtk_widget_queue_draw (GTK_WIDGET (pizza
)); 
 317 gtk_pizza_set_clear (GtkPizza  
*pizza
, 
 320     g_return_if_fail (pizza 
!= NULL
); 
 321     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 323     pizza
->clear_on_draw 
= clear
; 
 327 gtk_pizza_set_filter (GtkPizza  
*pizza
, 
 330     g_return_if_fail (pizza 
!= NULL
); 
 331     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 333     pizza
->use_filter 
= use
; 
 337 gtk_pizza_set_external (GtkPizza  
*pizza
, 
 340     g_return_if_fail (pizza 
!= NULL
); 
 341     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 343     pizza
->external_expose 
= expose
; 
 347 gtk_pizza_put (GtkPizza   
*pizza
, 
 354     GtkPizzaChild 
*child_info
; 
 356     g_return_if_fail (pizza 
!= NULL
); 
 357     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 358     g_return_if_fail (widget 
!= NULL
); 
 360     child_info 
= g_new (GtkPizzaChild
, 1); 
 362     child_info
->widget 
= widget
; 
 365     child_info
->width 
= width
; 
 366     child_info
->height 
= height
; 
 368     pizza
->children 
= g_list_append (pizza
->children
, child_info
); 
 370     if (GTK_WIDGET_REALIZED (pizza
)) 
 371       gtk_widget_set_parent_window (widget
, pizza
->bin_window
); 
 373     gtk_widget_set_parent (widget
, GTK_WIDGET (pizza
)); 
 375 #ifndef __WXGTK20__ /* FIXME? */ 
 376     if (!IS_ONSCREEN (x
, y
)) 
 377        GTK_PRIVATE_SET_FLAG (widget
, GTK_IS_OFFSCREEN
); 
 380     gtk_widget_set_usize (widget
, width
, height
); 
 384 gtk_pizza_move (GtkPizza     
*pizza
, 
 389     GtkPizzaChild 
*child
; 
 392     g_return_if_fail (pizza 
!= NULL
); 
 393     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 394     g_return_if_fail (widget 
!= NULL
); 
 396     children 
= pizza
->children
; 
 399         child 
= children
->data
; 
 400         children 
= children
->next
; 
 402         if (child
->widget 
== widget
) 
 404             if ((child
->x 
== x
) && (child
->y 
== y
)) 
 410             if (GTK_WIDGET_VISIBLE (widget
) && GTK_WIDGET_VISIBLE (pizza
)) 
 411                 gtk_widget_queue_resize (widget
); 
 418 gtk_pizza_resize (GtkPizza    
*pizza
, 
 423     GtkPizzaChild 
*child
; 
 426     g_return_if_fail (pizza 
!= NULL
); 
 427     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 428     g_return_if_fail (widget 
!= NULL
); 
 430     children 
= pizza
->children
; 
 433         child 
= children
->data
; 
 434         children 
= children
->next
; 
 436         if (child
->widget 
== widget
) 
 438             if ((child
->width 
== width
) && (child
->height 
== height
)) 
 441             child
->width 
= width
; 
 442             child
->height 
= height
; 
 444             gtk_widget_set_usize (widget
, width
, height
); 
 446             if (GTK_WIDGET_VISIBLE (widget
) && GTK_WIDGET_VISIBLE (pizza
)) 
 447                 gtk_widget_queue_resize (widget
); 
 454 gtk_pizza_set_size (GtkPizza   
*pizza
, 
 461     GtkPizzaChild 
*child
; 
 464     g_return_if_fail (pizza 
!= NULL
); 
 465     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 466     g_return_if_fail (widget 
!= NULL
); 
 468     children 
= pizza
->children
; 
 471         child 
= children
->data
; 
 472         children 
= children
->next
; 
 474         if (child
->widget 
== widget
) 
 476             if ((child
->x 
== x
) && 
 478                 (child
->width 
== width
) && 
 479                 (child
->height 
== height
)) return; 
 483             child
->width 
= width
; 
 484             child
->height 
= height
; 
 486             gtk_widget_set_usize (widget
, width
, height
); 
 488             if (GTK_WIDGET_VISIBLE (widget
) && GTK_WIDGET_VISIBLE (pizza
)) 
 489                 gtk_widget_queue_resize (widget
); 
 497 gtk_pizza_child_resized  (GtkPizza   
*pizza
, 
 500     GtkPizzaChild 
*child
; 
 503     g_return_val_if_fail (pizza 
!= NULL
, FALSE
); 
 504     g_return_val_if_fail (GTK_IS_PIZZA (pizza
), FALSE
); 
 505     g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
 507     children 
= pizza
->children
; 
 510         child 
= children
->data
; 
 511         children 
= children
->next
; 
 513         if (child
->widget 
== widget
) 
 515             return ((child
->width 
== widget
->allocation
.width
) && 
 516                     (child
->height 
== widget
->allocation
.height
)); 
 524 gtk_pizza_map (GtkWidget 
*widget
) 
 527     GtkPizzaChild 
*child
; 
 530     g_return_if_fail (widget 
!= NULL
); 
 531     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 533     GTK_WIDGET_SET_FLAGS (widget
, GTK_MAPPED
); 
 534     pizza 
= GTK_PIZZA (widget
); 
 536     children 
= pizza
->children
; 
 539         child 
= children
->data
; 
 540         children 
= children
->next
; 
 542         if ( GTK_WIDGET_VISIBLE (child
->widget
) && 
 543             !GTK_WIDGET_MAPPED (child
->widget
) && 
 547             !GTK_WIDGET_IS_OFFSCREEN (child
->widget
)) 
 550             gtk_widget_map (child
->widget
); 
 554     gdk_window_show (widget
->window
); 
 555     gdk_window_show (pizza
->bin_window
); 
 559 gtk_pizza_realize (GtkWidget 
*widget
) 
 562     GdkWindowAttr attributes
; 
 563     gint attributes_mask
; 
 564     GtkPizzaChild 
*child
; 
 567     g_return_if_fail (widget 
!= NULL
); 
 568     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 570     pizza 
= GTK_PIZZA (widget
); 
 571     GTK_WIDGET_SET_FLAGS (widget
, GTK_REALIZED
); 
 573     attributes
.window_type 
= GDK_WINDOW_CHILD
; 
 575     attributes
.x 
= widget
->allocation
.x
; 
 576     attributes
.y 
= widget
->allocation
.y
; 
 577     attributes
.width 
= widget
->allocation
.width
; 
 578     attributes
.height 
= widget
->allocation
.height
; 
 580 #ifndef __WXUNIVERSAL__ 
 581     if (pizza
->shadow_type 
== GTK_MYSHADOW_NONE
) 
 583         /* no border, no changes to sizes */ 
 585     else if (pizza
->shadow_type 
== GTK_MYSHADOW_THIN
) 
 587         /* GTK_MYSHADOW_THIN == wxSIMPLE_BORDER */ 
 590         attributes
.width 
-= 2; 
 591         attributes
.height 
-= 2; 
 595         /* GTK_MYSHADOW_IN == wxSUNKEN_BORDER */ 
 596         /* GTK_MYSHADOW_OUT == wxRAISED_BORDER */ 
 599         attributes
.width 
-= 4; 
 600         attributes
.height 
-= 4; 
 602 #endif /* __WXUNIVERSAL__ */ 
 605     if (attributes
.width 
< 2) attributes
.width 
= 2; 
 606     if (attributes
.height 
< 2) attributes
.height 
= 2; 
 608     attributes
.wclass 
= GDK_INPUT_OUTPUT
; 
 609     attributes
.visual 
= gtk_widget_get_visual (widget
); 
 610     attributes
.colormap 
= gtk_widget_get_colormap (widget
); 
 611     attributes
.event_mask 
= GDK_VISIBILITY_NOTIFY_MASK
; 
 612     attributes_mask 
= GDK_WA_X 
| GDK_WA_Y 
| GDK_WA_VISUAL 
| GDK_WA_COLORMAP
; 
 614     widget
->window 
= gdk_window_new(gtk_widget_get_parent_window (widget
), 
 615                                      &attributes
, attributes_mask
); 
 616     gdk_window_set_user_data (widget
->window
, widget
); 
 621     attributes
.event_mask 
= gtk_widget_get_events (widget
); 
 622     attributes
.event_mask 
|= GDK_EXPOSURE_MASK              
| 
 626                              GDK_POINTER_MOTION_MASK        
| 
 627                              GDK_POINTER_MOTION_HINT_MASK   
| 
 628                              GDK_BUTTON_MOTION_MASK         
| 
 629                              GDK_BUTTON1_MOTION_MASK        
| 
 630                              GDK_BUTTON2_MOTION_MASK        
| 
 631                              GDK_BUTTON3_MOTION_MASK        
| 
 632                              GDK_BUTTON_PRESS_MASK          
| 
 633                              GDK_BUTTON_RELEASE_MASK        
| 
 635                              GDK_KEY_RELEASE_MASK           
| 
 636                              GDK_ENTER_NOTIFY_MASK          
| 
 637                              GDK_LEAVE_NOTIFY_MASK          
| 
 638                              GDK_FOCUS_CHANGE_MASK
; 
 640     pizza
->bin_window 
= gdk_window_new(widget
->window
, 
 641                                           &attributes
, attributes_mask
); 
 642     gdk_window_set_user_data (pizza
->bin_window
, widget
); 
 644     widget
->style 
= gtk_style_attach (widget
->style
, widget
->window
); 
 645     gtk_style_set_background (widget
->style
, widget
->window
, GTK_STATE_NORMAL
); 
 646     gtk_style_set_background (widget
->style
, pizza
->bin_window
, GTK_STATE_NORMAL 
); 
 649     gdk_window_set_back_pixmap( widget->window, NULL, FALSE ); 
 650     gdk_window_set_back_pixmap( pizza->bin_window, NULL, FALSE ); 
 654     /* add filters for intercepting visibility and expose events */ 
 655     gdk_window_add_filter (widget
->window
, gtk_pizza_main_filter
, pizza
); 
 656     gdk_window_add_filter (pizza
->bin_window
, gtk_pizza_filter
, pizza
); 
 658     /* we NEED gravity or we'll give up */ 
 659     gravity_works 
= gdk_window_set_static_gravities (pizza
->bin_window
, TRUE
); 
 660 #endif // !__WXGTK20__ 
 662     /* cannot be done before realisation */ 
 663     children 
= pizza
->children
; 
 666         child 
= children
->data
; 
 667         children 
= children
->next
; 
 669         gtk_widget_set_parent_window (child
->widget
, pizza
->bin_window
); 
 674 gtk_pizza_unrealize (GtkWidget 
*widget
) 
 678     g_return_if_fail (widget 
!= NULL
); 
 679     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 681     pizza 
= GTK_PIZZA (widget
); 
 683     gdk_window_set_user_data (pizza
->bin_window
, NULL
); 
 684     gdk_window_destroy (pizza
->bin_window
); 
 685     pizza
->bin_window 
= NULL
; 
 687     if (GTK_WIDGET_CLASS (pizza_parent_class
)->unrealize
) 
 688        (* GTK_WIDGET_CLASS (pizza_parent_class
)->unrealize
) (widget
); 
 692 gtk_pizza_size_request (GtkWidget      
*widget
, 
 693                         GtkRequisition 
*requisition
) 
 696     GtkPizzaChild 
*child
; 
 698     GtkRequisition child_requisition
; 
 700     g_return_if_fail (widget 
!= NULL
); 
 701     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 702     g_return_if_fail (requisition 
!= NULL
); 
 704     pizza 
= GTK_PIZZA (widget
); 
 706     children 
= pizza
->children
; 
 709         child 
= children
->data
; 
 710         children 
= children
->next
; 
 712         if (GTK_WIDGET_VISIBLE (child
->widget
)) 
 714             gtk_widget_size_request (child
->widget
, &child_requisition
); 
 718     /* request very little, I'm not sure if requesting nothing 
 719        will always have positive effects on stability... */ 
 720     requisition
->width 
= 2; 
 721     requisition
->height 
= 2; 
 725 gtk_pizza_size_allocate (GtkWidget     
*widget
, 
 726                          GtkAllocation 
*allocation
) 
 731     GtkPizzaChild 
*child
; 
 734     g_return_if_fail (widget 
!= NULL
); 
 735     g_return_if_fail (GTK_IS_PIZZA(widget
)); 
 736     g_return_if_fail (allocation 
!= NULL
); 
 738     pizza 
= GTK_PIZZA (widget
); 
 740     widget
->allocation 
= *allocation
; 
 742     if (pizza
->shadow_type 
== GTK_MYSHADOW_NONE
) 
 745     if (pizza
->shadow_type 
== GTK_MYSHADOW_THIN
) 
 750     x 
= allocation
->x 
+ border
; 
 751     y 
= allocation
->y 
+ border
; 
 752     w 
= allocation
->width 
- border
*2; 
 753     h 
= allocation
->height 
- border
*2; 
 755     if (GTK_WIDGET_REALIZED (widget
)) 
 757         gdk_window_move_resize( widget
->window
, x
, y
, w
, h 
); 
 758         gdk_window_move_resize( pizza
->bin_window
, 0, 0, w
, h 
); 
 761     children 
= pizza
->children
; 
 764         child 
= children
->data
; 
 765         children 
= children
->next
; 
 768         gtk_pizza_position_child (pizza
, child
); 
 770         gtk_pizza_allocate_child (pizza
, child
); 
 777 gtk_pizza_draw (GtkWidget    
*widget
, 
 781     GtkPizzaChild 
*child
; 
 782     GdkRectangle child_area
; 
 785     g_return_if_fail (widget 
!= NULL
); 
 786     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 788     pizza 
= GTK_PIZZA (widget
); 
 790     /* Sometimes, We handle all expose events in window.cpp now. */ 
 791     if (pizza
->external_expose
) 
 794     children 
= pizza
->children
; 
 795     if ( !(GTK_WIDGET_APP_PAINTABLE (widget
)) && 
 796          (pizza
->clear_on_draw
)) 
 798         gdk_window_clear_area( pizza
->bin_window
, 
 799                                 area
->x
, area
->y
, area
->width
, area
->height
); 
 804         child 
= children
->data
; 
 805         children 
= children
->next
; 
 807         if (gtk_widget_intersect (child
->widget
, area
, &child_area
)) 
 808             gtk_widget_draw (child
->widget
, &child_area
); 
 812 #endif /* __WXGTK20__ */ 
 815 gtk_pizza_expose (GtkWidget      
*widget
, 
 816                   GdkEventExpose 
*event
) 
 820     GtkPizzaChild 
*child
; 
 821     GdkEventExpose child_event
; 
 825     g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
 826     g_return_val_if_fail (GTK_IS_PIZZA (widget
), FALSE
); 
 827     g_return_val_if_fail (event 
!= NULL
, FALSE
); 
 829     pizza 
= GTK_PIZZA (widget
); 
 831     if (event
->window 
!= pizza
->bin_window
) 
 834     /* We handle all expose events in window.cpp now. */ 
 835     if (pizza
->external_expose
) 
 840     (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, event
); 
 846     children 
= pizza
->children
; 
 849         child 
= children
->data
; 
 850         children 
= children
->next
; 
 852         child_event 
= *event
; 
 854         if (GTK_WIDGET_NO_WINDOW (child
->widget
) && 
 855             GTK_WIDGET_DRAWABLE (child
->widget
) && 
 856             gtk_widget_intersect (child
->widget
, &event
->area
, &child_event
.area
)) 
 858             gtk_widget_event (child
->widget
, (GdkEvent
*) &child_event
); 
 868 gtk_pizza_style_set(GtkWidget 
*widget
, GtkStyle  
*previous_style
) 
 870     if (GTK_WIDGET_REALIZED(widget
)) 
 872         gtk_style_set_background(widget
->style
, widget
->window
, GTK_STATE_NORMAL
); 
 873         gtk_style_set_background(widget
->style
, GTK_PIZZA(widget
)->bin_window
, GTK_STATE_NORMAL 
); 
 876     (* GTK_WIDGET_CLASS (pizza_parent_class
)->style_set
) (widget
, previous_style
); 
 880 gtk_pizza_add (GtkContainer 
*container
, 
 883     g_return_if_fail (container 
!= NULL
); 
 884     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 885     g_return_if_fail (widget 
!= NULL
); 
 887     gtk_pizza_put (GTK_PIZZA (container
), widget
, 0, 0, 20, 20 ); 
 891 gtk_pizza_remove (GtkContainer 
*container
, 
 895     GtkPizzaChild 
*child
; 
 898     g_return_if_fail (container 
!= NULL
); 
 899     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 900     g_return_if_fail (widget 
!= NULL
); 
 902     pizza 
= GTK_PIZZA (container
); 
 904     children 
= pizza
->children
; 
 907         child 
= children
->data
; 
 909         if (child
->widget 
== widget
) 
 911             gtk_widget_unparent (widget
); 
 913             /* security checks */ 
 914             g_return_if_fail (GTK_IS_WIDGET (widget
)); 
 916             pizza
->children 
= g_list_remove_link (pizza
->children
, children
); 
 917             g_list_free (children
); 
 920             /* security checks */ 
 921             g_return_if_fail (GTK_IS_WIDGET (widget
)); 
 924             GTK_PRIVATE_UNSET_FLAG (widget
, GTK_IS_OFFSCREEN
); 
 930         children 
= children
->next
; 
 935 gtk_pizza_forall (GtkContainer 
*container
, 
 936                   gboolean      include_internals
, 
 937                   GtkCallback   callback
, 
 938                   gpointer      callback_data
) 
 941     GtkPizzaChild 
*child
; 
 944     g_return_if_fail (container 
!= NULL
); 
 945     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 946     g_return_if_fail (callback 
!= (GtkCallback
)NULL
); 
 948     pizza 
= GTK_PIZZA (container
); 
 950     children 
= pizza
->children
; 
 953         child 
= children
->data
; 
 954         children 
= children
->next
; 
 956         (* callback
) (child
->widget
, callback_data
); 
 961 gtk_pizza_allocate_child (GtkPizza      
*pizza
, 
 962                           GtkPizzaChild 
*child
) 
 964     GtkAllocation allocation
; 
 965     GtkRequisition requisition
; 
 967     allocation
.x 
= child
->x 
- pizza
->xoffset
; 
 968     allocation
.y 
= child
->y 
- pizza
->yoffset
; 
 969     gtk_widget_get_child_requisition (child
->widget
, &requisition
); 
 970     allocation
.width 
= requisition
.width
; 
 971     allocation
.height 
= requisition
.height
; 
 973     gtk_widget_size_allocate (child
->widget
, &allocation
); 
 977 gtk_pizza_adjust_allocations_recurse (GtkWidget 
*widget
, 
 980     GtkPizzaAdjData 
*data 
= cb_data
; 
 982     widget
->allocation
.x 
+= data
->dx
; 
 983     widget
->allocation
.y 
+= data
->dy
; 
 985     if (GTK_WIDGET_NO_WINDOW (widget
) && GTK_IS_CONTAINER (widget
)) 
 987         gtk_container_forall (GTK_CONTAINER (widget
), 
 988                           gtk_pizza_adjust_allocations_recurse
, 
 994 gtk_pizza_adjust_allocations (GtkPizza 
*pizza
, 
 999     GtkPizzaAdjData data
; 
1004     tmp_list 
= pizza
->children
; 
1007         GtkPizzaChild 
*child 
= tmp_list
->data
; 
1008         tmp_list 
= tmp_list
->next
; 
1010         child
->widget
->allocation
.x 
+= dx
; 
1011         child
->widget
->allocation
.y 
+= dy
; 
1013         if (GTK_WIDGET_NO_WINDOW (child
->widget
) && 
1014             GTK_IS_CONTAINER (child
->widget
)) 
1016             gtk_container_forall (GTK_CONTAINER (child
->widget
), 
1017                                   gtk_pizza_adjust_allocations_recurse
, 
1025 gtk_pizza_position_child (GtkPizza      
*pizza
, 
1026                           GtkPizzaChild 
*child
) 
1031     x 
= child
->x 
- pizza
->xoffset
; 
1032     y 
= child
->y 
- pizza
->yoffset
; 
1034     if (IS_ONSCREEN (x
,y
)) 
1036         if (GTK_WIDGET_MAPPED (pizza
) && 
1037           GTK_WIDGET_VISIBLE (child
->widget
)) 
1039             if (!GTK_WIDGET_MAPPED (child
->widget
)) 
1040                 gtk_widget_map (child
->widget
); 
1043         if (GTK_WIDGET_IS_OFFSCREEN (child
->widget
)) 
1044             GTK_PRIVATE_UNSET_FLAG (child
->widget
, GTK_IS_OFFSCREEN
); 
1048         if (!GTK_WIDGET_IS_OFFSCREEN (child
->widget
)) 
1049             GTK_PRIVATE_SET_FLAG (child
->widget
, GTK_IS_OFFSCREEN
); 
1051         if (GTK_WIDGET_MAPPED (child
->widget
)) 
1052             gtk_widget_unmap (child
->widget
); 
1057 gtk_pizza_position_children (GtkPizza 
*pizza
) 
1061     tmp_list 
= pizza
->children
; 
1064         GtkPizzaChild 
*child 
= tmp_list
->data
; 
1065         tmp_list 
= tmp_list
->next
; 
1067         gtk_pizza_position_child (pizza
, child
); 
1071 /* This function is used to find events to process while scrolling */ 
1073 gtk_pizza_expose_predicate (Display 
*display
, 
1077     if ((xevent
->type 
== Expose
) || 
1078        ((xevent
->xany
.window 
== *(Window 
*)arg
) && 
1079        (xevent
->type 
== ConfigureNotify
))) 
1084 #endif /* __WXGTK20__ */ 
1086 /* This is the main routine to do the scrolling. Scrolling is 
1087  * done by "Guffaw" scrolling, as in the Mozilla XFE, with 
1088  * a few modifications. 
1090  * The main improvement is that we keep track of whether we 
1091  * are obscured or not. If not, we ignore the generated expose 
1092  * events and instead do the exposes ourself, without having 
1093  * to wait for a roundtrip to the server. This also provides 
1094  * a limited form of expose-event compression, since we do 
1095  * the affected area as one big chunk. 
1099 gtk_pizza_scroll (GtkPizza 
*pizza
, gint dx
, gint dy
) 
1102     pizza
->xoffset 
+= dx
; 
1103     pizza
->yoffset 
+= dy
; 
1105     gtk_pizza_adjust_allocations (pizza
, -dx
, -dy
); 
1107     if (pizza
->bin_window
) 
1108         gdk_window_scroll( pizza
->bin_window
, -dx
, -dy 
); 
1109 #else // !__WXGTK20__ 
1114     gint x
,y
,w
,h
,border
; 
1116     widget 
= GTK_WIDGET (pizza
); 
1118     pizza
->xoffset 
+= dx
; 
1119     pizza
->yoffset 
+= dy
; 
1121     if (!GTK_WIDGET_MAPPED (pizza
)) 
1123         gtk_pizza_position_children (pizza
); 
1127     gtk_pizza_adjust_allocations (pizza
, -dx
, -dy
); 
1129     if (pizza
->shadow_type 
== GTK_MYSHADOW_NONE
) 
1132     if (pizza
->shadow_type 
== GTK_MYSHADOW_THIN
) 
1139     w 
= widget
->allocation
.width 
- 2*border
; 
1140     h 
= widget
->allocation
.height 
- 2*border
; 
1146           gdk_window_resize (pizza
->bin_window
, 
1149           gdk_window_move   (pizza
->bin_window
, x
-dx
, y
); 
1150           gdk_window_move_resize (pizza
->bin_window
, x
, y
, w
, h 
); 
1161           gdk_window_move_resize (pizza
->bin_window
, 
1166           gdk_window_move   (pizza
->bin_window
, x
, y
); 
1167           gdk_window_resize (pizza
->bin_window
, w
, h 
); 
1179           gdk_window_resize (pizza
->bin_window
, w
, h 
+ dy
); 
1180           gdk_window_move   (pizza
->bin_window
, x
, y
-dy
); 
1181           gdk_window_move_resize (pizza
->bin_window
, 
1193           gdk_window_move_resize (pizza
->bin_window
, 
1194                                   x
, y
+dy
, w
, h 
- dy 
); 
1195           gdk_window_move   (pizza
->bin_window
, x
, y
); 
1196           gdk_window_resize (pizza
->bin_window
, w
, h 
); 
1204     gtk_pizza_position_children (pizza
); 
1208     win 
= GDK_WINDOW_XWINDOW (pizza
->bin_window
); 
1209     while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (pizza
->bin_window
), 
1211                          gtk_pizza_expose_predicate
, 
1215         GtkWidget 
*event_widget
; 
1217         if ((xevent
.xany
.window 
== GDK_WINDOW_XWINDOW (pizza
->bin_window
)) ) 
1218             gtk_pizza_filter (&xevent
, &event
, pizza
); 
1220         if (xevent
.type 
== Expose
) 
1222             event
.expose
.window 
= gdk_window_lookup (xevent
.xany
.window
); 
1223             gdk_window_get_user_data (event
.expose
.window
, 
1224                                     (gpointer 
*)&event_widget
); 
1228                 event
.expose
.type 
= GDK_EXPOSE
; 
1229                 event
.expose
.area
.x 
= xevent
.xexpose
.x
; 
1230                 event
.expose
.area
.y 
= xevent
.xexpose
.y
; 
1231                 event
.expose
.area
.width 
= xevent
.xexpose
.width
; 
1232                 event
.expose
.area
.height 
= xevent
.xexpose
.height
; 
1233                 event
.expose
.count 
= xevent
.xexpose
.count
; 
1235                 gdk_window_ref (event
.expose
.window
); 
1236                 gtk_widget_event (event_widget
, &event
); 
1237                 gdk_window_unref (event
.expose
.window
); 
1241 #endif /* __WXGTK20__/!__WXGTK20__ */ 
1246 /* The main event filter. Actually, we probably don't really need 
1247  * to install this as a filter at all, since we are calling it 
1248  * directly above in the expose-handling hack. But in case scrollbars 
1249  * are fixed up in some manner... 
1251  * This routine identifies expose events that are generated when 
1252  * we've temporarily moved the bin_window_origin, and translates 
1253  * them or discards them, depending on whether we are obscured 
1256 static GdkFilterReturn
 
1257 gtk_pizza_filter (GdkXEvent 
*gdk_xevent
, 
1264     xevent 
= (XEvent 
*)gdk_xevent
; 
1266     pizza 
= GTK_PIZZA (data
); 
1268     if (!pizza
->use_filter
) 
1269         return GDK_FILTER_CONTINUE
; 
1271     switch (xevent
->type
) 
1274             if (xevent
->xexpose
.serial 
== pizza
->configure_serial
) 
1276                 xevent
->xexpose
.x 
+= pizza
->scroll_x
; 
1277                 xevent
->xexpose
.y 
+= pizza
->scroll_y
; 
1281         case ConfigureNotify
: 
1283                 pizza
->configure_serial 
= xevent
->xconfigure
.serial
; 
1284                 pizza
->scroll_x 
= xevent
->xconfigure
.x
; 
1285                 pizza
->scroll_y 
= xevent
->xconfigure
.y
; 
1290     return GDK_FILTER_CONTINUE
; 
1293 /* Although GDK does have a GDK_VISIBILITY_NOTIFY event, 
1294  * there is no corresponding event in GTK, so we have 
1295  * to get the events from a filter 
1297 static GdkFilterReturn
 
1298 gtk_pizza_main_filter (GdkXEvent 
*gdk_xevent
, 
1305     xevent 
= (XEvent 
*)gdk_xevent
; 
1306     pizza 
= GTK_PIZZA (data
); 
1308     if (!pizza
->use_filter
) 
1309         return GDK_FILTER_CONTINUE
; 
1311     if (xevent
->type 
== VisibilityNotify
) 
1313         switch (xevent
->xvisibility
.state
) 
1315             case VisibilityFullyObscured
: 
1316                 pizza
->visibility 
= GDK_VISIBILITY_FULLY_OBSCURED
; 
1319             case VisibilityPartiallyObscured
: 
1320                 pizza
->visibility 
= GDK_VISIBILITY_PARTIAL
; 
1323             case VisibilityUnobscured
: 
1324                 pizza
->visibility 
= GDK_VISIBILITY_UNOBSCURED
; 
1328         return GDK_FILTER_REMOVE
; 
1331     return GDK_FILTER_CONTINUE
; 
1333 #endif /* __WXGTK20__ */ 
1338 #endif /* __cplusplus */