1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/combobox.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  15 #include "wx/combobox.h" 
  19     #include "wx/settings.h" 
  20     #include "wx/textctrl.h"    // for wxEVT_COMMAND_TEXT_UPDATED 
  21     #include "wx/arrstr.h" 
  24 // We use GtkCombo which has been deprecated since GTK+ 2.3.0 
  25 // in favour of GtkComboBox for <GTK2.4 runtime 
  26 // We also use GtkList 
  27 #ifdef GTK_DISABLE_DEPRECATED 
  28 #undef GTK_DISABLE_DEPRECATED 
  30 #include "wx/gtk/private.h" 
  32 //----------------------------------------------------------------------------- 
  34 //----------------------------------------------------------------------------- 
  36 extern bool   g_blockEventsOnDrag
; 
  37 static int    g_SelectionBeforePopup 
= wxID_NONE
; // this means the popup is hidden 
  39 //----------------------------------------------------------------------------- 
  40 //  "changed" - typing and list item matches get changed, select-child 
  41 //              if it doesn't match an item then just get a single changed 
  42 //----------------------------------------------------------------------------- 
  46 gtkcombo_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxComboBox 
*combo 
) 
  48     if (g_isIdle
) wxapp_install_idle_handler(); 
  50     if (combo
->m_ignoreNextUpdate
) 
  52         combo
->m_ignoreNextUpdate 
= false; 
  56     if (!combo
->m_hasVMT
) return; 
  58     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, combo
->GetId() ); 
  59     event
.SetString( combo
->GetValue() ); 
  60     event
.SetEventObject( combo 
); 
  61     combo
->GetEventHandler()->ProcessEvent( event 
); 
  67 gtkcombo_dummy_callback(GtkEntry 
*WXUNUSED(entry
), GtkCombo 
*WXUNUSED(combo
)) 
  74 gtkcombo_popup_hide_callback(GtkCombo 
*WXUNUSED(gtk_combo
), wxComboBox 
*combo
) 
  76     // when the popup is hidden, throw a SELECTED event only if the combobox 
  78     const int curSelection 
= combo
->GetCurrentSelection(); 
  80     const bool hasChanged 
= curSelection 
!= g_SelectionBeforePopup
; 
  82     // reset the selection flag to value meaning that it is hidden and do it 
  83     // now, before generating the events, so that GetSelection() returns the 
  84     // new value from the event handler 
  85     g_SelectionBeforePopup 
= wxID_NONE
; 
  89         wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, combo
->GetId() ); 
  90         event
.SetInt( curSelection 
); 
  91         event
.SetString( combo
->GetStringSelection() ); 
  92         event
.SetEventObject( combo 
); 
  93         combo
->GetEventHandler()->ProcessEvent( event 
); 
  95         // for consistency with the other ports, send TEXT event 
  96         wxCommandEvent 
event2( wxEVT_COMMAND_TEXT_UPDATED
, combo
->GetId() ); 
  97         event2
.SetString( combo
->GetStringSelection() ); 
  98         event2
.SetEventObject( combo 
); 
  99         combo
->GetEventHandler()->ProcessEvent( event2 
); 
 106 gtkcombo_popup_show_callback(GtkCombo 
*WXUNUSED(gtk_combo
), wxComboBox 
*combo
) 
 108     // store the combobox selection value before the popup is shown 
 109     g_SelectionBeforePopup 
= combo
->GetCurrentSelection(); 
 113 //----------------------------------------------------------------------------- 
 114 // "select-child" - click/cursor get select-child, changed, select-child 
 115 //----------------------------------------------------------------------------- 
 119 gtkcombo_combo_select_child_callback( GtkList 
*WXUNUSED(list
), GtkWidget 
*WXUNUSED(widget
), wxComboBox 
*combo 
) 
 121     if (g_isIdle
) wxapp_install_idle_handler(); 
 123     if (!combo
->m_hasVMT
) return; 
 125     if (g_blockEventsOnDrag
) return; 
 127     int curSelection 
= combo
->GetCurrentSelection(); 
 129     if (combo
->m_prevSelection 
== curSelection
) return; 
 131     GtkWidget 
*list 
= GTK_COMBO(combo
->m_widget
)->list
; 
 132     gtk_list_unselect_item( GTK_LIST(list
), combo
->m_prevSelection 
); 
 134     combo
->m_prevSelection 
= curSelection
; 
 136     // Quickly set the value of the combo box 
 137     // as GTK+ does that only AFTER the event 
 139     g_signal_handlers_disconnect_by_func (GTK_COMBO (combo
->GetHandle())->entry
, 
 140                                           (gpointer
) gtkcombo_text_changed_callback
, 
 142     combo
->SetValue( combo
->GetStringSelection() ); 
 143     g_signal_connect_after (GTK_COMBO (combo
->GetHandle())->entry
, "changed", 
 144                             G_CALLBACK (gtkcombo_text_changed_callback
), combo
); 
 146     // throw a SELECTED event only if the combobox popup is hidden (wxID_NONE) 
 147     // because when combobox popup is shown, gtkcombo_combo_select_child_callback is 
 148     // called each times the mouse is over an item with a pressed button so a lot 
 149     // of SELECTED event could be generated if the user keep the mouse button down 
 150     // and select other items ... 
 151     if (g_SelectionBeforePopup 
== wxID_NONE
) 
 153         wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, combo
->GetId() ); 
 154         event
.SetInt( curSelection 
); 
 155         event
.SetString( combo
->GetStringSelection() ); 
 156         event
.SetEventObject( combo 
); 
 157         combo
->GetEventHandler()->ProcessEvent( event 
); 
 159         // for consistency with the other ports, don't generate text update 
 160         // events while the user is browsing the combobox neither 
 161         wxCommandEvent 
event2( wxEVT_COMMAND_TEXT_UPDATED
, combo
->GetId() ); 
 162         event2
.SetString( combo
->GetValue() ); 
 163         event2
.SetEventObject( combo 
); 
 164         combo
->GetEventHandler()->ProcessEvent( event2 
); 
 172 gtkcombobox_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxComboBox 
*combo 
) 
 174     if (g_isIdle
) wxapp_install_idle_handler(); 
 176     if (!combo
->m_hasVMT
) return; 
 178     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, combo
->GetId() ); 
 179     event
.SetString( combo
->GetValue() ); 
 180     event
.SetEventObject( combo 
); 
 181     combo
->GetEventHandler()->ProcessEvent( event 
); 
 187 gtkcombobox_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxComboBox 
*combo 
) 
 189     if (g_isIdle
) wxapp_install_idle_handler(); 
 191     if (!combo
->m_hasVMT
) return; 
 193     wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, combo
->GetId() ); 
 194     event
.SetInt( combo
->GetSelection() ); 
 195     event
.SetString( combo
->GetStringSelection() ); 
 196     event
.SetEventObject( combo 
); 
 197     combo
->GetEventHandler()->ProcessEvent( event 
); 
 202 //----------------------------------------------------------------------------- 
 204 //----------------------------------------------------------------------------- 
 206 IMPLEMENT_DYNAMIC_CLASS(wxComboBox
,wxControl
) 
 208 BEGIN_EVENT_TABLE(wxComboBox
, wxControl
) 
 209     EVT_SIZE(wxComboBox::OnSize
) 
 210     EVT_CHAR(wxComboBox::OnChar
) 
 212     EVT_MENU(wxID_CUT
, wxComboBox::OnCut
) 
 213     EVT_MENU(wxID_COPY
, wxComboBox::OnCopy
) 
 214     EVT_MENU(wxID_PASTE
, wxComboBox::OnPaste
) 
 215     EVT_MENU(wxID_UNDO
, wxComboBox::OnUndo
) 
 216     EVT_MENU(wxID_REDO
, wxComboBox::OnRedo
) 
 217     EVT_MENU(wxID_CLEAR
, wxComboBox::OnDelete
) 
 218     EVT_MENU(wxID_SELECTALL
, wxComboBox::OnSelectAll
) 
 220     EVT_UPDATE_UI(wxID_CUT
, wxComboBox::OnUpdateCut
) 
 221     EVT_UPDATE_UI(wxID_COPY
, wxComboBox::OnUpdateCopy
) 
 222     EVT_UPDATE_UI(wxID_PASTE
, wxComboBox::OnUpdatePaste
) 
 223     EVT_UPDATE_UI(wxID_UNDO
, wxComboBox::OnUpdateUndo
) 
 224     EVT_UPDATE_UI(wxID_REDO
, wxComboBox::OnUpdateRedo
) 
 225     EVT_UPDATE_UI(wxID_CLEAR
, wxComboBox::OnUpdateDelete
) 
 226     EVT_UPDATE_UI(wxID_SELECTALL
, wxComboBox::OnUpdateSelectAll
) 
 229 bool wxComboBox::Create( wxWindow 
*parent
, wxWindowID id
, 
 230                          const wxString
& value
, 
 231                          const wxPoint
& pos
, const wxSize
& size
, 
 232                          const wxArrayString
& choices
, 
 233                          long style
, const wxValidator
& validator
, 
 234                          const wxString
& name 
) 
 236     wxCArrayString 
chs(choices
); 
 238     return Create( parent
, id
, value
, pos
, size
, chs
.GetCount(), 
 239                    chs
.GetStrings(), style
, validator
, name 
); 
 242 bool wxComboBox::Create( wxWindow 
*parent
, wxWindowID id
, const wxString
& value
, 
 243                          const wxPoint
& pos
, const wxSize
& size
, 
 244                          int n
, const wxString choices
[], 
 245                          long style
, const wxValidator
& validator
, 
 246                          const wxString
& name 
) 
 248     m_ignoreNextUpdate 
= false; 
 250     m_acceptsFocus 
= true; 
 253     if (!PreCreation( parent
, pos
, size 
) || 
 254         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 256         wxFAIL_MSG( wxT("wxComboBox creation failed") ); 
 261     if (!gtk_check_version(2,4,0)) 
 263         m_widget 
= gtk_combo_box_entry_new_text(); 
 264         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 266         gtk_entry_set_editable( GTK_ENTRY( GTK_BIN(m_widget
)->child 
), TRUE 
); 
 268         for (int i 
= 0; i 
< n
; i
++) 
 270             gtk_combo_box_append_text( combobox
,  wxGTK_CONV( choices
[i
] ) ); 
 272             m_clientDataList
.Append( (wxObject
*)NULL 
); 
 273             m_clientObjectList
.Append( (wxObject
*)NULL 
); 
 279         m_widget 
= gtk_combo_new(); 
 280         GtkCombo
* combo 
= GTK_COMBO(m_widget
); 
 282         // Disable GTK's broken events ... 
 283         g_signal_handler_disconnect (combo
->entry
, combo
->entry_change_id
); 
 284         // ... and add surrogate handler. 
 285         combo
->entry_change_id 
= g_signal_connect (combo
->entry
, "changed", 
 286                                                G_CALLBACK (gtkcombo_dummy_callback
), 
 289         // make it more useable 
 290         gtk_combo_set_use_arrows_always( GTK_COMBO(m_widget
), TRUE 
); 
 292         // and case-sensitive 
 293         gtk_combo_set_case_sensitive( GTK_COMBO(m_widget
), TRUE 
); 
 295         if (style 
& wxNO_BORDER
) 
 296             g_object_set (combo
->entry
, "has-frame", FALSE
, NULL 
); 
 298         GtkWidget 
*list 
= combo
->list
; 
 300         for (int i 
= 0; i 
< n
; i
++) 
 302             GtkWidget 
*list_item 
= gtk_list_item_new_with_label( wxGTK_CONV( choices
[i
] ) ); 
 304             m_clientDataList
.Append( (wxObject
*)NULL 
); 
 305             m_clientObjectList
.Append( (wxObject
*)NULL 
); 
 307             gtk_container_add( GTK_CONTAINER(list
), list_item 
); 
 309             gtk_widget_show( list_item 
); 
 314     m_parent
->DoAddChild( this ); 
 316     GtkEntry 
*entry 
= NULL
; 
 318     if (!gtk_check_version(2,4,0)) 
 319         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
 322         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
 324     m_focusWidget 
= GTK_WIDGET( entry 
); 
 329     if (!gtk_check_version(2,4,0)) 
 330         ConnectWidget( m_widget 
); 
 333         ConnectWidget( GTK_COMBO(m_widget
)->button 
); 
 336     if (!gtk_check_version(2,4,0)) 
 338         gtk_entry_set_text( entry
, wxGTK_CONV(value
) ); 
 340         if (style 
& wxCB_READONLY
) 
 341             gtk_entry_set_editable( entry
, FALSE 
); 
 343         g_signal_connect_after (entry
, "changed", 
 344                             G_CALLBACK (gtkcombobox_text_changed_callback
), this); 
 346         g_signal_connect_after (m_widget
, "changed", 
 347                             G_CALLBACK (gtkcombobox_changed_callback
), this); 
 352         GtkCombo 
*combo 
= GTK_COMBO(m_widget
); 
 353         // MSW's combo box shows the value and the selection is -1 
 354         gtk_entry_set_text( entry
, wxGTK_CONV(value
) ); 
 355         gtk_list_unselect_all( GTK_LIST(combo
->list
) ); 
 357         if (style 
& wxCB_READONLY
) 
 358             gtk_entry_set_editable( entry
, FALSE 
); 
 360         // "show" and "hide" events are generated when user click on the combobox button which popups a list 
 361         // this list is the "popwin" gtk widget 
 362         g_signal_connect (GTK_COMBO(combo
)->popwin
, "hide", 
 363                       G_CALLBACK (gtkcombo_popup_hide_callback
), this); 
 364         g_signal_connect (GTK_COMBO(combo
)->popwin
, "show", 
 365                       G_CALLBACK (gtkcombo_popup_show_callback
), this); 
 366         g_signal_connect_after (combo
->list
, "select-child", 
 367                             G_CALLBACK (gtkcombo_combo_select_child_callback
), 
 369         g_signal_connect_after (entry
, "changed", 
 370                             G_CALLBACK (gtkcombo_text_changed_callback
), this); 
 372         // This is required for tool bar support 
 373         // Doesn't currently work 
 374 //        wxSize setsize = GetSize(); 
 375 //        gtk_widget_set_size_request( m_widget, setsize.x, setsize.y ); 
 378     SetBestSize(size
); // need this too because this is a wxControlWithItems 
 384 wxComboBox::~wxComboBox() 
 386     wxList::compatibility_iterator node 
= m_clientObjectList
.GetFirst(); 
 389         wxClientData 
*cd 
= (wxClientData
*)node
->GetData(); 
 391         node 
= node
->GetNext(); 
 393     m_clientObjectList
.Clear(); 
 395     m_clientDataList
.Clear(); 
 398 void wxComboBox::SetFocus() 
 402         // don't do anything if we already have focus 
 406     gtk_widget_grab_focus( m_focusWidget 
); 
 409 int wxComboBox::DoAppend( const wxString 
&item 
) 
 411     wxCHECK_MSG( m_widget 
!= NULL
, -1, wxT("invalid combobox") ); 
 414     if (!gtk_check_version(2,4,0)) 
 416         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 417         gtk_combo_box_append_text( combobox
,  wxGTK_CONV( item 
) ); 
 424         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 425         GtkWidget 
*list_item 
= gtk_list_item_new_with_label( wxGTK_CONV( item 
) ); 
 427         gtk_container_add( GTK_CONTAINER(list
), list_item 
); 
 429         if (GTK_WIDGET_REALIZED(m_widget
)) 
 431             gtk_widget_realize( list_item 
); 
 432             gtk_widget_realize( GTK_BIN(list_item
)->child 
); 
 435         // Apply current widget style to the new list_item 
 436         GtkRcStyle 
*style 
= CreateWidgetStyle(); 
 439             gtk_widget_modify_style( GTK_WIDGET( list_item 
), style 
); 
 440             GtkBin 
*bin 
= GTK_BIN( list_item 
); 
 441             GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
 442             gtk_widget_modify_style( label
, style 
); 
 443             gtk_rc_style_unref( style 
); 
 446         gtk_widget_show( list_item 
); 
 451     const unsigned int count 
= GetCount(); 
 453     if ( m_clientDataList
.GetCount() < count 
) 
 454         m_clientDataList
.Append( (wxObject
*) NULL 
); 
 455     if ( m_clientObjectList
.GetCount() < count 
) 
 456         m_clientObjectList
.Append( (wxObject
*) NULL 
); 
 458     InvalidateBestSize(); 
 463 int wxComboBox::DoInsert(const wxString 
&item
, unsigned int pos
) 
 465     wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT
), -1, 
 466                     wxT("can't insert into sorted list")); 
 468     wxCHECK_MSG( m_widget 
!= NULL
, -1, wxT("invalid combobox") ); 
 469     wxCHECK_MSG( IsValidInsert(pos
), -1, wxT("invalid index") ); 
 471     unsigned int count 
= GetCount(); 
 477     if (!gtk_check_version(2,4,0)) 
 479         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 480         gtk_combo_box_insert_text( combobox
, pos
, wxGTK_CONV( item 
) ); 
 487         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 488         GtkWidget 
*list_item 
= gtk_list_item_new_with_label( wxGTK_CONV( item 
) ); 
 490         GList 
*gitem_list 
= g_list_alloc (); 
 491         gitem_list
->data 
= list_item
; 
 492         gtk_list_insert_items( GTK_LIST (list
), gitem_list
, pos 
); 
 494         if (GTK_WIDGET_REALIZED(m_widget
)) 
 496             gtk_widget_realize( list_item 
); 
 497             gtk_widget_realize( GTK_BIN(list_item
)->child 
); 
 502         gtk_widget_show( list_item 
); 
 509     if ( m_clientDataList
.GetCount() < count 
) 
 510         m_clientDataList
.Insert( pos
, (wxObject
*) NULL 
); 
 511     if ( m_clientObjectList
.GetCount() < count 
) 
 512         m_clientObjectList
.Insert( pos
, (wxObject
*) NULL 
); 
 514     InvalidateBestSize(); 
 519 void wxComboBox::DoSetItemClientData(unsigned int n
, void* clientData
) 
 521     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 523     wxList::compatibility_iterator node 
= m_clientDataList
.Item( n 
); 
 526     node
->SetData( (wxObject
*) clientData 
); 
 529 void* wxComboBox::DoGetItemClientData(unsigned int n
) const 
 531     wxCHECK_MSG( m_widget 
!= NULL
, NULL
, wxT("invalid combobox") ); 
 533     wxList::compatibility_iterator node 
= m_clientDataList
.Item( n 
); 
 535     return node 
? node
->GetData() : NULL
; 
 538 void wxComboBox::DoSetItemClientObject(unsigned int n
, wxClientData
* clientData
) 
 540     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 542     wxList::compatibility_iterator node 
= m_clientObjectList
.Item( n 
); 
 545     // wxItemContainer already deletes data for us 
 547     node
->SetData( (wxObject
*) clientData 
); 
 550 wxClientData
* wxComboBox::DoGetItemClientObject(unsigned int n
) const 
 552     wxCHECK_MSG( m_widget 
!= NULL
, (wxClientData
*)NULL
, wxT("invalid combobox") ); 
 554     wxList::compatibility_iterator node 
= m_clientObjectList
.Item( n 
); 
 556     return node 
? (wxClientData
*) node
->GetData() : NULL
; 
 559 void wxComboBox::Clear() 
 561     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 566     if (!gtk_check_version(2,4,0)) 
 568         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 569         const unsigned int count 
= GetCount(); 
 570         for (unsigned int i 
= 0; i 
< count
; i
++) 
 571             gtk_combo_box_remove_text( combobox
, 0 ); 
 574 #endif // __WXGTK24__ 
 576         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 577         gtk_list_clear_items( GTK_LIST(list
), 0, GetCount() ); 
 580     wxList::compatibility_iterator node 
= m_clientObjectList
.GetFirst(); 
 583         wxClientData 
*cd 
= (wxClientData
*)node
->GetData(); 
 585         node 
= node
->GetNext(); 
 587     m_clientObjectList
.Clear(); 
 589     m_clientDataList
.Clear(); 
 593     InvalidateBestSize(); 
 596 void wxComboBox::Delete(unsigned int n
) 
 598     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 601     if (!gtk_check_version(2,4,0)) 
 603         wxCHECK_RET( IsValid(n
), wxT("invalid index") ); 
 605         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 606         gtk_combo_box_remove_text( combobox
, n 
); 
 611         GtkList 
*listbox 
= GTK_LIST( GTK_COMBO(m_widget
)->list 
); 
 613         GList 
*child 
= g_list_nth( listbox
->children
, n 
); 
 617             wxFAIL_MSG(wxT("wrong index")); 
 623         GList 
*list 
= g_list_append( (GList
*) NULL
, child
->data 
); 
 624         gtk_list_remove_items( listbox
, list 
); 
 630     wxList::compatibility_iterator node 
= m_clientObjectList
.Item( n 
); 
 633         wxClientData 
*cd 
= (wxClientData
*)node
->GetData(); 
 635         m_clientObjectList
.Erase( node 
); 
 638     node 
= m_clientDataList
.Item( n 
); 
 640         m_clientDataList
.Erase( node 
); 
 642     InvalidateBestSize(); 
 645 void wxComboBox::SetString(unsigned int n
, const wxString 
&text
) 
 647     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 650     if (!gtk_check_version(2,4,0)) 
 652         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 653         wxCHECK_RET( IsValid(n
), wxT("invalid index") ); 
 655         GtkTreeModel 
*model 
= gtk_combo_box_get_model( combobox 
); 
 657         if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, n
)) 
 659             GValue value 
