From e702ff0f08a54622a6b0f1e2ec39537b082c3a8e Mon Sep 17 00:00:00 2001
From: Julian Smart <julian@anthemion.co.uk>
Date: Wed, 7 Apr 1999 21:33:22 +0000
Subject: [PATCH] Menu/toolbar event handling now tries the window with the
 focus first. wxTextCtrl processes cut, copy, paste, undo, redo commands and
 UI updates automatically.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2069 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/menu.tex      | 10 ++++-
 docs/latex/wx/tevent.tex    | 20 ++++++++-
 docs/latex/wx/text.tex      |  4 ++
 docs/latex/wx/toolbar.tex   |  7 +++
 docs/latex/wx/ttoolbar.tex  | 14 +++---
 include/wx/event.h          |  8 ++++
 include/wx/gtk/frame.h      |  2 +-
 include/wx/gtk/textctrl.h   | 12 ++++++
 include/wx/gtk1/frame.h     |  2 +-
 include/wx/gtk1/textctrl.h  | 12 ++++++
 include/wx/mac/frame.h      |  2 +-
 include/wx/motif/frame.h    |  2 +-
 include/wx/motif/textctrl.h | 14 +++++-
 include/wx/msw/frame.h      |  2 +-
 include/wx/msw/textctrl.h   | 12 ++++++
 include/wx/stubs/frame.h    |  2 +-
 include/wx/stubs/textctrl.h | 13 +++++-
 src/common/event.cpp        | 23 ++++++++++
 src/common/framecmn.cpp     | 13 ++++--
 src/common/tbarbase.cpp     | 49 ++++++++++++++++++++-
 src/gtk.inc                 |  1 +
 src/gtk/frame.cpp           |  8 +++-
 src/gtk/tbargtk.cpp         | 23 ++++++++++
 src/gtk/textctrl.cpp        | 61 ++++++++++++++++++++++++++
 src/gtk1/frame.cpp          |  8 +++-
 src/gtk1/tbargtk.cpp        | 23 ++++++++++
 src/gtk1/textctrl.cpp       | 61 ++++++++++++++++++++++++++
 src/mac/carbon/frame.cpp    |  7 ++-
 src/mac/frame.cpp           |  7 ++-
 src/motif.inc               |  1 +
 src/motif/frame.cpp         |  7 ++-
 src/motif/makefile.unx      |  1 +
 src/motif/textctrl.cpp      | 62 +++++++++++++++++++++++++++
 src/msw/frame.cpp           |  7 ++-
 src/msw/makefile.vc         |  1 +
 src/msw/textctrl.cpp        | 85 ++++++++++++++++++++++++++++++++++---
 src/stubs/frame.cpp         |  7 ++-
 src/stubs/textctrl.cpp      | 60 ++++++++++++++++++++++++++
 38 files changed, 617 insertions(+), 36 deletions(-)

diff --git a/docs/latex/wx/menu.tex b/docs/latex/wx/menu.tex
index cf8c61dcc8..ebaf7fb1a4 100644
--- a/docs/latex/wx/menu.tex
+++ b/docs/latex/wx/menu.tex
@@ -383,7 +383,15 @@ A menu bar is a series of menus accessible from the top of a frame.
 \wxheading{Event handling}
 
 To respond to a menu selection, provide a handler for EVT\_MENU, in the frame
-that contains the menu bar.
+that contains the menu bar. If you have a toolbar which uses the same identifiers
+as your EVT\_MENU entries, events from the toolbar will also be processed by your
+EVT\_MENU event handlers.
+
+Note that menu commands (and UI update events for menus) are first sent to
+the focus window within the frame. If no window within the frame has the focus,
+then the events are sent directly to the frame. This allows command and UI update
+handling to be processed by specific windows and controls, and not necessarily
+by the application frame.
 
 \wxheading{See also}
 
diff --git a/docs/latex/wx/tevent.tex b/docs/latex/wx/tevent.tex
index 6434617135..9ba0aee018 100644
--- a/docs/latex/wx/tevent.tex
+++ b/docs/latex/wx/tevent.tex
@@ -134,7 +134,9 @@ recursively applied to the parent window's event handler. If this returns TRUE,
 
 Note that your application may wish to override ProcessEvent to redirect processing of
 events. This is done in the document/view framework, for example, to allow event handlers
-to be defined in the document or view.
+to be defined in the document or view. To test for command events (which will probably
+be the only events you wish to redirect), you may use wxEvent::IsCommandEvent for
+efficiency, instead of using the slower run-time type system.
 
 As mentioned above, only command events are recursively applied to the parents event
 handler. As this quite often causes confusion for users, here is a list of system
@@ -164,7 +166,21 @@ In some cases, it might be desired by the programmer to get a certain number
 of system events in a parent window, for example all key events sent to, but not
 used by, the native controls in a dialog. In this case, a special event handler
 will have to be written that will override ProcessEvent() in order to pass
-all events (or any selection of them) to the parent window. See next section.
+all events (or any selection of them) to the parent window.
+
+\subsection{Redirection of command events to the window with the focus}
+
+The usual upward search through the window hierarchy for command event
+handlers does not always meet an application's requirements. Say you have two
+wxTextCtrl windows in a frame, plus a toolbar with Cut, Copy and Paste
+buttons. To avoid the need to define event handlers in the frame
+and redirect them explicitly to the window with the focus, command events
+are sent to the window with the focus first, for
+menu and toolbar command and UI update events only. This means that
+each window can handle its own commands and UI updates independently. In
+fact wxTextCtrl can handle Cut, Copy, Paste, Undo and Redo commands and UI update
+requests, so no extra coding is required to support them in your menus and
+toolbars.
 
 \subsection{Pluggable event handlers}
 
