1 /* /////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/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/gtk/private/win_gtk.h" 
  21 #endif /* __cplusplus */ 
  23 typedef struct _GtkPizzaChild GtkPizzaChild
; 
  24 typedef struct _GtkPizzaClass GtkPizzaClass
; 
  28   GtkContainerClass parent_class
; 
  30   void  (*set_scroll_adjustments
)   (GtkPizza     
*pizza
, 
  31                                      GtkAdjustment  
*hadjustment
, 
  32                                      GtkAdjustment  
*vadjustment
); 
  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_style_set     (GtkWidget 
*widget
, 
  55                                      GtkStyle  
*previous_style
); 
  56 static void gtk_pizza_add           (GtkContainer     
*container
, 
  58 static void gtk_pizza_remove        (GtkContainer     
*container
, 
  60 static void gtk_pizza_forall        (GtkContainer     
*container
, 
  61                                      gboolean          include_internals
, 
  63                                      gpointer          callback_data
); 
  65 static void     gtk_pizza_allocate_child     (GtkPizza      
*pizza
, 
  66                                               GtkPizzaChild 
*child
); 
  68 static GtkType 
gtk_pizza_child_type (GtkContainer     
*container
); 
  70 static void  gtk_pizza_scroll_set_adjustments (GtkPizza      
*pizza
, 
  74 static GtkWidgetClass
* pizza_parent_class
; 
  79     static GtkType pizza_type 
= 0; 
  83         const GTypeInfo pizza_info 
= 
  85             sizeof (GtkPizzaClass
), 
  87             NULL
,           /* base_finalize */ 
  88             (GClassInitFunc
) gtk_pizza_class_init
, 
  89             NULL
,           /* class_finalize */ 
  90             NULL
,           /* class_data */ 
  93             (GInstanceInitFunc
) gtk_pizza_init
, 
  96         pizza_type 
= g_type_register_static (GTK_TYPE_CONTAINER
, "GtkPizza", &pizza_info
, (GTypeFlags
)0); 
 102 /* Marshaller needed for set_scroll_adjustments signal, 
 103    generated with GLib-2.4.6 glib-genmarshal */ 
 104 #define g_marshal_value_peek_object(v)   g_value_get_object (v) 
 106 g_cclosure_user_marshal_VOID__OBJECT_OBJECT (GClosure     
*closure
, 
 107                                              GValue       
*return_value
, 
 108                                              guint         n_param_values
, 
 109                                              const GValue 
*param_values
, 
 110                                              gpointer      invocation_hint
, 
 111                                              gpointer      marshal_data
) 
 113   typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT
) (gpointer     data1
, 
 117   register GMarshalFunc_VOID__OBJECT_OBJECT callback
; 
 118   register GCClosure 
*cc 
= (GCClosure
*) closure
; 
 119   register gpointer data1
, data2
; 
 121   g_return_if_fail (n_param_values 
== 3); 
 123   if (G_CCLOSURE_SWAP_DATA (closure
)) 
 125       data1 
= closure
->data
; 
 126       data2 
= g_value_peek_pointer (param_values 
+ 0); 
 130       data1 
= g_value_peek_pointer (param_values 
+ 0); 
 131       data2 
= closure
->data
; 
 133   callback 
= (GMarshalFunc_VOID__OBJECT_OBJECT
) (marshal_data 
? marshal_data 
: cc
->callback
); 
 136             g_marshal_value_peek_object (param_values 
+ 1), 
 137             g_marshal_value_peek_object (param_values 
+ 2), 
 142 gtk_pizza_class_init (GtkPizzaClass 
*klass
) 
 144     GtkObjectClass 
*object_class
; 
 145     GtkWidgetClass 
*widget_class
; 
 146     GtkContainerClass 
*container_class
; 
 148     object_class 
= (GtkObjectClass
*) klass
; 
 149     widget_class 
= (GtkWidgetClass
*) klass
; 
 150     container_class 
= (GtkContainerClass
*) klass
; 
 151     pizza_parent_class 
= gtk_type_class (GTK_TYPE_CONTAINER
); 
 153     widget_class
->map 
= gtk_pizza_map
; 
 154     widget_class
->realize 
= gtk_pizza_realize
; 
 155     widget_class
->unrealize 
= gtk_pizza_unrealize
; 
 156     widget_class
->size_request 
= gtk_pizza_size_request
; 
 157     widget_class
->size_allocate 
= gtk_pizza_size_allocate
; 
 158     widget_class
->style_set 
= gtk_pizza_style_set
; 
 160     container_class
->add 
= gtk_pizza_add
; 
 161     container_class
->remove 
= gtk_pizza_remove
; 
 162     container_class
->forall 
= gtk_pizza_forall
; 
 164     container_class
->child_type 
= gtk_pizza_child_type
; 
 166     klass
->set_scroll_adjustments 
= gtk_pizza_scroll_set_adjustments
; 
 168     widget_class
->set_scroll_adjustments_signal 
= 
 170             "set_scroll_adjustments", 
 171             G_TYPE_FROM_CLASS(object_class
), 
 173             G_STRUCT_OFFSET(GtkPizzaClass
, set_scroll_adjustments
), 
 176             g_cclosure_user_marshal_VOID__OBJECT_OBJECT
, 
 180             GTK_TYPE_ADJUSTMENT
); 
 184 gtk_pizza_child_type (GtkContainer     
*container
) 
 186     return GTK_TYPE_WIDGET
; 
 190 gtk_pizza_init (GtkPizza 
*pizza
) 
 192     GTK_WIDGET_SET_FLAGS (pizza
, GTK_CAN_FOCUS
); 
 193     GTK_WIDGET_UNSET_FLAGS (pizza
, GTK_NO_WINDOW
); 
 195     pizza
->children 
= NULL
; 
 197     pizza
->bin_window 
= NULL
; 
 199     pizza
->m_xoffset 
= 0; 
 200     pizza
->m_yoffset 
= 0; 
 208     pizza 
= g_object_new (gtk_pizza_get_type (), NULL
); 
 210     pizza
->m_noscroll 
= FALSE
; 
 212     return GTK_WIDGET (pizza
); 
 216 gtk_pizza_new_no_scroll () 
 220     pizza 
= g_object_new (gtk_pizza_get_type (), NULL
); 
 222     pizza
->m_noscroll 
= TRUE
; 
 224     return GTK_WIDGET (pizza
); 
 227 gint       
gtk_pizza_get_xoffset     (GtkPizza          
*pizza
) 
 229     g_return_val_if_fail ( (pizza 
!= NULL
), -1 ); 
 230     g_return_val_if_fail ( (GTK_IS_PIZZA (pizza
)), -1 ); 
 232     return pizza
->m_xoffset
; 
 235 gint       
gtk_pizza_get_yoffset     (GtkPizza          
*pizza
) 
 237     g_return_val_if_fail ( (pizza 
!= NULL
), -1 ); 
 238     g_return_val_if_fail ( (GTK_IS_PIZZA (pizza
)), -1 ); 
 240     return pizza
->m_yoffset
; 
 243 void       gtk_pizza_set_xoffset     (GtkPizza          
*pizza
, gint xoffset
) 
 245     g_return_if_fail (pizza 
!= NULL
); 
 246     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 248     pizza
->m_xoffset 
= xoffset
; 
 252 void       gtk_pizza_set_yoffset     (GtkPizza          
*pizza
, gint yoffset
) 
 254     g_return_if_fail (pizza 
!= NULL
); 
 255     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 257     pizza
->m_xoffset 
= yoffset
; 
 261 gint       
gtk_pizza_get_rtl_offset  (GtkPizza          
*pizza
) 
 265     g_return_val_if_fail ( (pizza 
!= NULL
), 0 ); 
 266     g_return_val_if_fail ( (GTK_IS_PIZZA (pizza
)), 0 ); 
 268     if (!pizza
->bin_window
) return 0; 
 270     border 
= pizza
->container
.border_width
; 
 272     return GTK_WIDGET(pizza
)->allocation
.width 
- border
*2; 
 277 gtk_pizza_scroll_set_adjustments (GtkPizza     
*pizza
, 
 281    /* We handle scrolling in the wxScrolledWindow, not here. */ 
 285 gtk_pizza_put (GtkPizza   
*pizza
, 
 292     GtkPizzaChild 
*child_info
; 
 294     g_return_if_fail (pizza 
!= NULL
); 
 295     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 296     g_return_if_fail (widget 
!= NULL
); 
 298     child_info 
= g_new (GtkPizzaChild
, 1); 
 300     child_info
->widget 
= widget
; 
 304     pizza
->children 
= g_list_append (pizza
->children
, child_info
); 
 306     if (GTK_WIDGET_REALIZED (pizza
)) 
 307         gtk_widget_set_parent_window (widget
, pizza
->bin_window
); 
 309     gtk_widget_set_parent (widget
, GTK_WIDGET (pizza
)); 
 311     gtk_widget_set_size_request( widget
, width
, height 
); 
 315 gtk_pizza_set_size (GtkPizza   
*pizza
, 
 322     GtkPizzaChild 
*child
; 
 325     g_return_if_fail (pizza 
!= NULL
); 
 326     g_return_if_fail (GTK_IS_PIZZA (pizza
)); 
 327     g_return_if_fail (widget 
!= NULL
); 
 329 #ifndef WX_WARN_ILLEGAL_SETSIZE 
 330     /* this really shouldn't happen -- but it does, a lot, right now and we 
 331        can't pass negative values to gtk_widget_set_size_request() without getting 
 332        a warning printed out, so filter them out here */ 
 339     children 
= pizza
->children
; 
 342         child 
= children
->data
; 
 343         children 
= children
->next
; 
 345         if (child
->widget 
== widget
) 
 347             if (child
->x 
!= x 
|| child
->y 
!= y
) 
 351                 gtk_widget_queue_resize(widget
); 
 354             gtk_widget_set_size_request (widget
, width
, height
); 
 362 gtk_pizza_map (GtkWidget 
*widget
) 
 365     GtkPizzaChild 
*child
; 
 368     g_return_if_fail (widget 
!= NULL
); 
 369     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 371     GTK_WIDGET_SET_FLAGS (widget
, GTK_MAPPED
); 
 372     pizza 
= GTK_PIZZA (widget
); 
 374     children 
= pizza
->children
; 
 377         child 
= children
->data
; 
 378         children 
= children
->next
; 
 380         if ( GTK_WIDGET_VISIBLE (child
->widget
) && 
 381             !GTK_WIDGET_MAPPED (child
->widget
) ) 
 383             gtk_widget_map (child
->widget
); 
 387     gdk_window_show (widget
->window
); 
 388     gdk_window_show (pizza
->bin_window
); 
 392 gtk_pizza_realize (GtkWidget 
*widget
) 
 395     GdkWindowAttr attributes
; 
 396     gint attributes_mask
; 
 397     GtkPizzaChild 
*child
; 
 402     g_return_if_fail (widget 
!= NULL
); 
 403     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 405     pizza 
= GTK_PIZZA (widget
); 
 406     GTK_WIDGET_SET_FLAGS (widget
, GTK_REALIZED
); 
 408     attributes
.window_type 
= GDK_WINDOW_CHILD
; 
 410     attributes
.x 
= widget
->allocation
.x
; 
 411     attributes
.y 
= widget
->allocation
.y
; 
 412     attributes
.width 
= widget
->allocation
.width
; 
 413     attributes
.height 
= widget
->allocation
.height
; 
 416     if (attributes
.width 
< 2) attributes
.width 
= 2; 
 417     if (attributes
.height 
< 2) attributes
.height 
= 2; 
 419     border 
= pizza
->container
.border_width
; 
 420     w 
= attributes
.width  
- 2 * border
; 
 421     h 
= attributes
.height 
- 2 * border
; 
 425     if (!pizza
->m_noscroll
) 
 427         attributes
.x 
+= border
; 
 428         attributes
.y 
+= border
; 
 429         attributes
.width  
= w
; 
 430         attributes
.height 
= h
; 
 433     attributes
.wclass 
= GDK_INPUT_OUTPUT
; 
 434     attributes
.visual 
= gtk_widget_get_visual (widget
); 
 435     attributes
.colormap 
= gtk_widget_get_colormap (widget
); 
 436     attributes
.event_mask 
= GDK_VISIBILITY_NOTIFY_MASK
; 
 437     attributes_mask 
= GDK_WA_X 
| GDK_WA_Y 
| GDK_WA_VISUAL 
| GDK_WA_COLORMAP
; 
 439     widget
->window 
= gdk_window_new(gtk_widget_get_parent_window (widget
), 
 440                                      &attributes
, attributes_mask
); 
 441     gdk_window_set_user_data (widget
->window
, widget
); 
 445     if (pizza
->m_noscroll
) 
 447         attributes
.x 
= border
; 
 448         attributes
.y 
= border
; 
 449         attributes
.width  
= w
; 
 450         attributes
.height 
= h
; 
 453     attributes
.event_mask 
= gtk_widget_get_events (widget
); 
 454     attributes
.event_mask 
|= GDK_EXPOSURE_MASK              
| 
 456                              GDK_POINTER_MOTION_MASK        
| 
 457                              GDK_POINTER_MOTION_HINT_MASK   
| 
 458                              GDK_BUTTON_MOTION_MASK         
| 
 459                              GDK_BUTTON1_MOTION_MASK        
| 
 460                              GDK_BUTTON2_MOTION_MASK        
| 
 461                              GDK_BUTTON3_MOTION_MASK        
| 
 462                              GDK_BUTTON_PRESS_MASK          
| 
 463                              GDK_BUTTON_RELEASE_MASK        
| 
 465                              GDK_KEY_RELEASE_MASK           
| 
 466                              GDK_ENTER_NOTIFY_MASK          
| 
 467                              GDK_LEAVE_NOTIFY_MASK          
| 
 468                              GDK_FOCUS_CHANGE_MASK
; 
 470     pizza
->bin_window 
= gdk_window_new(widget
->window
, 
 471                                           &attributes
, attributes_mask
); 
 472     gdk_window_set_user_data (pizza
->bin_window
, widget
); 
 474     widget
->style 
= gtk_style_attach (widget
->style
, widget
->window
); 
 475     gtk_style_set_background (widget
->style
, widget
->window
, GTK_STATE_NORMAL
); 
 476     gtk_style_set_background (widget
->style
, pizza
->bin_window
, GTK_STATE_NORMAL 
); 
 479     gdk_window_set_back_pixmap( widget->window, NULL, FALSE ); 
 480     gdk_window_set_back_pixmap( pizza->bin_window, NULL, FALSE ); 
 483     /* cannot be done before realisation */ 
 484     children 
= pizza
->children
; 
 487         child 
= children
->data
; 
 488         children 
= children
->next
; 
 490         gtk_widget_set_parent_window (child
->widget
, pizza
->bin_window
); 
 495 gtk_pizza_unrealize (GtkWidget 
*widget
) 
 499     g_return_if_fail (widget 
!= NULL
); 
 500     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 502     pizza 
= GTK_PIZZA (widget
); 
 504     gdk_window_set_user_data (pizza
->bin_window
, NULL
); 
 505     gdk_window_destroy (pizza
->bin_window
); 
 506     pizza
->bin_window 
= NULL
; 
 508     if (pizza_parent_class
->unrealize
) 
 509         pizza_parent_class
->unrealize(widget
); 
 513 gtk_pizza_size_request (GtkWidget      
*widget
, 
 514                         GtkRequisition 
*requisition
) 
 517     GtkPizzaChild 
*child
; 
 519     GtkRequisition child_requisition
; 
 521     g_return_if_fail (widget 
!= NULL
); 
 522     g_return_if_fail (GTK_IS_PIZZA (widget
)); 
 523     g_return_if_fail (requisition 
!= NULL
); 
 525     pizza 
= GTK_PIZZA (widget
); 
 527     children 
= pizza
->children
; 
 530         child 
= children
->data
; 
 531         children 
= children
->next
; 
 533         if (GTK_WIDGET_VISIBLE (child
->widget
)) 
 535             gtk_widget_size_request (child
->widget
, &child_requisition
); 
 539     /* request very little, I'm not sure if requesting nothing 
 540        will always have positive effects on stability... */ 
 541     requisition
->width 
= 2; 
 542     requisition
->height 
= 2; 
 546 gtk_pizza_size_allocate (GtkWidget     
*widget
, 
 547                          GtkAllocation 
*allocation
) 
 552     GtkPizzaChild 
*child
; 
 554     gboolean only_resize
; 
 556     g_return_if_fail (widget 
!= NULL
); 
 557     g_return_if_fail (GTK_IS_PIZZA(widget
)); 
 558     g_return_if_fail (allocation 
!= NULL
); 
 560     pizza 
= GTK_PIZZA (widget
); 
 562     only_resize 
= ((widget
->allocation
.x 
== allocation
->x
) && 
 563                    (widget
->allocation
.y 
== allocation
->y
)); 
 564     widget
->allocation 
= *allocation
; 
 566     if (GTK_WIDGET_REALIZED(widget
)) 
 568         border 
= pizza
->container
.border_width
; 
 570         x 
= allocation
->x 
+ border
; 
 571         y 
= allocation
->y 
+ border
; 
 572         w 
= allocation
->width 
- border
*2; 
 573         h 
= allocation
->height 
- border
*2; 
 579         if (pizza
->m_noscroll
) 
 582                 gdk_window_resize( widget
->window
, allocation
->width
, allocation
->height 
); 
 584                 gdk_window_move_resize( widget
->window
, allocation
->x
, allocation
->y
,  
 585                                                         allocation
->width
, allocation
->height 
); 
 587             gdk_window_move_resize( pizza
->bin_window
, border
, border
, w
, h 
); 
 592                 gdk_window_resize( widget
->window
, w
, h 
); 
 594                 gdk_window_move_resize( widget
->window
, x
, y
, w
, h 
); 
 596             gdk_window_resize( pizza
->bin_window
, w
, h 
); 
 600     children 
= pizza
->children
; 
 603         child 
= children
->data
; 
 604         children 
= children
->next
; 
 606         gtk_pizza_allocate_child (pizza
, child
); 
 611 gtk_pizza_style_set(GtkWidget 
*widget
, GtkStyle  
*previous_style
) 
 613     if (GTK_WIDGET_REALIZED(widget
)) 
 615         gtk_style_set_background(widget
->style
, widget
->window
, GTK_STATE_NORMAL
); 
 616         gtk_style_set_background(widget
->style
, GTK_PIZZA(widget
)->bin_window
, GTK_STATE_NORMAL 
); 
 619     pizza_parent_class
->style_set(widget
, previous_style
); 
 623 gtk_pizza_add (GtkContainer 
*container
, 
 626     g_return_if_fail (container 
!= NULL
); 
 627     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 628     g_return_if_fail (widget 
!= NULL
); 
 630     gtk_pizza_put (GTK_PIZZA (container
), widget
, 0, 0, 20, 20 ); 
 634 gtk_pizza_remove (GtkContainer 
*container
, 
 638     GtkPizzaChild 
*child
; 
 641     g_return_if_fail (container 
!= NULL
); 
 642     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 643     g_return_if_fail (widget 
!= NULL
); 
 645     pizza 
= GTK_PIZZA (container
); 
 647     children 
= pizza
->children
; 
 650         child 
= children
->data
; 
 652         if (child
->widget 
== widget
) 
 654             gtk_widget_unparent (widget
); 
 656             /* security checks */ 
 657             g_return_if_fail (GTK_IS_WIDGET (widget
)); 
 659             pizza
->children 
= g_list_remove_link (pizza
->children
, children
); 
 660             g_list_free (children
); 
 663             /* security checks */ 
 664             g_return_if_fail (GTK_IS_WIDGET (widget
)); 
 669         children 
= children
->next
; 
 674 gtk_pizza_forall (GtkContainer 
*container
, 
 675                   gboolean      include_internals
, 
 676                   GtkCallback   callback
, 
 677                   gpointer      callback_data
) 
 680     GtkPizzaChild 
*child
; 
 683     g_return_if_fail (container 
!= NULL
); 
 684     g_return_if_fail (GTK_IS_PIZZA (container
)); 
 685     g_return_if_fail (callback 
!= (GtkCallback
)NULL
); 
 687     pizza 
= GTK_PIZZA (container
); 
 689     children 
= pizza
->children
; 
 692         child 
= children
->data
; 
 693         children 
= children
->next
; 
 695         (* callback
) (child
->widget
, callback_data
); 
 700 gtk_pizza_allocate_child (GtkPizza      
*pizza
, 
 701                           GtkPizzaChild 
*child
) 
 703     GtkAllocation allocation
; 
 704     GtkRequisition requisition
; 
 706     allocation
.x 
= child
->x 
- pizza
->m_xoffset
; 
 707     allocation
.y 
= child
->y 
- pizza
->m_yoffset
; 
 708     gtk_widget_get_child_requisition (child
->widget
, &requisition
); 
 709     allocation
.width 
= requisition
.width
; 
 710     allocation
.height 
= requisition
.height
; 
 712     if (gtk_widget_get_direction( GTK_WIDGET(pizza
) ) == GTK_TEXT_DIR_RTL
) 
 714         /* reverse horizontal placement */ 
 717         offset 
= GTK_WIDGET(pizza
)->allocation
.width
; 
 718         border 
= pizza
->container
.border_width
; 
 721         allocation
.x 
= offset 
- child
->x 
- allocation
.width 
+ pizza
->m_xoffset
; 
 724     gtk_widget_size_allocate (child
->widget
, &allocation
); 
 728 gtk_pizza_scroll (GtkPizza 
*pizza
, gint dx
, gint dy
) 
 732     pizza
->m_xoffset 
+= dx
; 
 733     pizza
->m_yoffset 
+= dy
; 
 735     if (pizza
->bin_window
) 
 736         gdk_window_scroll( pizza
->bin_window
, -dx
, -dy 
); 
 738     for (tmp_list 
= pizza
->children
; tmp_list
; tmp_list 
= tmp_list
->next
) 
 740         GtkPizzaChild 
*child 
= tmp_list
->data
; 
 741         gtk_widget_queue_resize(child
->widget
); 
 747 #endif /* __cplusplus */