= { 0, }; 
 660             g_value_init( &value
, G_TYPE_STRING 
); 
 661             g_value_set_string( &value
, wxGTK_CONV( text 
) ); 
 662             gtk_list_store_set_value( GTK_LIST_STORE(model
), &iter
, 0, &value 
); 
 663             g_value_unset( &value 
); 
 669         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 671         GList 
*child 
= g_list_nth( GTK_LIST(list
)->children
, n 
); 
 674             GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 675             GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 676             gtk_label_set_text(label
, wxGTK_CONV(text
)); 
 680             wxFAIL_MSG( wxT("wxComboBox: wrong index") ); 
 684     InvalidateBestSize(); 
 687 int wxComboBox::FindString( const wxString 
&item
, bool bCase 
) const 
 689     wxCHECK_MSG( m_widget 
!= NULL
, wxNOT_FOUND
, wxT("invalid combobox") ); 
 692     if (!gtk_check_version(2,4,0)) 
 694         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 695         GtkTreeModel
* model 
= gtk_combo_box_get_model( combobox 
); 
 697         gtk_tree_model_get_iter_first( model
, &iter 
); 
 698         if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model
), &iter 
)) 
 703             GValue value 
= { 0, }; 
 704             gtk_tree_model_get_value( model
, &iter
, 0, &value 
); 
 705             wxString str 
