]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/textctrl.cpp
don't crash if m_widget == NULL in OnInternalIdle()
[wxWidgets.git] / src / gtk / textctrl.cpp
index 3faedf4790b4c2e7a419cc3f6364efd407adb3ce..b9671b28503b39c6ff6b36340a35d66476145b8e 100644 (file)
     #include "wx/log.h"
     #include "wx/utils.h"
     #include "wx/panel.h"
+    #include "wx/settings.h"
+    #include "wx/math.h"
 #endif
 
-#include "wx/math.h"
-#include "wx/settings.h"
 #include "wx/strconv.h"
 #include "wx/fontutil.h"        // for wxNativeFontInfo (GetNativeFontInfo())
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
-#include "wx/math.h"
 
 #include "wx/gtk/private.h"
 #include <gdk/gdkkeysyms.h>
@@ -105,7 +104,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkTextBuffer *text_buffer,
 
     if (attr.HasTextColour())
     {
-        GdkColor *colFg = attr.GetTextColour().GetColor();
+        const GdkColor *colFg = attr.GetTextColour().GetColor();
         g_snprintf(buf, sizeof(buf), "WXFORECOLOR %d %d %d",
                    colFg->red, colFg->green, colFg->blue);
         tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ),
@@ -118,7 +117,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkTextBuffer *text_buffer,
 
     if (attr.HasBackgroundColour())
     {
-        GdkColor *colBg = attr.GetBackgroundColour().GetColor();
+        const GdkColor *colBg = attr.GetBackgroundColour().GetColor();
         g_snprintf(buf, sizeof(buf), "WXBACKCOLOR %d %d %d",
                    colBg->red, colBg->green, colBg->blue);
         tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ),
@@ -454,7 +453,8 @@ gtk_text_changed_callback( GtkWidget *widget, wxTextCtrl *win )
     if (g_isIdle)
         wxapp_install_idle_handler();
 
-    win->SetModified();
+    if ( win->MarkDirtyOnChange() )
+        win->MarkDirty();
 
     wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
     event.SetEventObject( win );
@@ -462,6 +462,48 @@ gtk_text_changed_callback( GtkWidget *widget, wxTextCtrl *win )
 }
 }
 
+//-----------------------------------------------------------------------------
+//  clipboard events: "copy-clipboard", "cut-clipboard", "paste-clipboard"
+//-----------------------------------------------------------------------------
+
+// common part of the event handlers below
+static void
+handle_text_clipboard_callback( GtkWidget *widget, wxTextCtrl *win,
+                                wxEventType eventType, const gchar * signal_name)
+{
+    wxClipboardTextEvent event( eventType, win->GetId() );
+    event.SetEventObject( win );
+    if ( win->GetEventHandler()->ProcessEvent( event ) )
+    {
+        // don't let the default processing to take place if we did something
+        // ourselves in the event handler
+        g_signal_stop_emission_by_name (widget, signal_name);
+    }
+}
+
+extern "C" {
+static void
+gtk_copy_clipboard_callback( GtkWidget *widget, wxTextCtrl *win )
+{
+    handle_text_clipboard_callback(
+        widget, win, wxEVT_COMMAND_TEXT_COPY, "copy-clipboard" );
+}
+
+static void
+gtk_cut_clipboard_callback( GtkWidget *widget, wxTextCtrl *win )
+{
+    handle_text_clipboard_callback(
+        widget, win, wxEVT_COMMAND_TEXT_CUT, "cut-clipboard" );
+}
+
+static void
+gtk_paste_clipboard_callback( GtkWidget *widget, wxTextCtrl *win )
+{
+    handle_text_clipboard_callback(
+        widget, win, wxEVT_COMMAND_TEXT_PASTE, "paste-clipboard" );
+}
+}
+
 //-----------------------------------------------------------------------------
 // "expose_event" from scrolled window and textview
 //-----------------------------------------------------------------------------
@@ -479,9 +521,9 @@ gtk_text_exposed_callback( GtkWidget *widget, GdkEventExpose *event, wxTextCtrl
 //  wxTextCtrl
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl,wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase)
 
-BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
     EVT_CHAR(wxTextCtrl::OnChar)
 
     EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
@@ -509,9 +551,12 @@ END_EVENT_TABLE()
 
 void wxTextCtrl::Init()
 {
+    m_dontMarkDirty =
     m_ignoreNextUpdate =
     m_modified = false;
+
     SetUpdateFont(false);
+
     m_text = NULL;
     m_frozenness = 0;
     m_gdkHandCursor = NULL;
@@ -572,6 +617,8 @@ bool wxTextCtrl::Create( wxWindow *parent,
         m_widget = gtk_scrolled_window_new( NULL, NULL );
         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( m_widget ),
                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+        // for ScrollLines/Pages
+        m_scrollBar[1] = (GtkRange*)((GtkScrolledWindow*)m_widget)->vscrollbar;
 
         // Insert view into scrolled window
         gtk_container_add( GTK_CONTAINER(m_widget), m_text );
@@ -612,7 +659,7 @@ bool wxTextCtrl::Create( wxWindow *parent,
         m_text = gtk_entry_new();
 
         if (style & wxNO_BORDER)
-            g_object_set( GTK_ENTRY(m_text), "has-frame", FALSE, NULL );
+            g_object_set (m_text, "has-frame", FALSE, NULL);
     }
 
     m_parent->DoAddChild( this );
@@ -624,7 +671,6 @@ bool wxTextCtrl::Create( wxWindow *parent,
     if (multi_line)
     {
         gtk_widget_show(m_text);
-        SetVScrollAdjustment(gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)m_widget));
     }
 
     if (!value.empty())
@@ -716,6 +762,13 @@ bool wxTextCtrl::Create( wxWindow *parent,
                           G_CALLBACK (gtk_text_changed_callback), this);
     }
 
+    g_signal_connect (m_text, "copy-clipboard",
+                      G_CALLBACK (gtk_copy_clipboard_callback), this);
+    g_signal_connect (m_text, "cut-clipboard",
+                      G_CALLBACK (gtk_cut_clipboard_callback), this);
+    g_signal_connect (m_text, "paste-clipboard",
+                      G_CALLBACK (gtk_paste_clipboard_callback), this);
+
     m_cursor = wxCursor( wxCURSOR_IBEAM );
 
     wxTextAttr attrDef(GetForegroundColour(), GetBackgroundColour(), GetFont());
@@ -763,6 +816,13 @@ void wxTextCtrl::SetValue( const wxString &value )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
+    // the control won't be modified any more as we programmatically replace
+    // all the existing text, so reset the flag and don't set it again (and do
+    // it now, before the text event handler is ran so that IsModified() called
+    // from there returns the expected value)
+    m_modified = false;
+    DontMarkDirtyOnNextChange();
+
     if (m_windowStyle & wxTE_MULTILINE)
     {
         const wxCharBuffer buffer(wxGTK_CONV(value));
@@ -791,8 +851,6 @@ void wxTextCtrl::SetValue( const wxString &value )
     //   the lists. wxWidgets 2.2 will have a set of flags to
     //   customize this behaviour.
     SetInsertionPoint(0);
-
-    m_modified = false;
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
@@ -809,10 +867,8 @@ void wxTextCtrl::WriteText( const wxString &text )
         return;
     }
 
-    // gtk_text_changed_callback() will set m_modified to true but m_modified
-    // shouldn't be changed by the program writing to the text control itself,
-    // so save the old value and restore when we're done
-    bool oldModified = m_modified;
+    // we're changing the text programmatically
+    DontMarkDirtyOnNextChange();
 
     if ( m_windowStyle & wxTE_MULTILINE )
     {
@@ -847,8 +903,6 @@ void wxTextCtrl::WriteText( const wxString &text )
         // Bring entry's cursor uptodate.
         gtk_editable_set_position( GTK_EDITABLE(m_text), len );
     }
-
-    m_modified = oldModified;
 }
 
 void wxTextCtrl::AppendText( const wxString &text )
@@ -889,19 +943,25 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y ) const
     if ( m_windowStyle & wxTE_MULTILINE )
     {
         GtkTextIter iter;
-        gtk_text_buffer_get_iter_at_offset(m_buffer, &iter, pos);
-        if (gtk_text_iter_is_end(&iter))
+
+        if (pos > GetLastPosition())
             return false;
 
-        *y = gtk_text_iter_get_line(&iter);
-        *x = gtk_text_iter_get_line_offset(&iter);
+        gtk_text_buffer_get_iter_at_offset(m_buffer, &iter, pos);
+
+        if ( y )
+            *y = gtk_text_iter_get_line(&iter);
+        if ( x )
+            *x = gtk_text_iter_get_line_offset(&iter);
     }
     else // single line control
     {
         if ( pos <= GTK_ENTRY(m_text)->text_length )
         {
-            *y = 0;
-            *x = pos;
+            if ( y )
+                *y = 0;
+            if ( x )
+                *x = pos;
         }
         else
         {
@@ -1090,11 +1150,6 @@ void wxTextCtrl::DiscardEdits()
 // max text length support
 // ----------------------------------------------------------------------------
 
-void wxTextCtrl::IgnoreNextTextUpdate()
-{
-    m_ignoreNextUpdate = true;
-}
-
 bool wxTextCtrl::IgnoreTextUpdate()
 {
     if ( m_ignoreNextUpdate )
@@ -1107,6 +1162,18 @@ bool wxTextCtrl::IgnoreTextUpdate()
     return false;
 }
 
+bool wxTextCtrl::MarkDirtyOnChange()
+{
+    if ( m_dontMarkDirty )
+    {
+        m_dontMarkDirty = false;
+
+        return false;
+    }
+
+    return true;
+}
+
 void wxTextCtrl::SetMaxLength(unsigned long len)
 {
     if ( !HasFlag(wxTE_MULTILINE) )