1 /* /////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk1/win_gtk.c 
   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 
  16 #include "wx/platform.h" 
  17 #include "wx/gtk1/win_gtk.h" 
  18 #include "gtk/gtksignal.h" 
  19 #include "gtk/gtkprivate.h" 
  24 #endif /* __cplusplus */ 
  27 #include <X11/Xutil.h> 
  28 #include <X11/Xatom.h> 
  30 #define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \ 
  31                           (y >= G_MINSHORT) && (y <= G_MAXSHORT)) 
  34 typedef struct _GtkPizzaAdjData  GtkPizzaAdjData
; 
  36 struct _GtkPizzaAdjData
 
  42 static void gtk_pizza_class_init    (GtkPizzaClass    
*klass
); 
  43 static void gtk_pizza_init          (GtkPizza         
*pizza
); 
  45 static void gtk_pizza_realize       (GtkWidget        
*widget
); 
  46 static void gtk_pizza_unrealize     (GtkWidget        
*widget
); 
  48 static void gtk_pizza_map           (GtkWidget        
*widget
); 
  50 static void gtk_pizza_size_request  (GtkWidget        
*widget
, 
  51                                      GtkRequisition   
*requisition
); 
  52 static void gtk_pizza_size_allocate (GtkWidget        
*widget
, 
  53                                      GtkAllocation    
*allocation
); 
  54 static void gtk_pizza_draw          (GtkWidget        
*widget
, 
  56 static gint 
gtk_pizza_expose        (GtkWidget        
*widget
, 
  57                                      GdkEventExpose   
*event
); 
  58 static void gtk_pizza_style_set     (GtkWidget 
*widget
, 
  59                                      GtkStyle  
*previous_style
); 
  60 static void gtk_pizza_add           (GtkContainer     
*container
, 
  62 static void gtk_pizza_remove        (GtkContainer     
*container
, 
  64 static void gtk_pizza_forall        (GtkContainer     
*container
, 
  65                                      gboolean          include_internals
, 
  67                                      gpointer          callback_data
); 
  69 static void     gtk_pizza_allocate_child     (GtkPizza      
*pizza
, 
  70                                               GtkPizzaChild 
*child
); 
  71 static void     gtk_pizza_adjust_allocations_recurse (GtkWidget 
*widget
, 
  74 static void     gtk_pizza_position_child     (GtkPizza      
*pizza
, 
  75                                               GtkPizzaChild 
*child
); 
  76 static void     gtk_pizza_position_children  (GtkPizza      
*pizza
); 
  78 static GdkFilterReturn 
gtk_pizza_filter      (GdkXEvent      
*gdk_xevent
, 
  81 static GdkFilterReturn 
gtk_pizza_main_filter (GdkXEvent      
*gdk_xevent
, 
  85 static GtkType 
gtk_pizza_child_type (GtkContainer     
*container
); 
  87 static void  gtk_pizza_scroll_set_adjustments (GtkPizza      
*pizza
, 
  92 static GtkContainerClass 
*pizza_parent_class 
= NULL
; 
  94 static gboolean gravity_works
; 
  99     static GtkType pizza_type 
= 0; 
 103         GtkTypeInfo pizza_info 
= 
 107             sizeof (GtkPizzaClass
), 
 108             (GtkClassInitFunc
) gtk_pizza_class_init
, 
 109             (GtkObjectInitFunc
) gtk_pizza_init
, 
 110             /* reserved_1 */ NULL
, 
 111             /* reserved_2 */ NULL
, 
 112             (GtkClassInitFunc
) NULL
, 
 114         pizza_type 
= gtk_type_unique (gtk_container_get_type (), &pizza_info
); 
 121 gtk_pizza_class_init (GtkPizzaClass 
*klass
) 
 123     GtkObjectClass 
*object_class
; 
 124     GtkWidgetClass 
*widget_class
; 
 125     GtkContainerClass 
*container_class
; 
 127     object_class 
= (GtkObjectClass
*) klass
; 
 128     widget_class 
= (GtkWidgetClass
*) klass
; 
 129     container_class 
= (GtkContainerClass
*) klass
; 
 130     pizza_parent_class 
= gtk_type_class (GTK_TYPE_CONTAINER
); 
 132     widget_class
->map 
= gtk_pizza_map
; 
 133     widget_class
->realize 
= gtk_pizza_realize
; 
 134     widget_class
->unrealize 
= gtk_pizza_unrealize
; 
 135     widget_class
->size_request 
= gtk_pizza_size_request
; 
 136     widget_class
->size_allocate 
= gtk_pizza_size_allocate
; 
 137     widget_class
->draw 
= gtk_pizza_draw
; 
 138     widget_class
->expose_event 
= gtk_pizza_expose
; 
 139     widget_class
->style_set 
= gtk_pizza_style_set
; 
 141     container_class
->add 
= gtk_pizza_add
; 
 142     container_class
->remove 
= gtk_pizza_remove
; 
 143     container_class
->forall 
= gtk_pizza_forall
; 
 145     container_class
->child_type 
= gtk_pizza_child_type
; 
 147     klass
->set_scroll_adjustments 
= gtk_pizza_scroll_set_adjustments
; 
 149     widget_class
->set_scroll_adjustments_signal 
= 
 150     gtk_signal_new ("set_scroll_adjustments", 
 153                     GTK_SIGNAL_OFFSET (GtkPizzaClass
, set_scroll_adjustments
), 
 154                     gtk_marshal_NONE__POINTER_POINTER
, 
 155                     GTK_TYPE_NONE
, 2, GTK_TYPE_ADJUSTMENT
, GTK_TYPE_ADJUSTMENT
); 
 159 gtk_pizza_child_type (GtkContainer     
*container
) 
 161     return GTK_TYPE_WIDGET
; 
 165 gtk_pizza_init (GtkPizza 
*pizza
) 
 167     GTK_WIDGET_UNSET_FLAGS (pizza
, GTK_NO_WINDOW
); 
 169     pizza
->shadow_type 
= GTK_MYSHADOW_NONE
; 
 171     pizza
->children 
= NULL
; 
 176     pizza
->bin_window 
= NULL
; 
 181     pizza
->configure_serial 
= 0; 
 184     pizza
->visibility 
= GDK_VISIBILITY_PARTIAL
; 
 186     pizza
->clear_on_draw 
= TRUE
; 
 187     pizza
->use_filter 
= TRUE
; 
 188     pizza
->external_expose 
= FALSE
; 
 196     pizza 
= gtk_type_new (gtk_pizza_get_type ()); 
 198     return GTK_WIDGET (pizza
); 
 202 gtk_pizza_scroll_set_adjustments (GtkPizza     
*pizza
, 
 206    /* We handle scrolling in the wxScrolledWindow, not here. */ 
 210 gtk_pizza_set_shadow_type (GtkPizza        
*pizza
, 
 211                            GtkMyShadowType  type
) 
 213     g_return_if_fail (pizza 
!= NULL
); 
 214     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 216     if ((GtkMyShadowType
) pizza
->shadow_type 
!= type
) 
 218         pizza
->shadow_type 
= type
; 
 220         if (GTK_WIDGET_VISIBLE (pizza
)) 
 222             gtk_widget_size_allocate (GTK_WIDGET (pizza
), &(GTK_WIDGET (pizza
)->allocation
)); 
 223             gtk_widget_queue_draw (GTK_WIDGET (pizza
)); 
 229 gtk_pizza_set_clear (GtkPizza  
*pizza
, 
 232     g_return_if_fail (pizza 
!= NULL
); 
 233     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 235     pizza
->clear_on_draw 
= clear
; 
 239 gtk_pizza_set_filter (GtkPizza  
*pizza
, 
 242     g_return_if_fail (pizza 
!= NULL
); 
 243     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 245     pizza
->use_filter 
= use
; 
 249 gtk_pizza_set_external (GtkPizza  
*pizza
, 
 252     g_return_if_fail (pizza 
!= NULL
); 
 253     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 255     pizza
->external_expose 
= expose
; 
 259 gtk_pizza_put (GtkPizza   
*pizza
, 
 266     GtkPizzaChild 
*child_info
; 
 268     g_return_if_fail (pizza 
!= NULL
); 
 269     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 270     g_return_if_fail (widget 
!= NULL
); 
 272     child_info 
= g_new (GtkPizzaChild
, 1); 
 274     child_info
->widget 
= widget
; 
 277     child_info
->width 
= width
; 
 278     child_info
->height 
= height
; 
 280     pizza
->children 
= g_list_append (pizza
->children
, child_info
); 
 282     if (GTK_WIDGET_REALIZED (pizza
)) 
 283       gtk_widget_set_parent_window (widget
, pizza
->bin_window
); 
 285     gtk_widget_set_parent (widget
, GTK_WIDGET (pizza
)); 
 287     if (!IS_ONSCREEN (x
, y
)) 
 288        GTK_PRIVATE_SET_FLAG (widget
, GTK_IS_OFFSCREEN
); 
 290     gtk_widget_set_usize (widget
, width
, height
); 
 294 gtk_pizza_move (GtkPizza     
*pizza
, 
 299     GtkPizzaChild 
*child
; 
 302     g_return_if_fail (pizza 
!= NULL
); 
 303     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 304     g_return_if_fail (widget 
!= NULL
); 
 306     children 
= pizza
->children
; 
 309         child 
= children
->data
; 
 310         children 
= children
->next
; 
 312         if (child
->widget 
== widget
) 
 314             if ((child
->x 
== x
) && (child
->y 
== y
)) 
 320             if (GTK_WIDGET_VISIBLE (widget
) && GTK_WIDGET_VISIBLE (pizza
)) 
 321                 gtk_widget_queue_resize (widget
); 
 328 gtk_pizza_resize (GtkPizza    
*pizza
, 
 333     GtkPizzaChild 
*child
; 
 336     g_return_if_fail (pizza 
!= NULL
); 
 337     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 338     g_return_if_fail (widget 
!= NULL
); 
 340     children 
= pizza
->children
; 
 343         child 
= children
->data
; 
 344         children 
= children
->next
; 
 346         if (child
->widget 
== widget
) 
 348             if ((child
->width 
== width
) && (child
->height 
== height
)) 
 351             child
->width 
= width
; 
 352             child
->height 
= height
; 
 354             gtk_widget_set_usize (widget
, width
, height
); 
 356             if (GTK_WIDGET_VISIBLE (widget
) && GTK_WIDGET_VISIBLE (pizza
)) 
 357                 gtk_widget_queue_resize (widget
); 
 364 gtk_pizza_set_size (GtkPizza   
*pizza
, 
 371     GtkPizzaChild 
*child
; 
 374     g_return_if_fail (pizza 
!= NULL
); 
 375     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 376     g_return_if_fail (widget 
!= NULL
); 
 378     children 
= pizza
->children
; 
 381         child 
= children
->data
; 
 382         children 
= children
->next
; 
 384         if (child
->widget 
== widget
) 
 386             if ((child
->x 
== x
) && 
 388                 (child
->width 
== width
) && 
 389                 (child
->height 
== height
)) return; 
 393             child
->width 
= width
; 
 394             child
->height 
= height
; 
 396             gtk_widget_set_usize (widget
, width
, height
); 
 398             if (GTK_WIDGET_VISIBLE (widget
) && GTK_WIDGET_VISIBLE (pizza
)) 
 399                 gtk_widget_queue_resize (widget
); 
 407 gtk_pizza_child_resized  (GtkPizza   
*pizza
, 
 410     GtkPizzaChild 
*child
; 
 413     g_return_val_if_fail (pizza 
!= NULL
, FALSE
); 
 414     g_return_val_if_fail (GTK_IS_PIZZA (pizza
), FALSE
); 
 415     g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
 417     children 
= pizza
->children
; 
 420         child 
= children
->data
; 
 421         children 
= children
->next
; 
 423         if (child
->widget 
== widget
) 
 425             return ((child
->width 
== widget
->allocation
.width
) && 
 426                     (child
->height 
== widget
->allocation
.height
)); 
 434 gtk_pizza_map (GtkWidget 
*widget
) 
 437     GtkPizzaChild 
*child
; 
 440     g_return_if_fail (widget 
!= NULL
); 
 441     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 443     GTK_WIDGET_SET_FLAGS (widget
, GTK_MAPPED
); 
 444     pizza 
= GTK_PIZZA (widget
); 
 446     children 
= pizza
->children
; 
 449         child 
= children
->data
; 
 450         children 
= children
->next
; 
 452         if ( GTK_WIDGET_VISIBLE (child
->widget
) && 
 453             !GTK_WIDGET_MAPPED (child
->widget
) && 
 454             !GTK_WIDGET_IS_OFFSCREEN (child
->widget
)) 
 456             gtk_widget_map (child
->widget
); 
 460     gdk_window_show (widget
->window
); 
 461     gdk_window_show (pizza
->bin_window
); 
 465 gtk_pizza_realize (GtkWidget 
*widget
) 
 468     GdkWindowAttr attributes
; 
 469     gint attributes_mask
; 
 470     GtkPizzaChild 
*child
; 
 473     g_return_if_fail (widget 
!= NULL
); 
 474     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 476     pizza 
= GTK_PIZZA (widget
); 
 477     GTK_WIDGET_SET_FLAGS (widget
, GTK_REALIZED
); 
 479     attributes
.window_type 
= GDK_WINDOW_CHILD
; 
 481     attributes
.x 
= widget
->allocation
.x
; 
 482     attributes
.y 
= widget
->allocation
.y
; 
 483     attributes
.width 
= widget
->allocation
.width
; 
 484     attributes
.height 
= widget
->allocation
.height
; 
 486 #ifndef __WXUNIVERSAL__ 
 487     if (pizza
->shadow_type 
== GTK_MYSHADOW_NONE
) 
 489         /* no border, no changes to sizes */ 
 491     else if (pizza
->shadow_type 
== GTK_MYSHADOW_THIN
) 
 493         /* GTK_MYSHADOW_THIN == wxSIMPLE_BORDER */ 
 496         attributes
.width 
-= 2; 
 497         attributes
.height 
-= 2; 
 501         /* GTK_MYSHADOW_IN == wxSUNKEN_BORDER */ 
 502         /* GTK_MYSHADOW_OUT == wxRAISED_BORDER */ 
 505         attributes
.width 
-= 4; 
 506         attributes
.height 
-= 4; 
 508 #endif /* __WXUNIVERSAL__ */ 
 511     if (attributes
.width 
< 2) attributes
.width 
= 2; 
 512     if (attributes
.height 
< 2) attributes
.height 
= 2; 
 514     attributes
.wclass 
= GDK_INPUT_OUTPUT
; 
 515     attributes
.visual 
= gtk_widget_get_visual (widget
); 
 516     attributes
.colormap 
= gtk_widget_get_colormap (widget
); 
 517     attributes
.event_mask 
= GDK_VISIBILITY_NOTIFY_MASK
; 
 518     attributes_mask 
= GDK_WA_X 
| GDK_WA_Y 
| GDK_WA_VISUAL 
| GDK_WA_COLORMAP
; 
 520     widget
->window 
= gdk_window_new(gtk_widget_get_parent_window (widget
), 
 521                                      &attributes
, attributes_mask
); 
 522     gdk_window_set_user_data (widget
->window
, widget
); 
 527     attributes
.event_mask 
= gtk_widget_get_events (widget
); 
 528     attributes
.event_mask 
|= GDK_EXPOSURE_MASK              
| 
 529                              GDK_POINTER_MOTION_MASK        
| 
 530                              GDK_POINTER_MOTION_HINT_MASK   
| 
 531                              GDK_BUTTON_MOTION_MASK         
| 
 532                              GDK_BUTTON1_MOTION_MASK        
| 
 533                              GDK_BUTTON2_MOTION_MASK        
| 
 534                              GDK_BUTTON3_MOTION_MASK        
| 
 535                              GDK_BUTTON_PRESS_MASK          
| 
 536                              GDK_BUTTON_RELEASE_MASK        
| 
 538                              GDK_KEY_RELEASE_MASK           
| 
 539                              GDK_ENTER_NOTIFY_MASK          
| 
 540                              GDK_LEAVE_NOTIFY_MASK          
| 
 541                              GDK_FOCUS_CHANGE_MASK
; 
 543     pizza
->bin_window 
= gdk_window_new(widget
->window
, 
 544                                           &attributes
, attributes_mask
); 
 545     gdk_window_set_user_data (pizza
->bin_window
, widget
); 
 547     widget
->style 
= gtk_style_attach (widget
->style
, widget
->window
); 
 548     gtk_style_set_background (widget
->style
, widget
->window
, GTK_STATE_NORMAL
); 
 549     gtk_style_set_background (widget
->style
, pizza
->bin_window
, GTK_STATE_NORMAL 
); 
 552     gdk_window_set_back_pixmap( widget->window, NULL, FALSE ); 
 553     gdk_window_set_back_pixmap( pizza->bin_window, NULL, FALSE ); 
 556     /* add filters for intercepting visibility and expose events */ 
 557     gdk_window_add_filter (widget
->window
, gtk_pizza_main_filter
, pizza
); 
 558     gdk_window_add_filter (pizza
->bin_window
, gtk_pizza_filter
, pizza
); 
 560     /* we NEED gravity or we'll give up */ 
 561     gravity_works 
= gdk_window_set_static_gravities (pizza
->bin_window
, TRUE
); 
 563     /* cannot be done before realisation */ 
 564     children 
= pizza
->children
; 
 567         child 
= children
->data
; 
 568         children 
= children
->next
; 
 570         gtk_widget_set_parent_window (child
->widget
, pizza
->bin_window
); 
 575 gtk_pizza_unrealize (GtkWidget 
*widget
) 
 579     g_return_if_fail (widget 
!= NULL
); 
 580     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 582     pizza 
= GTK_PIZZA (widget
); 
 584     gdk_window_set_user_data (pizza
->bin_window
, NULL
); 
 585     gdk_window_destroy (pizza
->bin_window
); 
 586     pizza
->bin_window 
= NULL
; 
 588     if (GTK_WIDGET_CLASS (pizza_parent_class
)->unrealize
) 
 589        (* GTK_WIDGET_CLASS (pizza_parent_class
)->unrealize
) (widget
); 
 593 gtk_pizza_size_request (GtkWidget      
*widget
, 
 594                         GtkRequisition 
*requisition
) 
 597     GtkPizzaChild 
*child
; 
 599     GtkRequisition child_requisition
; 
 601     g_return_if_fail (widget 
!= NULL
); 
 602     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 603     g_return_if_fail (requisition 
!= NULL
); 
 605     pizza 
= GTK_PIZZA (widget
); 
 607     children 
= pizza
->children
; 
 610         child 
= children
->data
; 
 611         children 
= children
->next
; 
 613         if (GTK_WIDGET_VISIBLE (child
->widget
)) 
 615             gtk_widget_size_request (child
->widget
, &child_requisition
); 
 619     /* request very little, I'm not sure if requesting nothing 
 620        will always have positive effects on stability... */ 
 621     requisition
->width 
= 2; 
 622     requisition
->height 
= 2; 
 626 gtk_pizza_size_allocate (GtkWidget     
*widget
, 
 627                          GtkAllocation 
*allocation
) 
 632     GtkPizzaChild 
*child
; 
 635     g_return_if_fail (widget 
!= NULL
); 
 636     g_return_if_fail (GTK_IS_PIZZA(widget
)); 
 637     g_return_if_fail (allocation 
!= NULL
); 
 639     pizza 
= GTK_PIZZA (widget
); 
 641     widget
->allocation 
= *allocation
; 
 643     if (pizza
->shadow_type 
== GTK_MYSHADOW_NONE
) 
 646     if (pizza
->shadow_type 
== GTK_MYSHADOW_THIN
) 
 651     x 
= allocation
->x 
+ border
; 
 652     y 
= allocation
->y 
+ border
; 
 653     w 
= allocation
->width 
- border
*2; 
 654     h 
= allocation
->height 
- border
*2; 
 656     if (GTK_WIDGET_REALIZED (widget
)) 
 658         gdk_window_move_resize( widget
->window
, x
, y
, w
, h 
); 
 659         gdk_window_move_resize( pizza
->bin_window
, 0, 0, w
, h 
); 
 662     children 
= pizza
->children
; 
 665         child 
= children
->data
; 
 666         children 
= children
->next
; 
 668         gtk_pizza_position_child (pizza
, child
); 
 669         gtk_pizza_allocate_child (pizza
, child
); 
 674 gtk_pizza_draw (GtkWidget    
*widget
, 
 678     GtkPizzaChild 
*child
; 
 679     GdkRectangle child_area
; 
 682     g_return_if_fail (widget 
!= NULL
); 
 683     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 685     pizza 
= GTK_PIZZA (widget
); 
 687     /* Sometimes, We handle all expose events in window.cpp now. */ 
 688     if (pizza
->external_expose
) 
 691     children 
= pizza
->children
; 
 692     if ( !(GTK_WIDGET_APP_PAINTABLE (widget
)) && 
 693          (pizza
->clear_on_draw
)) 
 695         gdk_window_clear_area( pizza
->bin_window
, 
 696                                 area
->x
, area
->y
, area
->width
, area
->height
); 
 701         child 
= children
->data
; 
 702         children 
= children
->next
; 
 704         if (gtk_widget_intersect (child
->widget
, area
, &child_area
)) 
 705             gtk_widget_draw (child
->widget
, &child_area
); 
 710 gtk_pizza_expose (GtkWidget      
*widget
, 
 711                   GdkEventExpose 
*event
) 
 714     GtkPizzaChild 
*child
; 
 715     GdkEventExpose child_event
; 
 718     g_return_val_if_fail (widget 
!= NULL
, FALSE
); 
 719     g_return_val_if_fail (GTK_IS_PIZZA (widget
), FALSE
); 
 720     g_return_val_if_fail (event 
!= NULL
, FALSE
); 
 722     pizza 
= GTK_PIZZA (widget
); 
 724     if (event
->window 
!= pizza
->bin_window
) 
 727     /* We handle all expose events in window.cpp now. */ 
 728     if (pizza
->external_expose
) 
 731     children 
= pizza
->children
; 
 734         child 
= children
->data
; 
 735         children 
= children
->next
; 
 737         child_event 
= *event
; 
 739         if (GTK_WIDGET_NO_WINDOW (child
->widget
) && 
 740             GTK_WIDGET_DRAWABLE (child
->widget
) && 
 741             gtk_widget_intersect (child
->widget
, &event
->area
, &child_event
.area
)) 
 743             gtk_widget_event (child
->widget
, (GdkEvent
*) &child_event
); 
 751 gtk_pizza_style_set(GtkWidget 
*widget
, GtkStyle  
*previous_style
) 
 753     if (GTK_WIDGET_REALIZED(widget
)) 
 755         gtk_style_set_background(widget
->style
, widget
->window
, GTK_STATE_NORMAL
); 
 756         gtk_style_set_background(widget
->style
, GTK_PIZZA(widget
)->bin_window
, GTK_STATE_NORMAL 
); 
 759     (* GTK_WIDGET_CLASS (pizza_parent_class
)->style_set
) (widget
, previous_style
); 
 763 gtk_pizza_add (GtkContainer 
*container
, 
 766     g_return_if_fail (container 
!= NULL
); 
 767     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 768     g_return_if_fail (widget 
!= NULL
); 
 770     gtk_pizza_put (GTK_PIZZA (container
), widget
, 0, 0, 20, 20 ); 
 774 gtk_pizza_remove (GtkContainer 
*container
, 
 778     GtkPizzaChild 
*child
; 
 781     g_return_if_fail (container 
!= NULL
); 
 782     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 783     g_return_if_fail (widget 
!= NULL
); 
 785     pizza 
= GTK_PIZZA (container
); 
 787     children 
= pizza
->children
; 
 790         child 
= children
->data
; 
 792         if (child
->widget 
== widget
) 
 794             gtk_widget_unparent (widget
); 
 796             /* security checks */ 
 797             g_return_if_fail (GTK_IS_WIDGET (widget
)); 
 799             pizza
->children 
= g_list_remove_link (pizza
->children
, children
); 
 800             g_list_free (children
); 
 803             /* security checks */ 
 804             g_return_if_fail (GTK_IS_WIDGET (widget
)); 
 806             GTK_PRIVATE_UNSET_FLAG (widget
, GTK_IS_OFFSCREEN
); 
 811         children 
= children
->next
; 
 816 gtk_pizza_forall (GtkContainer 
*container
, 
 817                   gboolean      include_internals
, 
 818                   GtkCallback   callback
, 
 819                   gpointer      callback_data
) 
 822     GtkPizzaChild 
*child
; 
 825     g_return_if_fail (container 
!= NULL
); 
 826     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 827     g_return_if_fail (callback 
!= (GtkCallback
)NULL
); 
 829     pizza 
= GTK_PIZZA (container
); 
 831     children 
= pizza
->children
; 
 834         child 
= children
->data
; 
 835         children 
= children
->next
; 
 837         (* callback
) (child
->widget
, callback_data
); 
 842 gtk_pizza_allocate_child (GtkPizza      
*pizza
, 
 843                           GtkPizzaChild 
*child
) 
 845     GtkAllocation allocation
; 
 846     GtkRequisition requisition
; 
 848     allocation
.x 
= child
->x 
- pizza
->xoffset
; 
 849     allocation
.y 
= child
->y 
- pizza
->yoffset
; 
 850     gtk_widget_get_child_requisition (child
->widget
, &requisition
); 
 851     allocation
.width 
= requisition
.width
; 
 852     allocation
.height 
= requisition
.height
; 
 854     gtk_widget_size_allocate (child
->widget
, &allocation
); 
 858 gtk_pizza_adjust_allocations_recurse (GtkWidget 
*widget
, 
 861     GtkPizzaAdjData 
*data 
= cb_data
; 
 863     widget
->allocation
.x 
+= data
->dx
; 
 864     widget
->allocation
.y 
+= data
->dy
; 
 866     if (GTK_WIDGET_NO_WINDOW (widget
) && GTK_IS_CONTAINER (widget
)) 
 868         gtk_container_forall (GTK_CONTAINER (widget
), 
 869                           gtk_pizza_adjust_allocations_recurse
, 
 875 gtk_pizza_adjust_allocations (GtkPizza 
*pizza
, 
 880     GtkPizzaAdjData data
; 
 885     tmp_list 
= pizza
->children
; 
 888         GtkPizzaChild 
*child 
= tmp_list
->data
; 
 889         tmp_list 
= tmp_list
->next
; 
 891         child
->widget
->allocation
.x 
+= dx
; 
 892         child
->widget
->allocation
.y 
+= dy
; 
 894         if (GTK_WIDGET_NO_WINDOW (child
->widget
) && 
 895             GTK_IS_CONTAINER (child
->widget
)) 
 897             gtk_container_forall (GTK_CONTAINER (child
->widget
), 
 898                                   gtk_pizza_adjust_allocations_recurse
, 
 905 gtk_pizza_position_child (GtkPizza      
*pizza
, 
 906                           GtkPizzaChild 
*child
) 
 911     x 
= child
->x 
- pizza
->xoffset
; 
 912     y 
= child
->y 
- pizza
->yoffset
; 
 914     if (IS_ONSCREEN (x
,y
)) 
 916         if (GTK_WIDGET_MAPPED (pizza
) && 
 917           GTK_WIDGET_VISIBLE (child
->widget
)) 
 919             if (!GTK_WIDGET_MAPPED (child
->widget
)) 
 920                 gtk_widget_map (child
->widget
); 
 923         if (GTK_WIDGET_IS_OFFSCREEN (child
->widget
)) 
 924             GTK_PRIVATE_UNSET_FLAG (child
->widget
, GTK_IS_OFFSCREEN
); 
 928         if (!GTK_WIDGET_IS_OFFSCREEN (child
->widget
)) 
 929             GTK_PRIVATE_SET_FLAG (child
->widget
, GTK_IS_OFFSCREEN
); 
 931         if (GTK_WIDGET_MAPPED (child
->widget
)) 
 932             gtk_widget_unmap (child
->widget
); 
 937 gtk_pizza_position_children (GtkPizza 
*pizza
) 
 941     tmp_list 
= pizza
->children
; 
 944         GtkPizzaChild 
*child 
= tmp_list
->data
; 
 945         tmp_list 
= tmp_list
->next
; 
 947         gtk_pizza_position_child (pizza
, child
); 
 951 /* This function is used to find events to process while scrolling */ 
 953 gtk_pizza_expose_predicate (Display 
*display
, 
 957     if ((xevent
->type 
== Expose
) || 
 958        ((xevent
->xany
.window 
== *(Window 
*)arg
) && 
 959        (xevent
->type 
== ConfigureNotify
))) 
 965 /* This is the main routine to do the scrolling. Scrolling is 
 966  * done by "Guffaw" scrolling, as in the Mozilla XFE, with 
 967  * a few modifications. 
 969  * The main improvement is that we keep track of whether we 
 970  * are obscured or not. If not, we ignore the generated expose 
 971  * events and instead do the exposes ourself, without having 
 972  * to wait for a roundtrip to the server. This also provides 
 973  * a limited form of expose-event compression, since we do 
 974  * the affected area as one big chunk. 
 978 gtk_pizza_scroll (GtkPizza 
*pizza
, gint dx
, gint dy
) 
 986     widget 
= GTK_WIDGET (pizza
); 
 988     pizza
->xoffset 
+= dx
; 
 989     pizza
->yoffset 
+= dy
; 
 991     if (!GTK_WIDGET_MAPPED (pizza
)) 
 993         gtk_pizza_position_children (pizza
); 
 997     gtk_pizza_adjust_allocations (pizza
, -dx
, -dy
); 
 999     if (pizza
->shadow_type 
== GTK_MYSHADOW_NONE
) 
1002     if (pizza
->shadow_type 
== GTK_MYSHADOW_THIN
) 
1009     w 
= widget
->allocation
.width 
- 2*border
; 
1010     h 
= widget
->allocation
.height 
- 2*border
; 
1016           gdk_window_resize (pizza
->bin_window
, 
1019           gdk_window_move   (pizza
->bin_window
, x
-dx
, y
); 
1020           gdk_window_move_resize (pizza
->bin_window
, x
, y
, w
, h 
); 
1031           gdk_window_move_resize (pizza
->bin_window
, 
1036           gdk_window_move   (pizza
->bin_window
, x
, y
); 
1037           gdk_window_resize (pizza
->bin_window
, w
, h 
); 
1049           gdk_window_resize (pizza
->bin_window
, w
, h 
+ dy
); 
1050           gdk_window_move   (pizza
->bin_window
, x
, y
-dy
); 
1051           gdk_window_move_resize (pizza
->bin_window
, 
1063           gdk_window_move_resize (pizza
->bin_window
, 
1064                                   x
, y
+dy
, w
, h 
- dy 
); 
1065           gdk_window_move   (pizza
->bin_window
, x
, y
); 
1066           gdk_window_resize (pizza
->bin_window
, w
, h 
); 
1074     gtk_pizza_position_children (pizza
); 
1078     win 
= GDK_WINDOW_XWINDOW (pizza
->bin_window
); 
1079     while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (pizza
->bin_window
), 
1081                          gtk_pizza_expose_predicate
, 
1085         GtkWidget 
*event_widget
; 
1087         if ((xevent
.xany
.window 
== GDK_WINDOW_XWINDOW (pizza
->bin_window
)) ) 
1088             gtk_pizza_filter (&xevent
, &event
, pizza
); 
1090         if (xevent
.type 
== Expose
) 
1092             event
.expose
.window 
= gdk_window_lookup (xevent
.xany
.window
); 
1093             gdk_window_get_user_data (event
.expose
.window
, 
1094                                     (gpointer 
*)&event_widget
); 
1098                 event
.expose
.type 
= GDK_EXPOSE
; 
1099                 event
.expose
.area
.x 
= xevent
.xexpose
.x
; 
1100                 event
.expose
.area
.y 
= xevent
.xexpose
.y
; 
1101                 event
.expose
.area
.width 
= xevent
.xexpose
.width
; 
1102                 event
.expose
.area
.height 
= xevent
.xexpose
.height
; 
1103                 event
.expose
.count 
= xevent
.xexpose
.count
; 
1105                 gdk_window_ref (event
.expose
.window
); 
1106                 gtk_widget_event (event_widget
, &event
); 
1107                 gdk_window_unref (event
.expose
.window
); 
1114 /* The main event filter. Actually, we probably don't really need 
1115  * to install this as a filter at all, since we are calling it 
1116  * directly above in the expose-handling hack. But in case scrollbars 
1117  * are fixed up in some manner... 
1119  * This routine identifies expose events that are generated when 
1120  * we've temporarily moved the bin_window_origin, and translates 
1121  * them or discards them, depending on whether we are obscured 
1124 static GdkFilterReturn
 
1125 gtk_pizza_filter (GdkXEvent 
*gdk_xevent
, 
1132     xevent 
= (XEvent 
*)gdk_xevent
; 
1134     pizza 
= GTK_PIZZA (data
); 
1136     if (!pizza
->use_filter
) 
1137         return GDK_FILTER_CONTINUE
; 
1139     switch (xevent
->type
) 
1142             if (xevent
->xexpose
.serial 
== pizza
->configure_serial
) 
1144                 xevent
->xexpose
.x 
+= pizza
->scroll_x
; 
1145                 xevent
->xexpose
.y 
+= pizza
->scroll_y
; 
1149         case ConfigureNotify
: 
1151                 pizza
->configure_serial 
= xevent
->xconfigure
.serial
; 
1152                 pizza
->scroll_x 
= xevent
->xconfigure
.x
; 
1153                 pizza
->scroll_y 
= xevent
->xconfigure
.y
; 
1158     return GDK_FILTER_CONTINUE
; 
1161 /* Although GDK does have a GDK_VISIBILITY_NOTIFY event, 
1162  * there is no corresponding event in GTK, so we have 
1163  * to get the events from a filter 
1165 static GdkFilterReturn
 
1166 gtk_pizza_main_filter (GdkXEvent 
*gdk_xevent
, 
1173     xevent 
= (XEvent 
*)gdk_xevent
; 
1174     pizza 
= GTK_PIZZA (data
); 
1176     if (!pizza
->use_filter
) 
1177         return GDK_FILTER_CONTINUE
; 
1179     if (xevent
->type 
== VisibilityNotify
) 
1181         switch (xevent
->xvisibility
.state
) 
1183             case VisibilityFullyObscured
: 
1184                 pizza
->visibility 
= GDK_VISIBILITY_FULLY_OBSCURED
; 
1187             case VisibilityPartiallyObscured
: 
1188                 pizza
->visibility 
= GDK_VISIBILITY_PARTIAL
; 
1191             case VisibilityUnobscured
: 
1192                 pizza
->visibility 
= GDK_VISIBILITY_UNOBSCURED
; 
1196         return GDK_FILTER_REMOVE
; 
1199     return GDK_FILTER_CONTINUE
; 
1204 #endif /* __cplusplus */