= wxGTK_CONV_BACK( g_value_get_string( &value 
) ); 
 706             g_value_unset( &value 
); 
 708             if (item
.IsSameAs( str
, bCase 
) ) 
 713         } while (gtk_tree_model_iter_next( model
, &iter 
)); 
 718         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 720         GList 
*child 
= GTK_LIST(list
)->children
; 
 724             GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 725             GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 726             wxString 
str( wxGTK_CONV_BACK( gtk_label_get_text(label
) ) ); 
 728             if (item
.IsSameAs( str 
, bCase 
) ) 
 739 int wxComboBox::GetSelection() const 
 742     if (!gtk_check_version(2,4,0)) 
 744         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 745         return gtk_combo_box_get_active( combobox 
); 
 749         // if the popup is currently opened, use the selection as it had been 
 750         // before it dropped down 
 751         return g_SelectionBeforePopup 
== wxID_NONE 
? GetCurrentSelection() 
 752                                                : g_SelectionBeforePopup
; 
 755 int wxComboBox::GetCurrentSelection() const 
 757     wxCHECK_MSG( m_widget 
!= NULL
, -1, wxT("invalid combobox") ); 
 760     if (!gtk_check_version(2,4,0)) 
 762         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 763         return gtk_combo_box_get_active( combobox 
); 
 768         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 770         GList 
*selection 
= GTK_LIST(list
)->selection
; 
 773             GList 
*child 
= GTK_LIST(list
)->children
; 
 777                 if (child
->data 
== selection
->data
) return count
; 
 787 wxString 
wxComboBox::GetString(unsigned int n
) const 
 789     wxCHECK_MSG( m_widget 
!= NULL
, wxEmptyString
, wxT("invalid combobox") ); 
 794     if (!gtk_check_version(2,4,0)) 
 796         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 797         GtkTreeModel 
*model 
= gtk_combo_box_get_model( combobox 
); 
 799         if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, n
)) 
 801             GValue value 
= { 0, }; 
 802             gtk_tree_model_get_value( model
, &iter
, 0, &value 
); 
 803             wxString tmp 
= wxGTK_CONV_BACK( g_value_get_string( &value 
) ); 
 804             g_value_unset( &value 
); 
 811         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 813         GList 
*child 
= g_list_nth( GTK_LIST(list
)->children
, n 
); 
 816             GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 817             GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 818             str 
= wxGTK_CONV_BACK( gtk_label_get_text(label
) ); 
 822             wxFAIL_MSG( wxT("wxComboBox: wrong index") ); 
 829 wxString 
wxComboBox::GetStringSelection() const 
 831     wxCHECK_MSG( m_widget 
!= NULL
, wxEmptyString
, wxT("invalid combobox") ); 
 834     if (!gtk_check_version(2,4,0)) 
 836         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 837         int sel 
= gtk_combo_box_get_active( combobox 
); 
 839             return wxEmptyString
; 
 840         return GetString(sel
); 
 845         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 847         GList 
*selection 
= GTK_LIST(list
)->selection
; 
 850             GtkBin 
*bin 
= GTK_BIN( selection
->data 
); 
 851             GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 852             wxString 
tmp( wxGTK_CONV_BACK( gtk_label_get_text(label
) ) ); 
 856         wxFAIL_MSG( wxT("wxComboBox: no selection") ); 
 859     return wxEmptyString
; 
 862 unsigned int wxComboBox::GetCount() const 
 864     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid combobox") ); 
 867     if (!gtk_check_version(2,4,0)) 
 869         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 870         GtkTreeModel
* model 
= gtk_combo_box_get_model( combobox 
); 
 872         gtk_tree_model_get_iter_first( model
, &iter 
); 
 873         if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model
), &iter 
)) 
 875         unsigned int ret 
= 1; 
 876         while (gtk_tree_model_iter_next( model
, &iter 
)) 
 883         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 885         GList 
*child 
= GTK_LIST(list
)->children
; 
 886         unsigned int count 
= 0; 
 898 void wxComboBox::SetSelection( int n 
) 
 900     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 905     if (!gtk_check_version(2,4,0)) 
 907         GtkComboBox
* combobox 
= GTK_COMBO_BOX( m_widget 
); 
 908         gtk_combo_box_set_active( combobox
, n 
); 
 913         GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 914         gtk_list_unselect_item( GTK_LIST(list
), m_prevSelection 
); 
 915         gtk_list_select_item( GTK_LIST(list
), n 
); 
 922 wxString 
wxComboBox::GetValue() const 
 924     GtkEntry 
*entry 
= NULL
; 
 926     if (!gtk_check_version(2,4,0)) 
 927         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
 930         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
 932     wxString 
tmp( wxGTK_CONV_BACK( gtk_entry_get_text( entry 
) ) ); 
 935     for (int i 
= 0; i 
< wxStrlen(tmp
.c_str()) +1; i
++) 
 938         printf( "%d ", (int) (c
) ); 
 946 void wxComboBox::SetValue( const wxString
& value 
) 
 948     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 950     GtkEntry 
*entry 
= NULL
; 
 952     if (!gtk_check_version(2,4,0)) 
 953         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
 956         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
 959     if (!value
.IsNull()) tmp 
= value
; 
 960     gtk_entry_set_text( entry
, wxGTK_CONV( tmp 
) ); 
 962     InvalidateBestSize(); 
 965 void wxComboBox::Copy() 
 967     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 969     GtkEntry 
*entry 
= NULL
; 
 971     if (!gtk_check_version(2,4,0)) 
 972         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
 975         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
 977     gtk_editable_copy_clipboard(GTK_EDITABLE(entry
)); 
 980 void wxComboBox::Cut() 
 982     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 984     GtkEntry 
*entry 
= NULL
; 
 986     if (!gtk_check_version(2,4,0)) 
 987         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
 990         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
 992     gtk_editable_cut_clipboard(GTK_EDITABLE(entry
)); 
 995 void wxComboBox::Paste() 
 997     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
 999     GtkEntry 