diff --git a/docs/latex/wx/text.tex b/docs/latex/wx/text.tex
index 54395fae08..d15cf7908a 100644
--- a/docs/latex/wx/text.tex
+++ b/docs/latex/wx/text.tex
@@ -52,6 +52,10 @@ wxTextCtrl header file.
 
 \wxheading{Event handling}
 
+The following commands are processed by default event handlers in wxTextCtrl: wxID\_CUT, wxID\_COPY,
+wxID\_PASTE, wxID\_UNDO, wxID\_REDO. The associated UI update events are also processed
+automatically, when the control has the focus.
+
 To process input from a text control, use these event handler macros to direct input to member
 functions that take a \helpref{wxCommandEvent}{wxcommandevent} argument.
 
diff --git a/docs/latex/wx/toolbar.tex b/docs/latex/wx/toolbar.tex
index 07242ae6bf..e2ac776041 100644
--- a/docs/latex/wx/toolbar.tex
+++ b/docs/latex/wx/toolbar.tex
@@ -62,6 +62,13 @@ window is passed and the tool id is retrieved from the wxCommandEvent.
 This is because the id may be -1 when the mouse moves off a tool, and -1 is not
 allowed as an identifier in the event system.
 
+Note that tool commands (and UI update events for tools) are first sent to
+the focus window within the frame that contains the toolbar. If no window within the frame has the focus,
+then the events are sent directly to the toolbar (and up the hierarchy to the
+frame, depending on where the application has put its event handlers). This allows command and UI update
+handling to be processed by specific windows and controls, and not necessarily
+by the application frame.
+
 \twocolwidtha{7cm}
 \begin{twocollist}\itemsep=0pt
 \twocolitem{{\bf EVT\_TOOL(id, func)}}{Process a wxEVT\_COMMAND\_TOOL\_CLICKED event
diff --git a/docs/latex/wx/ttoolbar.tex b/docs/latex/wx/ttoolbar.tex
index 2401877bca..258e4c2416 100644
--- a/docs/latex/wx/ttoolbar.tex
+++ b/docs/latex/wx/ttoolbar.tex
@@ -13,8 +13,7 @@ Instead of supplying one toolbar class with a number
 of different implementations depending on platform, wxWindows separates
 out the classes. This is because there are a number of different toolbar
 styles that you may wish to use simultaneously, and also, future
-toolbar implementations will emerge (for example, using the
-new-style Windows `coolbar' as seen in Microsoft applications) which
+toolbar implementations will emerge which
 cannot all be shoe-horned into the one class.
 
 For each platform, the symbol {\bf wxToolBar} is defined to be one of the
@@ -26,7 +25,7 @@ The following is a summary of the toolbar classes and their differences.
 \item {\bf wxToolBarBase.} This is a base class with pure virtual functions,
 and should not be used directly.
 \item {\bf wxToolBarSimple.} A simple toolbar class written entirely with generic wxWindows
-functionality. A simply 3D effect for buttons is possible, but it is not consistent
+functionality. A simple 3D effect for buttons is possible, but it is not consistent
 with the Windows look and feel. This toolbar can scroll, and you can have arbitrary
 numbers of rows and columns.
 \item {\bf wxToolBarMSW.} This class implements an old-style Windows toolbar, only on
@@ -39,7 +38,8 @@ CreateTools must be called after the tools have been added.
 No absolute positioning is supported but you can specify the number
 of rows, and add tool separators with {\bf AddSeparator}.
 Tooltips are supported. {\bf OnRightClick} is not supported. This is the default wxToolBar
-on Windows 95, Windows NT 4 and above.
+on Windows 95, Windows NT 4 and above. With the style wxTB\_FLAT, the flat toolbar
+look is used, with a border that is highlit when the cursor moves over the buttons.
 \end{itemize}
 
 A toolbar might appear as a single row of images under
@@ -61,8 +61,6 @@ as the demo shows, before adding tools to the button bar. Don't supply more than
 one bitmap for each tool, because the toolbar generates all three images (normal,
 depressed and checked) from the single bitmap you give it.
 
-To intercept
-
 \subsection{Using the toolbar library}
 
 Include {\tt "wx/toolbar.h"}, or if using a class directly, one of:
@@ -74,7 +72,9 @@ Include {\tt "wx/toolbar.h"}, or if using a class directly, one of:
 \end{itemize}
 
 Example of toolbar use are given in the sample program ``toolbar''. The
-source is given below.
+source is given below. In fact it's out of date because recommended
+practise is to use event handlers (using EVT\_MENU or EVT\_TOOL) instead of
+overriding OnLeftClick.
 
 {\small
 \begin{verbatim}
diff --git a/include/wx/event.h b/include/wx/event.h
index 24a0d2b4f1..d06b724aa8 100644
--- a/include/wx/event.h
+++ b/include/wx/event.h
@@ -1427,5 +1427,13 @@ const wxEventTableEntry theClass::sm_eventTableEntries[] = { \
 #define EVT_UPDATE_UI(id, func) \
  { wxEVT_UPDATE_UI, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxUpdateUIEventFunction) & func, (wxObject *) NULL },\
 
+/*
+ * Helper functions
+ */
+
+// Find a window with the focus, that is also a descendant of the given window.
+// This is used to determine the window to initially send commands to.
+wxWindow* wxFindFocusDescendant(wxWindow* ancestor);
+
 #endif
         // _WX_EVENTH__
diff --git a/include/wx/gtk/frame.h b/include/wx/gtk/frame.h
index de86ad8e1a..490d00170f 100644
--- a/include/wx/gtk/frame.h
+++ b/include/wx/gtk/frame.h
@@ -105,7 +105,7 @@ public:
     virtual void GtkOnSize( int x, int y, int width, int height );
     virtual wxPoint GetClientAreaOrigin() const;
     void DoMenuUpdates();
-    void DoMenuUpdates(wxMenu* menu);
+    void DoMenuUpdates(wxMenu* menu, wxWindow* focusWin);
     virtual void OnInternalIdle();
 
     wxMenuBar    *m_frameMenuBar;
diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h
index 2512ce42c1..31946009a3 100644
--- a/include/wx/gtk/textctrl.h
+++ b/include/wx/gtk/textctrl.h
@@ -118,6 +118,18 @@ class wxTextCtrl: public wxControl
 
     void OnChar( wxKeyEvent &event );
 
+    void OnCut(wxCommandEvent& event);
+    void OnCopy(wxCommandEvent& event);
+    void OnPaste(wxCommandEvent& event);
+    void OnUndo(wxCommandEvent& event);
+    void OnRedo(wxCommandEvent& event);
+
+    void OnUpdateCut(wxUpdateUIEvent& event);
+    void OnUpdateCopy(wxUpdateUIEvent& event);
+    void OnUpdatePaste(wxUpdateUIEvent& event);
+    void OnUpdateUndo(wxUpdateUIEvent& event);
+    void OnUpdateRedo(wxUpdateUIEvent& event);
+
 #ifndef NO_TEXT_WINDOW_STREAM
     int overflow(int i);
     int sync();
diff --git a/include/wx/gtk1/frame.h b/include/wx/gtk1/frame.h
index de86ad8e1a..490d00170f 100644
--- a/include/wx/gtk1/frame.h
+++ b/include/wx/gtk1/frame.h
@@ -105,7 +105,7 @@ public:
     virtual void GtkOnSize( int x, int y, int width, int height );
     virtual wxPoint GetClientAreaOrigin() const;
     void DoMenuUpdates();
-    void DoMenuUpdates(wxMenu* menu);
+    void DoMenuUpdates(wxMenu* menu, wxWindow* focusWin);
     virtual void OnInternalIdle();
 
     wxMenuBar    *m_frameMenuBar;
diff --git a/include/wx/gtk1/textctrl.h b/include/wx/gtk1/textctrl.h
index 2512ce42c1..31946009a3 100644
--- a/include/wx/gtk1/textctrl.h
+++ b/include/wx/gtk1/textctrl.h
@@ -118,6 +118,18 @@ class wxTextCtrl: public wxControl
 
     void OnChar( wxKeyEvent &event );
 
+    void OnCut(wxCommandEvent& event);
+    void OnCopy(wxCommandEvent& event);
+    void OnPaste(wxCommandEvent& event);
+    void OnUndo(wxCommandEvent& event);
+    void OnRedo(wxCommandEvent& event);
+
+    void OnUpdateCut(wxUpdateUIEvent& event);
+    void OnUpdateCopy(wxUpdateUIEvent& event);
+    void OnUpdatePaste(wxUpdateUIEvent& event);
+    void OnUpdateUndo(wxUpdateUIEvent& event);
+    void OnUpdateRedo(wxUpdateUIEvent& event);
+
 #ifndef NO_TEXT_WINDOW_STREAM
     int overflow(int i);
     int sync();
diff --git a/include/wx/mac/frame.h b/include/wx/mac/frame.h
index c2b5eb39a8..64ec0d6cd1 100644
--- a/include/wx/mac/frame.h
+++ b/include/wx/mac/frame.h
@@ -136,7 +136,7 @@ public:
 
   // Query app for menu item updates (called from OnIdle)
   void DoMenuUpdates();
-  void DoMenuUpdates(wxMenu* menu);
+  void DoMenuUpdates(wxMenu* menu, wxWindow* focusWin);
 
   // Checks if there is a toolbar, and returns the first free client position
   virtual wxPoint GetClientAreaOrigin() const;
diff --git a/include/wx/motif/frame.h b/include/wx/motif/frame.h
index 4c9372f4d9..28b68bcdb9 100644
--- a/include/wx/motif/frame.h
+++ b/include/wx/motif/frame.h
@@ -145,7 +145,7 @@ public:
 
     // Query app for menu item updates (called from OnIdle)
     void DoMenuUpdates();
-    void DoMenuUpdates(wxMenu* menu);
+    void DoMenuUpdates(wxMenu* menu, wxWindow* focusWin);
 
     // Checks if there is a toolbar, and returns the first free client position
     virtual wxPoint GetClientAreaOrigin() const;
diff --git a/include/wx/motif/textctrl.h b/include/wx/motif/textctrl.h
index 6622976caf..2466ff7376 100644
--- a/include/wx/motif/textctrl.h
+++ b/include/wx/motif/textctrl.h
@@ -16,8 +16,8 @@
     #pragma interface "textctrl.h"
 #endif
 
-#include "wx/ioswrap.h"
 #include "wx/control.h"
+#include "wx/ioswrap.h"
 
 // TODO Some platforms/compilers don't like inheritance from streambuf.
 #if (defined(__BORLANDC__) && !defined(__WIN32__)) || defined(__MWERKS__)
@@ -133,6 +133,18 @@ public:
     void OnChar(wxKeyEvent& event);
     //  void OnEraseBackground(wxEraseEvent& event);
 
+    void OnCut(wxCommandEvent& event);
+    void OnCopy(wxCommandEvent& event);
+    void OnPaste(wxCommandEvent& event);
+    void OnUndo(wxCommandEvent& event);
+    void OnRedo(wxCommandEvent& event);
+
+    void OnUpdateCut(wxUpdateUIEvent& event);
+    void OnUpdateCopy(wxUpdateUIEvent& event);
+    void OnUpdatePaste(wxUpdateUIEvent& event);
+    void OnUpdateUndo(wxUpdateUIEvent& event);
+    void OnUpdateRedo(wxUpdateUIEvent& event);
+
     virtual void Command(wxCommandEvent& event);
 
     // implementation from here to the end
diff --git a/include/wx/msw/frame.h b/include/wx/msw/frame.h
index a0e3ae67fc..51fe39e5ae 100644
--- a/include/wx/msw/frame.h
+++ b/include/wx/msw/frame.h
@@ -153,7 +153,7 @@ public:
 
     // Query app for menu item updates (called from OnIdle)
     void DoMenuUpdates();
-    void DoMenuUpdates(wxMenu* menu);
+    void DoMenuUpdates(wxMenu* menu, wxWindow* focusWin);
 
     WXHMENU GetWinMenu() const ;
 
diff --git a/include/wx/msw/textctrl.h b/include/wx/msw/textctrl.h
index 142ee8ba49..fd5a835584 100644
--- a/include/wx/msw/textctrl.h
+++ b/include/wx/msw/textctrl.h
@@ -154,6 +154,18 @@ public:
     void OnChar(wxKeyEvent& event); // Process 'enter' if required
     void OnEraseBackground(wxEraseEvent& event);
 
+    void OnCut(wxCommandEvent& event);
+    void OnCopy(wxCommandEvent& event);
+    void OnPaste(wxCommandEvent& event);
+    void OnUndo(wxCommandEvent& event);
+    void OnRedo(wxCommandEvent& event);
+
+    void OnUpdateCut(wxUpdateUIEvent& event);
+    void OnUpdateCopy(wxUpdateUIEvent& event);
+    void OnUpdatePaste(wxUpdateUIEvent& event);
+    void OnUpdateUndo(wxUpdateUIEvent& event);
+    void OnUpdateRedo(wxUpdateUIEvent& event);
+
     // Implementation
     // --------------
     virtual void Command(wxCommandEvent& event);
diff --git a/include/wx/stubs/frame.h b/include/wx/stubs/frame.h
index c2b5eb39a8..64ec0d6cd1 100644
--- a/include/wx/stubs/frame.h
+++ b/include/wx/stubs/frame.h
@@ -136,7 +136,7 @@ public:
 
   // Query app for menu item updates (called from OnIdle)
   void DoMenuUpdates();
-  void DoMenuUpdates(wxMenu* menu);
+  void DoMenuUpdates(wxMenu* menu, wxWindow* focusWin);
 
   // Checks if there is a toolbar, and returns the first free client position
   virtual wxPoint GetClientAreaOrigin() const;
diff --git a/include/wx/stubs/textctrl.h b/include/wx/stubs/textctrl.h
index 0834e1a43b..09c11e063e 100644
--- a/include/wx/stubs/textctrl.h
+++ b/include/wx/stubs/textctrl.h
@@ -141,7 +141,18 @@ public:
   void OnDropFiles(wxDropFilesEvent& event);
 //  void OnChar(wxKeyEvent& event); // Process 'enter' if required
 //  void OnEraseBackground(wxEraseEvent& event);
-  
+  void OnCut(wxCommandEvent& event);
+  void OnCopy(wxCommandEvent& event);
+  void OnPaste(wxCommandEvent& event);
+  void OnUndo(wxCommandEvent& event);
+  void OnRedo(wxCommandEvent& event);
+
+  void OnUpdateCut(wxUpdateUIEvent& event);
+  void OnUpdateCopy(wxUpdateUIEvent& event);
+  void OnUpdatePaste(wxUpdateUIEvent& event);
+  void OnUpdateUndo(wxUpdateUIEvent& event);
+  void OnUpdateRedo(wxUpdateUIEvent& event);
+
   // Implementation
   // --------------
   virtual void Command(wxCommandEvent& event);
diff --git a/src/common/event.cpp b/src/common/event.cpp
index 07c9462cff..c64449a3a5 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -555,3 +555,26 @@ bool wxEvtHandler::OnClose()
 }
 #endif // WXWIN_COMPATIBILITY
 
+// Find a window with the focus, that is also a descendant of the given window.
+// This is used to determine the window to initially send commands to.
+wxWindow* wxFindFocusDescendant(wxWindow* ancestor)
+{
+    // Process events starting with the window with the focus, if any.
+    wxWindow* focusWin = wxWindow::FindFocus();
+    wxWindow* win = focusWin;
+
+    // Check if this is a descendant of this frame.
+    // If not, win will be set to NULL.
+    while (win)
+    {
+        if (win == ancestor)
+            break;
+        else
+            win = win->GetParent();
+    }
+    if (win == (wxWindow*) NULL)
+        focusWin = (wxWindow*) NULL;
+
+    return focusWin;
+}
+
diff --git a/src/common/framecmn.cpp b/src/common/framecmn.cpp
index aa326ecdf8..163b00a160 100644
--- a/src/common/framecmn.cpp
+++ b/src/common/framecmn.cpp
@@ -30,16 +30,21 @@ void wxFrame::OnIdle(wxIdleEvent& WXUNUSED(event) )
 void wxFrame::DoMenuUpdates()
 {
   wxMenuBar* bar = GetMenuBar();
+
+  // Process events starting with the window with the focus, if any.
+  wxWindow* focusWin = wxFindFocusDescendant(this);
+
   if ( bar != NULL ) {
     int nCount = bar->GetMenuCount();
     for (int n = 0; n < nCount; n++)
-      DoMenuUpdates(bar->GetMenu(n));
+      DoMenuUpdates(bar->GetMenu(n), focusWin);
   }
 }
 
 // update a menu and all submenus recursively
-void wxFrame::DoMenuUpdates(wxMenu* menu)
+void wxFrame::DoMenuUpdates(wxMenu* menu, wxWindow* focusWin)
 {
+  wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
   wxNode* node = menu->GetItems().First();
   while (node)
   {
@@ -50,7 +55,7 @@ void wxFrame::DoMenuUpdates(wxMenu* menu)
       wxUpdateUIEvent event(id);
       event.SetEventObject( this );
 
-      if (GetEventHandler()->ProcessEvent(event))
+      if (evtHandler->ProcessEvent(event))
       {
         if (event.GetSetText())
           menu->SetLabel(id, event.GetText());
@@ -61,7 +66,7 @@ void wxFrame::DoMenuUpdates(wxMenu* menu)
       }
 
       if (item->GetSubMenu())
-        DoMenuUpdates(item->GetSubMenu());
+        DoMenuUpdates(item->GetSubMenu(), focusWin);
     }
     node = node->Next();
   }
diff --git a/src/common/tbarbase.cpp b/src/common/tbarbase.cpp
index 218ecbea4f..77034f80a4 100644
--- a/src/common/tbarbase.cpp
+++ b/src/common/tbarbase.cpp
@@ -24,6 +24,8 @@
 #include "wx/wx.h"
 #endif
 
+#include "wx/frame.h"
+
 // For ::UpdateWindow
 #ifdef __WXMSW__
 #include <windows.h>
@@ -147,6 +149,29 @@ bool wxToolBarBase::OnLeftClick(int toolIndex, bool toggleDown)
     event.SetEventObject(this);
     event.SetExtraLong((long) toggleDown);
 
+    // First try sending the command to a window that has the focus, within a frame that
+    // also contains this toolbar.
+    wxFrame* frame = (wxFrame*) NULL;
+    wxWindow* win = this;
+    wxWindow* focusWin = (wxWindow*) NULL;
+
+    while (win)
+    {
+        if (win->IsKindOf(CLASSINFO(wxFrame)))
+        {
+            frame = (wxFrame*) win;
+            break;
+        }
+        else
+            win = win->GetParent();
+    }
+    if (frame)
+        focusWin = wxFindFocusDescendant(frame);
+
+    if (focusWin && focusWin->GetEventHandler()->ProcessEvent(event))
+        return TRUE;
+
+    // Send events to this toolbar instead (and thence up the window hierarchy)
     GetEventHandler()->ProcessEvent(event);
 
     return TRUE;
@@ -732,6 +757,28 @@ void wxToolBarBase::OnIdle(wxIdleEvent& event)
 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
 void wxToolBarBase::DoToolbarUpdates()
 {
+    // First try sending the command to a window that has the focus, within a frame that
+    // also contains this toolbar.
+    wxFrame* frame = (wxFrame*) NULL;
+    wxWindow* win = this;
+    wxWindow* focusWin = (wxWindow*) NULL;
+
+    while (win)
+    {
+        if (win->IsKindOf(CLASSINFO(wxFrame)))
+        {
+            frame = (wxFrame*) win;
+            break;
+        }
+        else
+            win = win->GetParent();
+    }
+    if (frame)
+        focusWin = wxFindFocusDescendant(frame);
+
+
+    wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler() ;
+
     wxNode* node = GetTools().First();
     while (node)
     {
@@ -740,7 +787,7 @@ void wxToolBarBase::DoToolbarUpdates()
         wxUpdateUIEvent event(tool->m_index);
         event.SetEventObject(this);
 
-        if (GetEventHandler()->ProcessEvent(event))
+        if (evtHandler->ProcessEvent(event))
         {
             if (event.GetSetEnabled())
                 EnableTool(tool->m_index, event.GetEnabled());
diff --git a/src/gtk.inc b/src/gtk.inc
index 240068c9b5..c6e4cbd1d9 100644
--- a/src/gtk.inc
+++ b/src/gtk.inc
@@ -28,6 +28,7 @@ LIB_CPP_SRC=\
  common/image.cpp \
  common/imagjpeg.cpp \
  common/imagpng.cpp \
+ common/imaggif.cpp \
  common/ipcbase.cpp \
  common/layout.cpp \
  common/list.cpp \
diff --git a/src/gtk/frame.cpp b/src/gtk/frame.cpp
index 84899e1e48..a217593847 100644
--- a/src/gtk/frame.cpp
+++ b/src/gtk/frame.cpp
@@ -654,7 +654,13 @@ void wxFrame::Command( int id )
     {
         bar->Check(id,!bar->Checked(id)) ;
     }
-    GetEventHandler()->ProcessEvent(commandEvent);
+
+    // Process events starting with the window with the focus, if any.
+    wxWindow* focusWin = wxFindFocusDescendant(this);
+
+    wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+
+    evtHandler->ProcessEvent(commandEvent);
 }
 
 void wxFrame::SetStatusText(const wxString& text, int number)
diff --git a/src/gtk/tbargtk.cpp b/src/gtk/tbargtk.cpp
index 78e4e339ac..3523a06f3b 100644
--- a/src/gtk/tbargtk.cpp
+++ b/src/gtk/tbargtk.cpp
@@ -12,6 +12,7 @@
 #endif
 
 #include "wx/toolbar.h"
+#include "wx/frame.h"
 
 #include "glib.h"
 #include "gdk/gdk.h"
@@ -168,6 +169,28 @@ bool wxToolBar::OnLeftClick( int toolIndex, bool toggleDown )
     event.SetInt( toolIndex );
     event.SetExtraLong((long) toggleDown);
 
+    // First try sending the command to a window that has the focus, within a frame that
+    // also contains this toolbar.
+    wxFrame* frame = (wxFrame*) NULL;
+    wxWindow* win = this;
+    wxWindow* focusWin = (wxWindow*) NULL;
+
+    while (win)
+    {
+        if (win->IsKindOf(CLASSINFO(wxFrame)))
+        {
+            frame = (wxFrame*) win;
+            break;
+        }
+        else
+            win = win->GetParent();
+    }
+    if (frame)
+        focusWin = wxFindFocusDescendant(frame);
+
+    if (focusWin && focusWin->GetEventHandler()->ProcessEvent(event))
+        return TRUE;
+
     GetEventHandler()->ProcessEvent(event);
 
     return TRUE;
diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp
index 4da56a23e5..5fd1f455a1 100644
--- a/src/gtk/textctrl.cpp
+++ b/src/gtk/textctrl.cpp
@@ -65,6 +65,18 @@ IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl,wxControl)
 
 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
     EVT_CHAR(wxTextCtrl::OnChar)
+
+    EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
+    EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
+    EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
+    EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
+    EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
+
+    EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
+    EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
+    EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
+    EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
+    EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 
 #ifndef NO_TEXT_WINDOW_STREAM
@@ -931,3 +943,52 @@ void wxTextCtrl::ApplyWidgetStyle()
     }
 }
 
+void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
+{
+    Cut();
+}
+
+void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+    Copy();
+}
+
+void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
+{
+    Paste();
+}
+
+void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
+{
+    Undo();
+}
+
+void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
+{
+    Redo();
+}
+
+void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCut() );
+}
+
+void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCopy() );
+}
+
+void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+    event.Enable( CanPaste() );
+}
+
+void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanUndo() );
+}
+
+void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanRedo() );
+}
diff --git a/src/gtk1/frame.cpp b/src/gtk1/frame.cpp
index 84899e1e48..a217593847 100644
--- a/src/gtk1/frame.cpp
+++ b/src/gtk1/frame.cpp
@@ -654,7 +654,13 @@ void wxFrame::Command( int id )
     {
         bar->Check(id,!bar->Checked(id)) ;
     }
-    GetEventHandler()->ProcessEvent(commandEvent);
+
+    // Process events starting with the window with the focus, if any.
+    wxWindow* focusWin = wxFindFocusDescendant(this);
+
+    wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+
+    evtHandler->ProcessEvent(commandEvent);
 }
 
 void wxFrame::SetStatusText(const wxString& text, int number)
diff --git a/src/gtk1/tbargtk.cpp b/src/gtk1/tbargtk.cpp
index 78e4e339ac..3523a06f3b 100644
--- a/src/gtk1/tbargtk.cpp
+++ b/src/gtk1/tbargtk.cpp
@@ -12,6 +12,7 @@
 #endif
 
 #include "wx/toolbar.h"
+#include "wx/frame.h"
 
 #include "glib.h"
 #include "gdk/gdk.h"
@@ -168,6 +169,28 @@ bool wxToolBar::OnLeftClick( int toolIndex, bool toggleDown )
     event.SetInt( toolIndex );
     event.SetExtraLong((long) toggleDown);
 
+    // First try sending the command to a window that has the focus, within a frame that
+    // also contains this toolbar.
+    wxFrame* frame = (wxFrame*) NULL;
+    wxWindow* win = this;
+    wxWindow* focusWin = (wxWindow*) NULL;
+
+    while (win)
+    {
+        if (win->IsKindOf(CLASSINFO(wxFrame)))
+        {
+            frame = (wxFrame*) win;
+            break;
+        }
+        else
+            win = win->GetParent();
+    }
+    if (frame)
+        focusWin = wxFindFocusDescendant(frame);
+
+    if (focusWin && focusWin->GetEventHandler()->ProcessEvent(event))
+        return TRUE;
+
     GetEventHandler()->ProcessEvent(event);
 
     return TRUE;
diff --git a/src/gtk1/textctrl.cpp b/src/gtk1/textctrl.cpp
index 4da56a23e5..5fd1f455a1 100644
--- a/src/gtk1/textctrl.cpp
+++ b/src/gtk1/textctrl.cpp
@@ -65,6 +65,18 @@ IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl,wxControl)
 
 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
     EVT_CHAR(wxTextCtrl::OnChar)
+
+    EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
+    EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
+    EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
+    EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
+    EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
+
+    EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
+    EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
+    EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
+    EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
+    EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 
 #ifndef NO_TEXT_WINDOW_STREAM
@@ -931,3 +943,52 @@ void wxTextCtrl::ApplyWidgetStyle()
     }
 }
 
+void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
+{
+    Cut();
+}
+
+void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+    Copy();
+}
+
+void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
+{
+    Paste();
+}
+
+void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
+{
+    Undo();
+}
+
+void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
+{
+    Redo();
+}
+
+void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCut() );
+}
+
+void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCopy() );
+}
+
+void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+    event.Enable( CanPaste() );
+}
+
+void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanUndo() );
+}
+
+void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanRedo() );
+}
diff --git a/src/mac/carbon/frame.cpp b/src/mac/carbon/frame.cpp
index b370f7b108..55f1e3b72c 100644
--- a/src/mac/carbon/frame.cpp
+++ b/src/mac/carbon/frame.cpp
@@ -450,7 +450,12 @@ void wxFrame::ProcessCommand(int id)
   }
 */
 
-  GetEventHandler()->ProcessEvent(commandEvent);
+  // Process events starting with the window with the focus, if any.
+  wxWindow* focusWin = wxFindFocusDescendant(this);
+
+  wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+
+  evtHandler->ProcessEvent(commandEvent);
 }
 
 // Checks if there is a toolbar, and returns the first free client position
diff --git a/src/mac/frame.cpp b/src/mac/frame.cpp
index b370f7b108..55f1e3b72c 100644
--- a/src/mac/frame.cpp
+++ b/src/mac/frame.cpp
@@ -450,7 +450,12 @@ void wxFrame::ProcessCommand(int id)
   }
 */
 
-  GetEventHandler()->ProcessEvent(commandEvent);
+  // Process events starting with the window with the focus, if any.
+  wxWindow* focusWin = wxFindFocusDescendant(this);
+
+  wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+
+  evtHandler->ProcessEvent(commandEvent);
 }
 
 // Checks if there is a toolbar, and returns the first free client position
diff --git a/src/motif.inc b/src/motif.inc
index 56b9f3e56f..0d26fbe0d8 100644
--- a/src/motif.inc
+++ b/src/motif.inc
@@ -27,6 +27,7 @@ LIB_CPP_SRC=\
  common/image.cpp \
  common/imagjpeg.cpp \
  common/imagpng.cpp \
+ common/imaggif.cpp \
  common/intl.cpp \
  common/ipcbase.cpp \
  common/layout.cpp \
diff --git a/src/motif/frame.cpp b/src/motif/frame.cpp
index 264204fb1b..2e3f2f78a1 100644
--- a/src/motif/frame.cpp
+++ b/src/motif/frame.cpp
@@ -869,7 +869,12 @@ void wxFrame::ProcessCommand(int id)
   }
 */
 
-  GetEventHandler()->ProcessEvent(commandEvent);
+  // Process events starting with the window with the focus, if any.
+  wxWindow* focusWin = wxFindFocusDescendant(this);
+
+  wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+
+  evtHandler->ProcessEvent(commandEvent);
 }
 
 // Checks if there is a toolbar, and returns the first free client position
diff --git a/src/motif/makefile.unx b/src/motif/makefile.unx
index e8c8ab7532..182f91062c 100644
--- a/src/motif/makefile.unx
+++ b/src/motif/makefile.unx
@@ -33,6 +33,7 @@ LIB_CPP_SRC=\
  ../common/image.cpp \
  ../common/imagjpeg.cpp \
  ../common/imagpng.cpp \
+ ../common/imaggif.cpp \
  ../common/layout.cpp \
  ../common/list.cpp \
  ../common/log.cpp \
diff --git a/src/motif/textctrl.cpp b/src/motif/textctrl.cpp
index a9ae3f9b0a..d697c83662 100644
--- a/src/motif/textctrl.cpp
+++ b/src/motif/textctrl.cpp
@@ -57,6 +57,19 @@ static void wxTextWindowActivateProc(Widget w, XtPointer clientData, XmAnyCallba
     BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
         EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
         EVT_CHAR(wxTextCtrl::OnChar)
+
+    EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
+    EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
+    EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
+    EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
+    EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
+
+    EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
+    EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
+    EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
+    EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
+    EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
+
     END_EVENT_TABLE()
 #endif
 
@@ -995,3 +1008,52 @@ static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
     tw->ProcessCommand(event);
 }
 
+void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
+{
+    Cut();
+}
+
+void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+    Copy();
+}
+
+void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
+{
+    Paste();
+}
+
+void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
+{
+    Undo();
+}
+
+void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
+{
+    Redo();
+}
+
+void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCut() );
+}
+
+void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCopy() );
+}
+
+void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+    event.Enable( CanPaste() );
+}
+
+void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanUndo() );
+}
+
+void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanRedo() );
+}
diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp
index 0099a31787..4cfcc231d6 100644
--- a/src/msw/frame.cpp
+++ b/src/msw/frame.cpp
@@ -916,7 +916,12 @@ void wxFrame::ProcessCommand(int id)
   {
     bar->Check(id,!bar->Checked(id)) ;
   }
-  GetEventHandler()->ProcessEvent(commandEvent);
+
+  // Process events starting with the window with the focus, if any.
+  wxWindow* focusWin = wxFindFocusDescendant(this);
+
+  wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+  evtHandler->ProcessEvent(commandEvent);
 }
 
 // Checks if there is a toolbar, and returns the first free client position
diff --git a/src/msw/makefile.vc b/src/msw/makefile.vc
index 1f2ccebc1b..1d685d6314 100644
--- a/src/msw/makefile.vc
+++ b/src/msw/makefile.vc
@@ -114,6 +114,7 @@ COMMONOBJS = \
   ..\common\$D\image.obj \
   ..\common\$D\imagjpeg.obj \
   ..\common\$D\imagpng.obj \
+  ..\common\$D\imaggif.obj \
   ..\common\$D\intl.obj \
   ..\common\$D\ipcbase.obj \
   ..\common\$D\helpbase.obj \
diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp
index 2642a90de4..630fc27176 100644
--- a/src/msw/textctrl.cpp
+++ b/src/msw/textctrl.cpp
@@ -68,13 +68,27 @@
 #endif
 
 #if !USE_SHARED_LIBRARY
+
 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
 
 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
   EVT_CHAR(wxTextCtrl::OnChar)
   EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
   EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground)
+
+  EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
+  EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
+  EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
+  EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
+  EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
+
+  EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
+  EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
+  EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
+  EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
+  EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
+
 #endif // USE_SHARED_LIBRARY
 
 // Text item
@@ -363,20 +377,29 @@ void wxTextCtrl::DoSetSize(int x, int y, int width, int height, int sizeFlags)
 // Clipboard operations
 void wxTextCtrl::Copy()
 {
-  HWND hWnd = (HWND) GetHWND();
-  SendMessage(hWnd, WM_COPY, 0, 0L);
+    if (CanCopy())
+    {
+        HWND hWnd = (HWND) GetHWND();
+        SendMessage(hWnd, WM_COPY, 0, 0L);
+    }
 }
 
 void wxTextCtrl::Cut()
 {
-  HWND hWnd = (HWND) GetHWND();
-  SendMessage(hWnd, WM_CUT, 0, 0L);
+    if (CanCut())
+    {
+        HWND hWnd = (HWND) GetHWND();
+        SendMessage(hWnd, WM_CUT, 0, 0L);
+    }
 }
 
 void wxTextCtrl::Paste()
 {
-  HWND hWnd = (HWND) GetHWND();
-  SendMessage(hWnd, WM_PASTE, 0, 0L);
+    if (CanPaste())
+    {
+        HWND hWnd = (HWND) GetHWND();
+        SendMessage(hWnd, WM_PASTE, 0, 0L);
+    }
 }
 
 void wxTextCtrl::SetEditable(bool editable)
@@ -1235,3 +1258,53 @@ bool wxTextCtrl::MSWNotify(WXWPARAM wParam, WXLPARAM lParam)
 #endif
 #endif
 
+void wxTextCtrl::OnCut(wxCommandEvent& event)
+{
+    Cut();
+}
+
+void wxTextCtrl::OnCopy(wxCommandEvent& event)
+{
+    Copy();
+}
+
+void wxTextCtrl::OnPaste(wxCommandEvent& event)
+{
+    Paste();
+}
+
+void wxTextCtrl::OnUndo(wxCommandEvent& event)
+{
+    Undo();
+}
+
+void wxTextCtrl::OnRedo(wxCommandEvent& event)
+{
+    Redo();
+}
+
+void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCut() );
+}
+
+void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCopy() );
+}
+
+void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+    event.Enable( CanPaste() );
+}
+
+void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanUndo() );
+}
+
+void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanRedo() );
+}
+
diff --git a/src/stubs/frame.cpp b/src/stubs/frame.cpp
index c0b6d6b932..48ff977bda 100644
--- a/src/stubs/frame.cpp
+++ b/src/stubs/frame.cpp
@@ -451,7 +451,12 @@ void wxFrame::ProcessCommand(int id)
   }
 */
 
-  GetEventHandler()->ProcessEvent(commandEvent);
+  // Process events starting with the window with the focus, if any.
+  wxWindow* focusWin = wxFindFocusDescendant(this);
+
+  wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
+
+  evtHandler->ProcessEvent(commandEvent);
 }
 
 // Checks if there is a toolbar, and returns the first free client position
diff --git a/src/stubs/textctrl.cpp b/src/stubs/textctrl.cpp
index a43a38acc9..720e6082be 100644
--- a/src/stubs/textctrl.cpp
+++ b/src/stubs/textctrl.cpp
@@ -35,6 +35,17 @@ IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
 
 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
 	EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
+    EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
+    EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
+    EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
+    EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
+    EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
+
+    EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
+    EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
+    EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
+    EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
+    EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 #endif
 
@@ -496,3 +507,52 @@ wxTextCtrl& wxTextCtrl::operator<<(const char c)
     return *this;
 }
 
+void wxTextCtrl::OnCut(wxCommandEvent& event)
+{
+    Cut();
+}
+
+void wxTextCtrl::OnCopy(wxCommandEvent& event)
+{
+    Copy();
+}
+
+void wxTextCtrl::OnPaste(wxCommandEvent& event)
+{
+    Paste();
+}
+
+void wxTextCtrl::OnUndo(wxCommandEvent& event)
+{
+    Undo();
+}
+
+void wxTextCtrl::OnRedo(wxCommandEvent& event)
+{
+    Redo();
+}
+
+void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCut() );
+}
+
+void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
+{
+    event.Enable( CanCopy() );
+}
+
+void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
+{
+    event.Enable( CanPaste() );
+}
+
+void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanUndo() );
+}
+
+void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
+{
+    event.Enable( CanRedo() );
+}
-- 
2.50.0

