+bool wxComboBox::IsEditable() const
+{
+ return !HasFlag(wxCB_READONLY);
+}
+
+
+void wxComboBox::SetInsertionPoint( long pos )
+{
+ wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
+
+ if ( pos == GetLastPosition() )
+ pos = -1;
+
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ gtk_entry_set_position( entry, (int)pos );
+}
+
+long wxComboBox::GetInsertionPoint() const
+{
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ return (long) gtk_editable_get_position(GTK_EDITABLE(entry));
+}
+
+wxTextPos wxComboBox::GetLastPosition() const
+{
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ int pos = entry->text_length;
+ return (long) pos-1;
+}
+
+void wxComboBox::Replace( long from, long to, const wxString& value )
+{
+ wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
+
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ gtk_editable_delete_text( GTK_EDITABLE(entry), (gint)from, (gint)to );
+ if (value.IsNull()) return;
+ gint pos = (gint)to;
+
+#if wxUSE_UNICODE
+ wxCharBuffer buffer = wxConvUTF8.cWX2MB( value );
+ gtk_editable_insert_text( GTK_EDITABLE(entry), (const char*) buffer, strlen( (const char*) buffer ), &pos );
+#else
+ gtk_editable_insert_text( GTK_EDITABLE(entry), value.c_str(), value.length(), &pos );
+#endif
+}
+
+void wxComboBox::SetSelection( long from, long to )
+{
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ gtk_editable_select_region( GTK_EDITABLE(entry), (gint)from, (gint)to );
+}
+
+void wxComboBox::GetSelection( long* from, long* to ) const
+{
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ if (IsEditable())
+ {
+ GtkEditable *editable = GTK_EDITABLE(entry);
+ gint start, end;
+ gtk_editable_get_selection_bounds(editable, & start, & end);
+ *from = start;
+ *to = end;
+ }
+}
+
+void wxComboBox::SetEditable( bool editable )
+{
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ gtk_entry_set_editable( GTK_ENTRY(entry), editable );
+}
+
+void wxComboBox::OnChar( wxKeyEvent &event )
+{
+ if ( event.GetKeyCode() == WXK_RETURN )
+ {
+ // GTK automatically selects an item if its in the list
+ wxCommandEvent eventEnter(wxEVT_COMMAND_TEXT_ENTER, GetId());
+ eventEnter.SetString( GetValue() );
+ eventEnter.SetInt( GetSelection() );
+ eventEnter.SetEventObject( this );
+
+ if (!GetEventHandler()->ProcessEvent( eventEnter ))
+ {
+ // This will invoke the dialog default action, such
+ // as the clicking the default button.
+
+ wxWindow *top_frame = m_parent;
+ while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
+ top_frame = top_frame->GetParent();
+
+ if (top_frame && GTK_IS_WINDOW(top_frame->m_widget))
+ {
+ GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
+
+ if (window->default_widget)
+ gtk_widget_activate (window->default_widget);
+ }
+ }
+
+ // Catch GTK event so that GTK doesn't open the drop
+ // down list upon RETURN.
+ return;
+ }
+
+ event.Skip();
+}
+
+void wxComboBox::DisableEvents()
+{
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ {
+ g_signal_handlers_disconnect_by_func (GTK_BIN(m_widget)->child,
+ (gpointer)gtkcombobox_text_changed_callback, this);
+
+ g_signal_handlers_disconnect_by_func (m_widget,
+ (gpointer)gtkcombobox_changed_callback, this);
+ }
+ else
+#endif
+ {
+ g_signal_handlers_disconnect_by_func (GTK_COMBO(m_widget)->list,
+ (gpointer) gtkcombo_combo_select_child_callback, this);
+
+ g_signal_handlers_disconnect_by_func (GTK_COMBO(m_widget)->entry,
+ (gpointer) gtkcombo_text_changed_callback, this);
+ }
+}
+
+void wxComboBox::EnableEvents()
+{
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ {
+ g_signal_connect_after (GTK_BIN(m_widget)->child, "changed",
+ G_CALLBACK (gtkcombobox_text_changed_callback), this);
+
+ g_signal_connect_after (m_widget, "changed",
+ G_CALLBACK (gtkcombobox_changed_callback), this);
+ }
+ else
+#endif
+ {
+ g_signal_connect_after (GTK_COMBO(m_widget)->list, "select-child",
+ G_CALLBACK (gtkcombo_combo_select_child_callback),
+ this);
+ g_signal_connect_after (GTK_COMBO(m_widget)->entry, "changed",
+ G_CALLBACK (gtkcombo_text_changed_callback),
+ this );
+ }
+}
+
+void wxComboBox::OnSize( wxSizeEvent &event )
+{
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ {
+ // Do nothing
+ }
+ else
+#endif
+ {
+ // NB: In some situations (e.g. on non-first page of a wizard, if the
+ // size used is default size), GtkCombo widget is resized correctly,
+ // but it's look is not updated, it's rendered as if it was much wider.
+ // No other widgets are affected, so it looks like a bug in GTK+.
+ // Manually requesting resize calculation (as gtk_pizza_set_size does)
+ // fixes it.
+ if (GTK_WIDGET_VISIBLE(m_widget))
+ gtk_widget_queue_resize(m_widget);
+ }
+
+ event.Skip();
+}
+
+void wxComboBox::DoApplyWidgetStyle(GtkRcStyle *style)
+{
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ {
+ // Do nothing
+ }
+ else
+#endif
+ {
+// gtk_widget_modify_style( GTK_COMBO(m_widget)->button, syle );
+
+ gtk_widget_modify_style( GTK_COMBO(m_widget)->entry, style );
+ gtk_widget_modify_style( GTK_COMBO(m_widget)->list, style );
+
+ GtkList *list = GTK_LIST( GTK_COMBO(m_widget)->list );
+ GList *child = list->children;
+ while (child)
+ {
+ gtk_widget_modify_style( GTK_WIDGET(child->data), style );
+
+ GtkBin *bin = GTK_BIN(child->data);
+ gtk_widget_modify_style( bin->child, style );
+
+ child = child->next;
+ }
+ }
+}
+
+GtkWidget* wxComboBox::GetConnectWidget()
+{
+ GtkEntry *entry = NULL;
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
+ else
+#endif
+ entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
+
+ return GTK_WIDGET( entry );
+}
+
+GdkWindow *wxComboBox::GTKGetWindow(wxArrayGdkWindows& windows) const
+{
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ {
+ wxUnusedVar(windows);
+
+ return GTK_ENTRY(GTK_BIN(m_widget)->child)->text_area;
+ }
+ else
+#endif // GTK+ 2.4
+ {
+ windows.push_back(GTK_ENTRY(GTK_COMBO(m_widget)->entry)->text_area);
+ windows.push_back(GTK_COMBO(m_widget)->button->window);
+
+ // indicate that we return multiple windows in the windows array
+ return NULL;
+ }
+}
+
+wxSize wxComboBox::DoGetBestSize() const
+{
+ wxSize ret( wxControl::DoGetBestSize() );
+
+ // we know better our horizontal extent: it depends on the longest string
+ // in the combobox
+ if ( m_widget )
+ {
+ int width;
+ unsigned int count = GetCount();
+ for ( unsigned int n = 0; n < count; n++ )
+ {
+ GetTextExtent(GetString(n), &width, NULL, NULL, NULL );
+ if ( width > ret.x )
+ ret.x = width;
+ }
+ }
+
+ // empty combobox should have some reasonable default size too
+ if ( ret.x < 100 )
+ ret.x = 100;
+
+ CacheBestSize(ret);
+ return ret;
+}
+
+// static
+wxVisualAttributes
+wxComboBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+{
+#ifdef __WXGTK24__
+ if (!gtk_check_version(2,4,0))
+ return GetDefaultAttributesFromGTKWidget(gtk_combo_box_entry_new, true);
+ else
+#endif
+ return GetDefaultAttributesFromGTKWidget(gtk_combo_new, true);
+}
+
+// ----------------------------------------------------------------------------
+// standard event handling
+// ----------------------------------------------------------------------------
+
+void wxComboBox::OnCut(wxCommandEvent& WXUNUSED(event))
+{
+ Cut();
+}
+
+void wxComboBox::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+ Copy();
+}
+
+void wxComboBox::OnPaste(wxCommandEvent& WXUNUSED(event))
+{
+ Paste();
+}
+
+void wxComboBox::OnUndo(wxCommandEvent& WXUNUSED(event))
+{
+ Undo();
+}
+
+void wxComboBox::OnRedo(wxCommandEvent& WXUNUSED(event))
+{
+ Redo();
+}
+
+void wxComboBox::OnDelete(wxCommandEvent& WXUNUSED(event))
+{
+ long from, to;
+ GetSelection(& from, & to);
+ if (from != -1 && to != -1)
+ Remove(from, to);
+}
+
+void wxComboBox::OnSelectAll(wxCommandEvent& WXUNUSED(event))
+{
+ SetSelection(-1, -1);
+}
+
+void wxComboBox::OnUpdateCut(wxUpdateUIEvent& event)
+{
+ event.Enable( CanCut() );
+}
+
+void wxComboBox::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+ event.Enable( CanCopy() );
+}
+
+void wxComboBox::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+ event.Enable( CanPaste() );
+}
+
+void wxComboBox::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+ event.Enable( CanUndo() );
+}
+
+void wxComboBox::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+ event.Enable( CanRedo() );
+}
+
+void wxComboBox::OnUpdateDelete(wxUpdateUIEvent& event)
+{
+ event.Enable(HasSelection() && IsEditable()) ;
+}
+
+void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent& event)
+{
+ event.Enable(GetLastPosition() > 0);
+}
+
+#endif