*entry 
= NULL
; 
1001     if (!gtk_check_version(2,4,0)) 
1002         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1005         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1007     gtk_editable_paste_clipboard(GTK_EDITABLE(entry
)); 
1010 void wxComboBox::Undo() 
1015 void wxComboBox::Redo() 
1020 void wxComboBox::SelectAll() 
1022     SetSelection(0, GetLastPosition()); 
1025 bool wxComboBox::CanUndo() const 
1031 bool wxComboBox::CanRedo() const 
1037 bool wxComboBox::HasSelection() const 
1040     GetSelection(&from
, &to
); 
1044 bool wxComboBox::CanCopy() const 
1046     // Can copy if there's a selection 
1047     return HasSelection(); 
1050 bool wxComboBox::CanCut() const 
1052     return CanCopy() && IsEditable(); 
1055 bool wxComboBox::CanPaste() const 
1057     // TODO: check for text on the clipboard 
1058     return IsEditable() ; 
1061 bool wxComboBox::IsEditable() const 
1063     return !HasFlag(wxCB_READONLY
); 
1067 void wxComboBox::SetInsertionPoint( long pos 
) 
1069     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
1071     if ( pos 
== GetLastPosition() ) 
1074     GtkEntry 
*entry 
= NULL
; 
1076     if (!gtk_check_version(2,4,0)) 
1077         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1080         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1082     gtk_entry_set_position( entry
, (int)pos 
); 
1085 long wxComboBox::GetInsertionPoint() const 
1087     GtkEntry 
*entry 
= NULL
; 
1089     if (!gtk_check_version(2,4,0)) 
1090         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1093         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1095     return (long) gtk_editable_get_position(GTK_EDITABLE(entry
)); 
1098 wxTextPos 
wxComboBox::GetLastPosition() const 
1100     GtkEntry 
*entry 
= NULL
; 
1102     if (!gtk_check_version(2,4,0)) 
1103         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1106         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1108     int pos 
= entry
->text_length
; 
1109     return (long) pos
-1; 
1112 void wxComboBox::Replace( long from
, long to
, const wxString
& value 
) 
1114     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid combobox") ); 
1116     GtkEntry 
*entry 
= NULL
; 
1118     if (!gtk_check_version(2,4,0)) 
1119         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1122         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1124     gtk_editable_delete_text( GTK_EDITABLE(entry
), (gint
)from
, (gint
)to 
); 
1125     if (value
.IsNull()) return; 
1126     gint pos 
= (gint
)to
; 
1129     wxCharBuffer buffer 
= wxConvUTF8
.cWX2MB( value 
); 
1130     gtk_editable_insert_text( GTK_EDITABLE(entry
), (const char*) buffer
, strlen( (const char*) buffer 
), &pos 
); 
1132     gtk_editable_insert_text( GTK_EDITABLE(entry
), value
.c_str(), value
.length(), &pos 
); 
1136 void wxComboBox::SetSelection( long from
, long to 
) 
1138     GtkEntry 
*entry 
= NULL
; 
1140     if (!gtk_check_version(2,4,0)) 
1141         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1144         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1146     gtk_editable_select_region( GTK_EDITABLE(entry
), (gint
)from
, (gint
)to 
); 
1149 void wxComboBox::GetSelection( long* from
, long* to 
) const 
1151     GtkEntry 
*entry 
= NULL
; 
1153     if (!gtk_check_version(2,4,0)) 
1154         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1157         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1161         GtkEditable 
*editable 
= GTK_EDITABLE(entry
); 
1163         gtk_editable_get_selection_bounds(editable
, & start
, & end
); 
1169 void wxComboBox::SetEditable( bool editable 
) 
1171     GtkEntry 
*entry 
= NULL
; 
1173     if (!gtk_check_version(2,4,0)) 
1174         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1177         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1179     gtk_entry_set_editable( GTK_ENTRY(entry
), editable 
); 
1182 void wxComboBox::OnChar( wxKeyEvent 
&event 
) 
1184     if ( event
.GetKeyCode() == WXK_RETURN 
) 
1186         // GTK automatically selects an item if its in the list 
1187         wxCommandEvent 
eventEnter(wxEVT_COMMAND_TEXT_ENTER
, GetId()); 
1188         eventEnter
.SetString( GetValue() ); 
1189         eventEnter
.SetInt( GetSelection() ); 
1190         eventEnter
.SetEventObject( this ); 
1192         if (!GetEventHandler()->ProcessEvent( eventEnter 
)) 
1194             // This will invoke the dialog default action, such 
1195             // as the clicking the default button. 
1197             wxWindow 
*top_frame 
= m_parent
; 
1198             while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
1199                 top_frame 
= top_frame
->GetParent(); 
1201             if (top_frame 
&& GTK_IS_WINDOW(top_frame
->m_widget
)) 
1203                 GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
1205                 if (window
->default_widget
) 
1206                         gtk_widget_activate (window
->default_widget
); 
1210         // Catch GTK event so that GTK doesn't open the drop 
1211         // down list upon RETURN. 
1218 void wxComboBox::DisableEvents() 
1221     if (!gtk_check_version(2,4,0)) 
1223         g_signal_handlers_disconnect_by_func (GTK_BIN(m_widget
)->child
, 
1224                 (gpointer
)gtkcombobox_text_changed_callback
, this); 
1226         g_signal_handlers_disconnect_by_func (m_widget
, 
1227                 (gpointer
)gtkcombobox_changed_callback
, this); 
1232         g_signal_handlers_disconnect_by_func (GTK_COMBO(m_widget
)->list
, 
1233                 (gpointer
) gtkcombo_combo_select_child_callback
, this); 
1235         g_signal_handlers_disconnect_by_func (GTK_COMBO(m_widget
)->entry
, 
1236                 (gpointer
) gtkcombo_text_changed_callback
, this); 
1240 void wxComboBox::EnableEvents() 
1243     if (!gtk_check_version(2,4,0)) 
1245         g_signal_connect_after (GTK_BIN(m_widget
)->child
, "changed", 
1246                             G_CALLBACK (gtkcombobox_text_changed_callback
), this); 
1248         g_signal_connect_after (m_widget
, "changed", 
1249                             G_CALLBACK (gtkcombobox_changed_callback
), this); 
1254         g_signal_connect_after (GTK_COMBO(m_widget
)->list
, "select-child", 
1255                             G_CALLBACK (gtkcombo_combo_select_child_callback
), 
1257         g_signal_connect_after (GTK_COMBO(m_widget
)->entry
, "changed", 
1258                             G_CALLBACK (gtkcombo_text_changed_callback
), 
1263 void wxComboBox::OnSize( wxSizeEvent 
&event 
) 
1266     if (!gtk_check_version(2,4,0)) 
1273         // NB: In some situations (e.g. on non-first page of a wizard, if the 
1274         //     size used is default size), GtkCombo widget is resized correctly, 
1275         //     but it's look is not updated, it's rendered as if it was much wider. 
1276         //     No other widgets are affected, so it looks like a bug in GTK+. 
1277         //     Manually requesting resize calculation (as gtk_pizza_set_size does) 
1279         if (GTK_WIDGET_VISIBLE(m_widget
)) 
1280             gtk_widget_queue_resize(m_widget
); 
1286 void wxComboBox::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
1289     if (!gtk_check_version(2,4,0)) 
1296 //    gtk_widget_modify_style( GTK_COMBO(m_widget)->button, syle ); 
1298         gtk_widget_modify_style( GTK_COMBO(m_widget
)->entry
, style 
); 
1299         gtk_widget_modify_style( GTK_COMBO(m_widget
)->list
, style 
); 
1301         GtkList 
*list 
= GTK_LIST( GTK_COMBO(m_widget
)->list 
); 
1302         GList 
*child 
= list
->children
; 
1305             gtk_widget_modify_style( GTK_WIDGET(child
->data
), style 
); 
1307             GtkBin 
*bin 
= GTK_BIN(child
->data
); 
1308             gtk_widget_modify_style( bin
->child
, style 
); 
1310             child 
= child
->next
; 
1315 GtkWidget
* wxComboBox::GetConnectWidget() 
1317     GtkEntry 
*entry 
= NULL
; 
1319     if (!gtk_check_version(2,4,0)) 
1320         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1323         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1325     return GTK_WIDGET( entry 
); 
1328 bool wxComboBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
1330     GtkEntry 
*entry 
= NULL
; 
1332     if (!gtk_check_version(2,4,0)) 
1334         entry 
= GTK_ENTRY( GTK_BIN(m_widget
)->child 
); 
1335         return (window 
== entry
->text_area
); 
1340         entry 
= GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
); 
1341         return ( (window 
== entry
->text_area
) || 
1342                  (window 
== GTK_COMBO(m_widget
)->button
->window 
) ); 
1346 wxSize 
wxComboBox::DoGetBestSize() const 
1348     wxSize 
ret( wxControl::DoGetBestSize() ); 
1350     // we know better our horizontal extent: it depends on the longest string 
1355         unsigned int count 
= GetCount(); 
1356         for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
1358             GetTextExtent(GetString(n
), &width
, NULL
, NULL
, NULL 
); 
1359             if ( width 
> ret
.x 
) 
1364     // empty combobox should have some reasonable default size too 
1374 wxComboBox::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
1377     if (!gtk_check_version(2,4,0)) 
1378         return GetDefaultAttributesFromGTKWidget(gtk_combo_box_entry_new
, true); 
1381         return GetDefaultAttributesFromGTKWidget(gtk_combo_new
, true); 
1384 // ---------------------------------------------------------------------------- 
1385 // standard event handling 
1386 // ---------------------------------------------------------------------------- 
1388 void wxComboBox::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
1393 void wxComboBox::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1398 void wxComboBox::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
1403 void wxComboBox::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
1408 void wxComboBox::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
1413 void wxComboBox::OnDelete(wxCommandEvent
& WXUNUSED(event
)) 
1416     GetSelection(& from
, & to
); 
1417     if (from 
!= -1 && to 
!= -1) 
1421 void wxComboBox::OnSelectAll(wxCommandEvent
& WXUNUSED(event
)) 
1423     SetSelection(-1, -1); 
1426 void wxComboBox::OnUpdateCut(wxUpdateUIEvent
& event
) 
1428     event
.Enable( CanCut() ); 
1431 void wxComboBox::OnUpdateCopy(wxUpdateUIEvent
& event
) 
1433     event
.Enable( CanCopy() ); 
1436 void wxComboBox::OnUpdatePaste(wxUpdateUIEvent
& event
) 
1438     event
.Enable( CanPaste() ); 
1441 void wxComboBox::OnUpdateUndo(wxUpdateUIEvent
& event
) 
1443     event
.Enable( CanUndo() ); 
1446 void wxComboBox::OnUpdateRedo(wxUpdateUIEvent
& event
) 
1448     event
.Enable( CanRedo() ); 
1451 void wxComboBox::OnUpdateDelete(wxUpdateUIEvent
& event
) 
1453     event
.Enable(HasSelection() && IsEditable()) ; 
1456 void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent
& event
) 
1458     event
.Enable(GetLastPosition() > 0);