+void wxTextCtrl::DoSendEvents(void *wxcbs, long keycode)
+{
+ // we're in process of updating the text control
+ m_tempCallbackStruct = wxcbs;
+
+ XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)wxcbs;
+
+ wxKeyEvent event (wxEVT_CHAR);
+ event.SetId(GetId());
+ event.m_keyCode = keycode;
+ event.SetEventObject(this);
+
+ // Only if wxTextCtrl::OnChar is called will this be set to True (and
+ // the character passed through)
+ cbs->doit = False;
+
+ GetEventHandler()->ProcessEvent(event);
+
+ if ( !InSetValue() && m_processedDefault )
+ {
+ // Can generate a command
+ wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, GetId());
+ commandEvent.SetEventObject(this);
+ ProcessCommand(commandEvent);
+ }
+
+ // do it after the (user) event handlers processed the events because
+ // otherwise GetValue() would return incorrect (not yet updated value)
+ m_tempCallbackStruct = NULL;
+}
+
+// ----------------------------------------------------------------------------
+// helpers and Motif callbacks
+// ----------------------------------------------------------------------------
+
+static void MergeChangesIntoString(wxString& value,
+ XmTextVerifyCallbackStruct *cbs)
+{
+ /* _sm_
+ * At least on my system (SunOS 4.1.3 + Motif 1.2), you need to think of
+ * every event as a replace event. cbs->text->ptr gives the replacement
+ * text, cbs->startPos gives the index of the first char affected by the
+ * replace, and cbs->endPos gives the index one more than the last char
+ * affected by the replace (startPos == endPos implies an empty range).
+ * Hence, a deletion is represented by replacing all input text with a
+ * blank string ("", *not* NULL!). A simple insertion that does not
+ * overwrite any text has startPos == endPos.
+ */
+
+ if ( !value )
+ {
+ // easy case: the ol value was empty
+ value = cbs->text->ptr;
+ }
+ else
+ {
+ // merge the changes into the value
+ const char * const passwd = value;
+ int len = value.length();
+
+ len += strlen(cbs->text->ptr) + 1; // + new text (if any) + NUL
+ len -= cbs->endPos - cbs->startPos; // - text from affected region.
+
+ char * newS = new char [len];
+ char * dest = newS,
+ * insert = cbs->text->ptr;
+
+ // Copy (old) text from passwd, up to the start posn of the change.
+ int i;
+ const char * p = passwd;
+ for (i = 0; i < cbs->startPos; ++i)
+ *dest++ = *p++;
+
+ // Copy the text to be inserted).
+ while (*insert)
+ *dest++ = *insert++;
+
+ // Finally, copy into newS any remaining text from passwd[endPos] on.
+ for (p = passwd + cbs->endPos; *p; )
+ *dest++ = *p++;
+ *dest = 0;
+
+ value = newS;
+
+ delete[] newS;
+ }
+}
+
+static void
+wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
+{
+ if (!wxGetWindowFromTable(w))
+ // Widget has been deleted!
+ return;
+
+ wxTextCtrl *tw = (wxTextCtrl *) clientData;
+ tw->SetModified(TRUE);
+}
+
+static void
+wxTextWindowModifyProc (Widget WXUNUSED(w), XtPointer clientData, XmTextVerifyCallbackStruct *cbs)
+{
+ wxTextCtrl *tw = (wxTextCtrl *) clientData;
+ tw->m_processedDefault = FALSE;
+
+ // First, do some stuff if it's a password control: in this case, we need
+ // to store the string inside the class because GetValue() can't retrieve
+ // it from the text ctrl. We do *not* do it in other circumstances because
+ // it would double the amount of memory needed.
+
+ if ( tw->GetWindowStyleFlag() & wxTE_PASSWORD )
+ {
+ MergeChangesIntoString(tw->m_value, cbs);
+
+ if ( cbs->text->length > 0 )
+ {
+ int i;
+ for (i = 0; i < cbs->text->length; ++i)
+ cbs->text->ptr[i] = '*';
+ cbs->text->ptr[i] = '\0';
+ }
+ }
+
+ // If we're already within an OnChar, return: probably a programmatic
+ // insertion.
+ if (tw->m_tempCallbackStruct)
+ return;
+
+ // Check for a backspace
+ if (cbs->startPos == (cbs->currInsert - 1))
+ {
+ tw->DoSendEvents((void *)cbs, WXK_DELETE);
+
+ return;
+ }
+
+ // Pasting operation: let it through without calling OnChar
+ if (cbs->text->length > 1)
+ return;
+
+ // Something other than text
+ if (cbs->text->ptr == NULL)
+ return;
+
+ // normal key press
+ char ch = cbs->text->ptr[0];
+ tw->DoSendEvents((void *)cbs, ch == '\n' ? '\r' : ch);
+}
+
+static void
+wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs))
+{
+ if (!wxGetWindowFromTable(w))
+ return;
+
+ wxTextCtrl *tw = (wxTextCtrl *) clientData;
+ wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId());
+ event.SetEventObject(tw);
+ tw->GetEventHandler()->ProcessEvent(event);
+}
+
+static void
+wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs))