]> git.saurik.com Git - wxWidgets.git/commitdiff
Implemented wxEventLoop for wxMotif, and used it in wxDialog::ShowModal,
authorMattia Barbon <mbarbon@cpan.org>
Sun, 2 Feb 2003 15:48:50 +0000 (15:48 +0000)
committerMattia Barbon <mbarbon@cpan.org>
Sun, 2 Feb 2003 15:48:50 +0000 (15:48 +0000)
wxWindow::DoPopupMenu and for the application main loop.
  Implemented wxWakeUpIdle.
  Fixed crash when a popup menu entry is used to close/destroy the parent
window of the menu.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@19078 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

12 files changed:
distrib/msw/tmake/filelist.txt
include/wx/motif/app.h
include/wx/motif/dialog.h
include/wx/motif/menu.h
include/wx/motif/private.h
src/motif/app.cpp
src/motif/dialog.cpp
src/motif/evtloop.cpp [new file with mode: 0644]
src/motif/files.lst
src/motif/menu.cpp
src/motif/menuitem.cpp
src/motif/window.cpp

index a5510edd27ed3b4d3769e95cbd92ebe67c5ce085..bab1a3ae7ecaaba3726015ffda1f304ddf48bef1 100644 (file)
@@ -584,6 +584,7 @@ dcclient.cpp        Motif
 dcmemory.cpp   Motif
 dcscreen.cpp   Motif
 dialog.cpp     Motif
+evtloop.cpp    Motif
 filedlg.cpp    Motif
 font.cpp       Motif
 frame.cpp      Motif
index 650736e9c3ce7e6d9664650f441f58aae54b3d6e..b8e43947c4cf631ce095ea077b88c3f87c93586c 100644 (file)
@@ -20,7 +20,6 @@
 // headers
 // ----------------------------------------------------------------------------
 
-#include "wx/gdicmn.h"
 #include "wx/event.h"
 
 // ----------------------------------------------------------------------------
@@ -32,6 +31,7 @@ class WXDLLEXPORT wxWindow;
 class WXDLLEXPORT wxApp;
 class WXDLLEXPORT wxKeyEvent;
 class WXDLLEXPORT wxLog;
+class WXDLLEXPORT wxEventLoop;
 
 // ----------------------------------------------------------------------------
 // the wxApp class for Motif - see wxAppBase for more details
@@ -43,7 +43,7 @@ class WXDLLEXPORT wxApp : public wxAppBase
         
 public:
     wxApp();
-    ~wxApp() {}
+    virtual ~wxApp();
     
     // override base class (pure) virtuals
     // -----------------------------------
@@ -71,20 +71,6 @@ public:
     // Returns TRUE if more idle time is requested.
     bool SendIdleEvents(wxWindow* win);
     
-    // Motif implementation.
-    
-    // Processes an X event.
-    virtual void ProcessXEvent(WXEvent* event);
-    
-    // Returns TRUE if an accelerator has been processed
-    virtual bool CheckForAccelerator(WXEvent* event);
-    
-    // Returns TRUE if a key down event has been processed
-    virtual bool CheckForKeyDown(WXEvent* event);
-    
-    // Returns TRUE if a key up event has been processed
-    virtual bool CheckForKeyUp(WXEvent* event);
-    
 protected:
     bool                  m_showOnInit;
     
@@ -105,12 +91,11 @@ public:
     // This handler is called when a property change event occurs
     virtual void   HandlePropertyChange(WXEvent *event);
     
-public:
+private:
     static long    sm_lastMessageTime;
     int            m_nCmdShow;
-    
-protected:
-    bool                  m_keepGoing;
+
+    wxEventLoop*    m_eventLoop;
     
     // Motif-specific
     WXAppContext          m_appContext;
index c8d36d63faaa5b41ae00ca39b713135eb07a7135..0e3b7980f624ee2b702ba4ea5dfb1cba96be3372 100644 (file)
@@ -18,6 +18,8 @@
 
 WXDLLEXPORT_DATA(extern const char*) wxDialogNameStr;
 
+class WXDLLEXPORT wxEventLoop;
+
 // Dialog boxes
 class WXDLLEXPORT wxDialog : public wxDialogBase
 {
@@ -102,6 +104,7 @@ private:
 
     //// Motif-specific
     bool          m_modalShowing;
+    wxEventLoop*  m_eventLoop;
 
 protected:
     virtual void DoSetSize(int x, int y,
index 50af6f378102d70aa6f2aba1252ea4afde5f83f1..fb1b8d870984b66afae149b5f0b6d5f1bcb96ccb 100644 (file)
@@ -93,7 +93,8 @@ public:
     WXWidget GetHandle() const { return m_menuWidget; }
     
     bool IsTearOff() const { return (m_style & wxMENU_TEAROFF) != 0; }
-    
+
+    void DestroyWidgetAndDetach();
 public:
     // Motif-specific data
     int               m_numColumns;
index ec1f7efa653a6cac594fb8ede8486cde7a459cfe..5d1f132aad1ea74bd712a54c1011260842b6e8fb 100644 (file)
 // ----------------------------------------------------------------------------
 
 // All widgets should have this as their resize proc.
-extern void wxWidgetResizeProc(Widget w, XConfigureEvent *event, String args[], int *num_args);
+extern void wxWidgetResizeProc(Widget w, XConfigureEvent *event, 
+                               String args[], int *num_args);
 
 // For repainting arbitrary windows
-void wxUniversalRepaintProc(Widget w, XtPointer WXUNUSED(c_data), XEvent *event, char *);
+void wxUniversalRepaintProc(Widget w, XtPointer WXUNUSED(c_data), 
+                            XEvent *event, char *);
 
 // ----------------------------------------------------------------------------
 // we maintain a hash table which contains the mapping from Widget to wxWindow
@@ -51,11 +53,17 @@ extern XmString wxFindAcceleratorText (const char *s);
 // ----------------------------------------------------------------------------
 // TranslateXXXEvent() functions - translate Motif event to wxWindow one
 // ----------------------------------------------------------------------------
-extern bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Widget widget, XEvent *xevent);
-extern bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win, Widget widget, XEvent *xevent);
 
-extern void wxDoChangeForegroundColour(WXWidget widget, wxColour& foregroundColour);
-extern void wxDoChangeBackgroundColour(WXWidget widget, wxColour& backgroundColour, bool changeArmColour = FALSE);
+extern bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win,
+                                  Widget widget, XEvent *xevent);
+extern bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win,
+                                Widget widget, XEvent *xevent);
+
+extern void wxDoChangeForegroundColour(WXWidget widget,
+                                       wxColour& foregroundColour);
+extern void wxDoChangeBackgroundColour(WXWidget widget,
+                                       wxColour& backgroundColour,
+                                       bool changeArmColour = FALSE);
 
 #define wxNO_COLORS   0x00
 #define wxBACK_COLORS 0x01
@@ -78,6 +86,11 @@ extern XColor itemColors[5] ;
 class wxXmString
 {
 public:
+    wxXmString(const char* str)
+    {
+        m_string = XmStringCreateLtoR((char *)str, XmSTRING_DEFAULT_CHARSET);
+    }
+
     wxXmString(const wxString& str)
     {
         m_string = XmStringCreateLtoR((char *)str.c_str(),
@@ -94,6 +107,15 @@ private:
     XmString m_string;
 };
 
+// ----------------------------------------------------------------------------
+// executes one main loop iteration (implemented in src/motif/evtloop.cpp)
+// ----------------------------------------------------------------------------
+
+class wxEventLoop;
+
+// returns true if the loop should be exited
+bool wxDoEventLoopIteration( wxEventLoop& evtLoop );
+
 // ----------------------------------------------------------------------------
 // macros to avoid casting WXFOO to Foo all the time
 // ----------------------------------------------------------------------------
index 3cfc2853e2fe932f9e103cdd76fceac10b79e5bf..330ba91007c4832e081619f1eb5a84c50e43bd55 100644 (file)
@@ -35,6 +35,7 @@
 #include "wx/memory.h"
 #include "wx/log.h"
 #include "wx/intl.h"
+#include "wx/evtloop.h"
 
 #if wxUSE_THREADS
     #include "wx/thread.h"
@@ -61,6 +62,7 @@
 #include <string.h>
 
 extern wxList wxPendingDelete;
+extern bool wxAddIdleCallback();
 
 wxApp *wxTheApp = NULL;
 
@@ -267,6 +269,7 @@ wxApp::wxApp()
     argc = 0;
     argv = NULL;
 
+    m_eventLoop = new wxEventLoop;
     m_mainColormap = (WXColormap) NULL;
     m_appContext = (WXAppContext) NULL;
     m_topLevelWidget = (WXWidget) NULL;
@@ -274,6 +277,11 @@ wxApp::wxApp()
     m_initialDisplay = (WXDisplay*) 0;
 }
 
+wxApp::~wxApp()
+{
+    delete m_eventLoop;
+}
+
 bool wxApp::Initialized()
 {
     if (GetTopWindow())
@@ -284,8 +292,6 @@ bool wxApp::Initialized()
 
 int wxApp::MainLoop()
 {
-    m_keepGoing = TRUE;
-
     /*
     * Sit around forever waiting to process X-events. Property Change
     * event are handled special, because they have to refer to
@@ -297,129 +303,23 @@ int wxApp::MainLoop()
         XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())),
         PropertyChangeMask);
 
-    XEvent event;
-
-    // Use this flag to allow breaking the loop via wxApp::ExitMainLoop()
-    while (m_keepGoing)
-    {
-        XtAppNextEvent( (XtAppContext) wxTheApp->GetAppContext(), &event);
-
-        ProcessXEvent((WXEvent*) & event);
-
-        if (XtAppPending( (XtAppContext) wxTheApp->GetAppContext() ) == 0)
-        {
-            if (!ProcessIdle())
-            {
-#if wxUSE_THREADS
-                // leave the main loop to give other threads a chance to
-                // perform their GUI work
-                wxMutexGuiLeave();
-                wxUsleep(20);
-                wxMutexGuiEnter();
-#endif
-            }
-        }
-
-    }
+    m_eventLoop->Run();
 
     return 0;
 }
 
-// Processes an X event.
-void wxApp::ProcessXEvent(WXEvent* _event)
-{
-    XEvent* event = (XEvent*) _event;
-
-    if (event->type == KeyPress)
-    {
-#if 0 // def __WXDEBUG__
-        Widget widget = XtWindowToWidget(event->xany.display, event->xany.window);
-        wxLogDebug("Got key press event for 0x%08x (parent = 0x%08x)",
-                   widget, XtParent(widget));
-#endif // DEBUG
-
-    if (CheckForAccelerator(_event))
-    {
-            // Do nothing! We intercepted and processed the event as an
-            // accelerator.
-            return;
-    }
-#if 1
-        // It seemed before that this hack was redundant and
-        // key down events were being generated by wxCanvasInputEvent.
-        // But no longer - why ???
-        //
-    else if (CheckForKeyDown(_event))
-    {
-            // We intercepted and processed the key down event
-            return;
-    }
-#endif
-    else
-    {
-            XtDispatchEvent(event);
-        return;
-    }
-    }
-    else if (event->type == KeyRelease)
-    {
-        // TODO: work out why we still need this !  -michael
-        //
-        if (CheckForKeyUp(_event))
-    {
-        // We intercepted and processed the key up event
-        return;
-    }
-    else
-    {
-        XtDispatchEvent(event);
-        return;
-    }
-    }
-    else if (event->type == PropertyNotify)
-    {
-        HandlePropertyChange(_event);
-        return;
-    }
-    else if (event->type == ResizeRequest)
-    {
-        /* Terry Gitnick <terryg@scientech.com> - 1/21/98
-         * If resize event, don't resize until the last resize event for this
-         * window is recieved. Prevents flicker as windows are resized.
-         */
-
-        Display *disp = XtDisplay((Widget) wxTheApp->GetTopLevelWidget());
-        Window win = event->xany.window;
-        XEvent report;
-
-        //  to avoid flicker
-        report = * event;
-        while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
-
-        // TODO: when implementing refresh optimization, we can use
-        // XtAddExposureToRegion to expand the window's paint region.
-
-        XtDispatchEvent(event);
-    }
-    else
-    {
-        XtDispatchEvent(event);
-    }
-}
-
+// Processes an idle event.
 // Returns TRUE if more time is needed.
 bool wxApp::ProcessIdle()
 {
     wxIdleEvent event;
-    event.SetEventObject(this);
-    ProcessEvent(event);
 
-    return event.MoreRequested();
+    return ProcessEvent(event) && event.MoreRequested();
 }
 
 void wxApp::ExitMainLoop()
 {
-    m_keepGoing = FALSE;
+    m_eventLoop->Exit();
 }
 
 // Is a message/event pending?
@@ -435,11 +335,7 @@ bool wxApp::Pending()
 // Dispatch a message.
 void wxApp::Dispatch()
 {
-    //    XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll);
-
-    XEvent event;
-    XtAppNextEvent((XtAppContext) GetAppContext(), &event);
-    ProcessXEvent((WXEvent*) & event);
+    m_eventLoop->Dispatch();
 }
 
 // This should be redefined in a derived class for
@@ -489,13 +385,6 @@ void wxApp::OnIdle(wxIdleEvent& event)
     inOnIdle = FALSE;
 }
 
-void wxWakeUpIdle()
-{
-    // **** please implement me! ****
-    // Wake up the idle handler processor, even if it is in another thread...
-}
-
-
 // Send idle event to all top-level windows
 bool wxApp::SendIdleEvents()
 {
@@ -539,7 +428,7 @@ bool wxApp::SendIdleEvents(wxWindow* win)
 
 void wxApp::DeletePendingObjects()
 {
-    wxNode *node = wxPendingDelete.GetFirst();
+    wxList::Node *node = wxPendingDelete.GetFirst();
     while (node)
     {
         wxObject *obj = node->GetData();
@@ -610,6 +499,8 @@ bool wxApp::OnInitGui()
     GetMainColormap(dpy);
     m_maxRequestSize = XMaxRequestSize((Display*) dpy);
 
+    wxAddIdleCallback();
+
     return TRUE;
 }
 
@@ -629,91 +520,6 @@ WXColormap wxApp::GetMainColormap(WXDisplay* display)
     return (WXColormap) c;
 }
 
-// Returns TRUE if an accelerator has been processed
-bool wxApp::CheckForAccelerator(WXEvent* event)
-{
-    XEvent* xEvent = (XEvent*) event;
-    if (xEvent->xany.type == KeyPress)
-    {
-        // Find a wxWindow for this window
-        // TODO: should get display for the window, not the current display
-        Widget widget = XtWindowToWidget((Display*) wxGetDisplay(), xEvent->xany.window);
-        wxWindow* win = NULL;
-
-        // Find the first wxWindow that corresponds to this event window
-        while (widget && !(win = wxGetWindowFromTable(widget)))
-            widget = XtParent(widget);
-
-        if (!widget || !win)
-            return FALSE;
-
-        wxKeyEvent keyEvent(wxEVT_CHAR);
-        wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent);
-
-        // Now we have a wxKeyEvent and we have a wxWindow.
-        // Go up the hierarchy until we find a matching accelerator,
-        // or we get to the top.
-        while (win)
-        {
-            if (win->ProcessAccelerator(keyEvent))
-                return TRUE;
-            win = win->GetParent();
-        }
-        return FALSE;
-    }
-    return FALSE;
-}
-
-bool wxApp::CheckForKeyDown(WXEvent* event)
-{
-    XEvent* xEvent = (XEvent*) event;
-    if (xEvent->xany.type == KeyPress)
-    {
-        Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
-                     xEvent->xany.window);
-    wxWindow* win = NULL;
-
-    // Find the first wxWindow that corresponds to this event window
-    while (widget && !(win = wxGetWindowFromTable(widget)))
-            widget = XtParent(widget);
-
-    if (!widget || !win)
-            return FALSE;
-
-    wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
-    wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent);
-
-    return win->ProcessEvent( keyEvent );
-    }
-
-    return FALSE;
-}
-
-bool wxApp::CheckForKeyUp(WXEvent* event)
-{
-    XEvent* xEvent = (XEvent*) event;
-    if (xEvent->xany.type == KeyRelease)
-    {
-        Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
-                         xEvent->xany.window);
-        wxWindow* win = NULL;
-
-        // Find the first wxWindow that corresponds to this event window
-        while (widget && !(win = wxGetWindowFromTable(widget)))
-                widget = XtParent(widget);
-
-        if (!widget || !win)
-                return FALSE;
-
-        wxKeyEvent keyEvent(wxEVT_KEY_UP);
-        wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent);
-
-        return win->ProcessEvent( keyEvent );
-    }
-
-    return FALSE;
-}
-
 void wxExit()
 {
     int retValue = 0;
index 5fdd39cb9fdfe59a43528735d581ce51d7e1654a..1e3191c27e8d037a2d3173f6609c0c143e433037 100644 (file)
@@ -24,6 +24,7 @@
 #include "wx/utils.h"
 #include "wx/app.h"
 #include "wx/settings.h"
+#include "wx/evtloop.h"
 
 #ifdef __VMS__
 #pragma message disable nosimpint
@@ -56,7 +57,7 @@
 // A stack of modal_showing flags, since we can't rely
 // on accessing wxDialog::m_modalShowing within
 // wxDialog::Show in case a callback has deleted the wxDialog.
-static wxList wxModalShowingStack;
+// static wxList wxModalShowingStack;
 
 // Lists to keep track of windows, so we can disable/enable them
 // for modal dialogs
@@ -81,6 +82,7 @@ END_EVENT_TABLE()
 wxDialog::wxDialog()
 {
     m_modalShowing = FALSE;
+    m_eventLoop = NULL;
     m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
 }
 
@@ -98,6 +100,7 @@ bool wxDialog::Create(wxWindow *parent, wxWindowID id,
         return FALSE;
 
     m_modalShowing = FALSE;
+    m_eventLoop = NULL;
 
     m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
     m_foregroundColour = *wxBLACK;
@@ -204,6 +207,7 @@ void wxDialog::SetModal(bool flag)
 wxDialog::~wxDialog()
 {
     m_isBeingDeleted = TRUE;
+    delete m_eventLoop;
 
     if (m_mainWidget)
     {
@@ -312,52 +316,24 @@ int wxDialog::ShowModal()
 
     if (m_modalShowing)
         return 0;
-
-    wxModalShowingStack.Insert((wxObject *)TRUE);
+    m_eventLoop = new wxEventLoop;
 
     m_modalShowing = TRUE;
     XtAddGrab((Widget) m_mainWidget, TRUE, FALSE);
 
-    XEvent event;
-
-    // Loop until we signal that the dialog should be closed
-    while ((wxModalShowingStack.Number() > 0) && ((int)(wxModalShowingStack.First()->Data()) != 0))
-    {
-        //        XtAppProcessEvent((XtAppContext) wxTheApp->GetAppContext(), XtIMAll);
-
-        XtAppNextEvent((XtAppContext) wxTheApp->GetAppContext(), &event);
-        wxTheApp->ProcessXEvent((WXEvent*) &event);
-
-        if (XtAppPending( (XtAppContext) wxTheApp->GetAppContext() ) == 0)
-        {
-            if (!wxTheApp->ProcessIdle())
-            {
-#if wxUSE_THREADS
-                // leave the main loop to give other threads a chance to
-                // perform their GUI work
-                wxMutexGuiLeave();
-                wxUsleep(20);
-                wxMutexGuiEnter();
-#endif
-            }
-        }
-    }
-
-    // Remove modal dialog flag from stack
-    wxNode *node = wxModalShowingStack.First();
-    if (node)
-        delete node;
+    m_eventLoop->Run();
 
     // Now process all events in case they get sent to a destroyed dialog
     XSync(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()), FALSE);
-    while (XtAppPending((XtAppContext) wxTheApp->GetAppContext()))
+    while (m_eventLoop->Pending())
     {
         XFlush(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()));
-        XtAppNextEvent((XtAppContext) wxTheApp->GetAppContext(), &event);
-
-        wxTheApp->ProcessXEvent((WXEvent*) &event);
+        m_eventLoop->Dispatch();
     }
 
+    delete m_eventLoop;
+    m_eventLoop = NULL;
+
     // TODO: is it safe to call this, if the dialog may have been deleted
     // by now? Probably only if we're using delayed deletion of dialogs.
     return GetReturnCode();
@@ -376,10 +352,7 @@ void wxDialog::EndModal(int retCode)
     Show(FALSE);
 
     m_modalShowing = FALSE;
-
-    wxNode *node = wxModalShowingStack.First();
-    if (node)
-        node->SetData((wxObject *)FALSE);
+    m_eventLoop->Exit();
 }
 
 // Standard buttons
diff --git a/src/motif/evtloop.cpp b/src/motif/evtloop.cpp
new file mode 100644 (file)
index 0000000..57a3283
--- /dev/null
@@ -0,0 +1,467 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        motif/evtloop.cpp
+// Purpose:     implements wxEventLoop for Motif
+// Author:      Mattia Barbon
+// Modified by:
+// Created:     01.11.02
+// RCS-ID:      $Id$
+// Copyright:   (c) 2002 Mattia Barbon
+// License:     wxWindows license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+    #pragma implementation "evtloop.h"
+#endif
+
+#ifdef __VMS
+#define XtParent XTPARENT
+#define XtDisplay XTDISPLAY
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifndef WX_PRECOMP
+#endif //WX_PRECOMP
+
+#include "wx/evtloop.h"
+#include "wx/event.h"
+#include "wx/app.h"
+
+#ifdef __VMS__
+#pragma message disable nosimpint
+#endif
+#include <Xm/Xm.h>
+#include <X11/Xlib.h>
+#ifdef __VMS__
+#pragma message enable nosimpint
+#endif
+
+#include "wx/motif/private.h"
+
+static bool CheckForKeyUp(XEvent* event);
+static bool CheckForKeyDown(XEvent* event);
+static bool CheckForAccelerator(XEvent* event);
+static void ProcessXEvent(XEvent* event);
+static void wxBreakDispatch();
+
+// ----------------------------------------------------------------------------
+// wxEventLoopImpl
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxEventLoopImpl
+{
+public:
+    // ctor
+    wxEventLoopImpl() { SetExitCode(0); }
+
+    // set/get the exit code
+    void SetExitCode(int exitcode) { m_exitcode = exitcode; }
+    int GetExitCode() const { return m_exitcode; }
+
+    bool SendIdleMessage();
+    bool GetKeepGoing() const { return m_keepGoing; }
+    void SetKeepGoing(bool keepGoing) { m_keepGoing = keepGoing; }
+private:
+    // the exit code of the event loop
+    int  m_exitcode;
+    bool m_keepGoing;
+};
+
+// ----------------------------------------------------------------------------
+// wxEventLoopImpl idle event processing
+// ----------------------------------------------------------------------------
+
+static bool SendIdleMessage()
+{
+    wxIdleEvent event;
+
+    return wxTheApp->ProcessEvent(event) && event.MoreRequested();
+}
+
+bool wxEventLoopImpl::SendIdleMessage()
+{
+    return ::SendIdleMessage();
+}
+
+// ============================================================================
+// wxEventLoop implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxEventLoop running and exiting
+// ----------------------------------------------------------------------------
+
+wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
+
+wxEventLoop::~wxEventLoop()
+{
+    wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
+}
+
+bool wxEventLoop::IsRunning() const
+{
+    return m_impl != NULL;
+}
+
+int wxEventLoop::Run()
+{
+    // event loops are not recursive, you need to create another loop!
+    wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
+
+    wxEventLoop *oldLoop = ms_activeLoop;
+    ms_activeLoop = this;
+
+    m_impl = new wxEventLoopImpl;
+    m_impl->SetKeepGoing( true );
+
+    for( ;; )
+    {
+        if( !wxDoEventLoopIteration( *this ) )
+            break;
+    }
+
+    int exitcode = m_impl->GetExitCode();
+    delete m_impl;
+    m_impl = NULL;
+
+    ms_activeLoop = oldLoop;
+
+    return exitcode;
+}
+
+void wxEventLoop::Exit(int rc)
+{
+    wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
+
+    m_impl->SetExitCode(rc);
+    m_impl->SetKeepGoing( false );
+
+    ::wxBreakDispatch();
+}
+
+// ----------------------------------------------------------------------------
+// wxEventLoop message processing dispatching
+// ----------------------------------------------------------------------------
+
+bool wxEventLoop::Pending() const
+{
+    return XtAppPending( (XtAppContext)wxTheApp->GetAppContext() ) != 0;
+}
+
+bool wxEventLoop::Dispatch()
+{
+    XEvent event;
+    XtAppContext context = (XtAppContext)wxTheApp->GetAppContext();
+
+    if( XtAppPeekEvent( context, &event ) != 0 )
+    {
+        XtAppNextEvent( context, &event );
+        ProcessXEvent( &event );
+    }
+    else
+        XtAppProcessEvent( context, XtIMTimer|XtIMAlternateInput|XtIMSignal );
+
+    return m_impl ? m_impl->GetKeepGoing() : true;
+}
+
+// ----------------------------------------------------------------------------
+// Static functions (originally in app.cpp)
+// ----------------------------------------------------------------------------
+
+void ProcessXEvent(XEvent* event)
+{
+    if (event->type == KeyPress)
+    {
+        if (CheckForAccelerator(event))
+        {
+            // Do nothing! We intercepted and processed the event as an
+            // accelerator.
+            return;
+        }
+        // It seemed before that this hack was redundant and
+        // key down events were being generated by wxCanvasInputEvent.
+        // But no longer - why ???
+        //
+        else if (CheckForKeyDown(event))
+        {
+            // We intercepted and processed the key down event
+            return;
+        }
+        else
+        {
+            XtDispatchEvent(event);
+            return;
+        }
+    }
+    else if (event->type == KeyRelease)
+    {
+        // TODO: work out why we still need this !  -michael
+        //
+        if (::CheckForKeyUp(event))
+        {
+            // We intercepted and processed the key up event
+            return;
+        }
+        else
+        {
+            XtDispatchEvent(event);
+            return;
+        }
+    }
+    else if (event->type == PropertyNotify)
+    {
+        wxTheApp->HandlePropertyChange(event);
+        return;
+    }
+    else if (event->type == ResizeRequest)
+    {
+        /* Terry Gitnick <terryg@scientech.com> - 1/21/98
+         * If resize event, don't resize until the last resize event for this
+         * window is recieved. Prevents flicker as windows are resized.
+         */
+
+        Display *disp = XtDisplay((Widget) wxTheApp->GetTopLevelWidget());
+        Window win = event->xany.window;
+        XEvent report;
+
+        //  to avoid flicker
+        report = * event;
+        while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
+
+        // TODO: when implementing refresh optimization, we can use
+        // XtAddExposureToRegion to expand the window's paint region.
+
+        XtDispatchEvent(event);
+    }
+    else
+    {
+        XtDispatchEvent(event);
+    }
+}
+
+// Returns true if an accelerator has been processed
+bool CheckForAccelerator(XEvent* event)
+{
+    if (event->xany.type == KeyPress)
+    {
+        // Find a wxWindow for this window
+        // TODO: should get display for the window, not the current display
+        Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
+                                         event->xany.window);
+        wxWindow* win = NULL;
+
+        // Find the first wxWindow that corresponds to this event window
+        while (widget && !(win = wxGetWindowFromTable(widget)))
+            widget = XtParent(widget);
+
+        if (!widget || !win)
+            return false;
+
+        wxKeyEvent keyEvent(wxEVT_CHAR);
+        wxTranslateKeyEvent(keyEvent, win, (Widget) 0, event);
+
+        // Now we have a wxKeyEvent and we have a wxWindow.
+        // Go up the hierarchy until we find a matching accelerator,
+        // or we get to the top.
+        while (win)
+        {
+            if (win->ProcessAccelerator(keyEvent))
+                return true;
+            win = win->GetParent();
+        }
+        return false;
+    }
+    return false;
+}
+
+// bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; }
+
+bool CheckForKeyDown(XEvent* event)
+{
+    if (event->xany.type == KeyPress)
+    {
+        Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
+                     event->xany.window);
+        wxWindow* win = NULL;
+
+        // Find the first wxWindow that corresponds to this event window
+        while (widget && !(win = wxGetWindowFromTable(widget)))
+            widget = XtParent(widget);
+
+        if (!widget || !win)
+            return false;
+
+        wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
+        wxTranslateKeyEvent(keyEvent, win, (Widget) 0, event);
+
+        return win->ProcessEvent( keyEvent );
+    }
+
+    return false;
+}
+
+// bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; }
+
+bool CheckForKeyUp(XEvent* event)
+{
+    if (event->xany.type == KeyRelease)
+    {
+        Widget widget = XtWindowToWidget((Display*) wxGetDisplay(),
+                         event->xany.window);
+        wxWindow* win = NULL;
+
+        // Find the first wxWindow that corresponds to this event window
+        while (widget && !(win = wxGetWindowFromTable(widget)))
+                widget = XtParent(widget);
+
+        if (!widget || !win)
+            return false;
+
+        wxKeyEvent keyEvent(wxEVT_KEY_UP);
+        wxTranslateKeyEvent(keyEvent, win, (Widget) 0, event);
+
+        return win->ProcessEvent( keyEvent );
+    }
+
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+// executes one main loop iteration (declared in include/wx/motif/private.h)
+// ----------------------------------------------------------------------------
+
+bool wxDoEventLoopIteration( wxEventLoop& evtLoop )
+{
+#if wxUSE_THREADS
+    // leave the main loop to give other threads a chance to
+    // perform their GUI work
+    wxMutexGuiLeave();
+    wxUsleep(20);
+    wxMutexGuiEnter();
+#endif
+
+    while ( !evtLoop.Pending() && ::SendIdleMessage() )
+        ;
+
+    if( !evtLoop.Dispatch() )
+        return false;
+
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+// ::wxWakeUpIdle implementation
+// ----------------------------------------------------------------------------
+
+// As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
+// writing a single byte to the pipe will cause wxEventLoop::Pending
+// to return true, and wxEventLoop::Dispatch to dispatch an input handler
+// that simply removes the byte(s), and to return, which will cause
+// an idle event to be sent
+
+// also wxEventLoop::Exit is implemented that way, so that exiting an
+// event loop won't require an event being in the queue
+
+#include "wx/module.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+static XtInputId inputId;
+static int idleFds[2] = { -1, -1 };
+
+class wxIdlePipeModule : public wxModule
+{
+public:
+    wxIdlePipeModule() {};
+
+    virtual bool OnInit()
+    {
+        if( pipe(idleFds) != 0 )
+            return false;
+
+        return true;
+    }
+
+    virtual void OnExit()
+    {
+        close( idleFds[0] );
+        close( idleFds[1] );
+    }
+private:
+    DECLARE_DYNAMIC_CLASS(wxIdlePipeModule);
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule, wxModule);
+
+static void wxInputCallback( XtPointer, int* fd, XtInputId* )
+{
+    char buffer[128];
+
+    // wxWakeUpIdle may have been called more than once
+    for(;;)
+    {
+        fd_set in;
+        struct timeval timeout;
+
+        timeout.tv_sec = 0;
+        timeout.tv_usec = 0;
+
+        FD_ZERO( &in );
+        FD_SET( *fd, &in );
+
+        if( select( *fd + 1, &in, NULL, NULL, &timeout ) <= 0 )
+            break;
+        if( read( *fd, buffer, sizeof(buffer) - 1 ) != sizeof(buffer) - 1 )
+            break;
+    }
+}
+
+static void wxBreakDispatch()
+{
+    char dummy;
+
+    // check if wxWakeUpIdle has already been called
+    fd_set in;
+    struct timeval timeout;
+
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+
+    FD_ZERO( &in );
+    FD_SET( idleFds[0], &in );
+
+    if( select( idleFds[0] + 1, &in, NULL, NULL, &timeout ) > 0 )
+        return;
+
+    // write a single byte
+    write( idleFds[1], &dummy, 1 );
+}
+
+void wxWakeUpIdle()
+{
+    ::wxBreakDispatch();
+}
+
+bool wxAddIdleCallback()
+{
+    // install input handler for wxWakeUpIdle
+    inputId = XtAppAddInput( (XtAppContext) wxTheApp->GetAppContext(),
+                             idleFds[0],
+                             (XtPointer)XtInputReadMask,
+                             wxInputCallback,
+                             NULL );
+
+    return true;
+}
+
index 75620f067afbabb974007b793204d51996f03205..98b08d38afa0cda66bda774eb4ca577e61f39720 100644 (file)
@@ -199,6 +199,7 @@ ALL_SOURCES = \
                motif/dcmemory.cpp \
                motif/dcscreen.cpp \
                motif/dialog.cpp \
+               motif/evtloop.cpp \
                motif/filedlg.cpp \
                motif/font.cpp \
                motif/frame.cpp \
@@ -834,6 +835,7 @@ GUIOBJS = \
                dcmemory.o \
                dcscreen.o \
                dialog.o \
+               evtloop.o \
                filedlg.o \
                font.o \
                frame.o \
index b7e919489318cfd6078436810918831651140307..8a42ba4f1d3af73990739c639b7dd8f45892f269 100644 (file)
@@ -440,28 +440,20 @@ bool wxMenuBar::DestroyMenuBar()
     return TRUE;
 }
 
-//// Motif-specific
-static XtWorkProcId WorkProcMenuId;
-
-/* Since PopupMenu under Motif stills grab right mouse button events
-* after it was closed, we need to delete the associated widgets to
-* allow next PopUpMenu to appear...
-*/
-
-int PostDeletionOfMenu( XtPointer* clientData )
+// Since PopupMenu under Motif stills grab right mouse button events
+// after it was closed, we need to delete the associated widgets to
+// allow next PopUpMenu to appear...
+void wxMenu::DestroyWidgetAndDetach()
 {
-    XtRemoveWorkProc(WorkProcMenuId);
-    wxMenu *menu = (wxMenu *)clientData;
-
-    if (menu->GetMainWidget())
+    if (GetMainWidget())
     {
-        wxMenu *menuParent = menu->GetParent();
+        wxMenu *menuParent = GetParent();
         if ( menuParent )
         {
             wxMenuItemList::Node *node = menuParent->GetMenuItems().GetFirst();
             while ( node )
             {
-                if ( node->GetData()->GetSubMenu() == menu )
+                if ( node->GetData()->GetSubMenu() == this )
                 {
                     menuParent->GetMenuItems().DeleteNode(node);
 
@@ -472,33 +464,11 @@ int PostDeletionOfMenu( XtPointer* clientData )
             }
         }
 
-        menu->DestroyMenu(TRUE);
+        DestroyMenu(TRUE);
     }
 
     // Mark as no longer popped up
-    menu->m_menuId = -1;
-
-    return TRUE;
-}
-
-void
-wxMenuPopdownCallback(Widget WXUNUSED(w), XtPointer clientData,
-                      XtPointer WXUNUSED(ptr))
-{
-    wxMenu *menu = (wxMenu *)clientData;
-
-    // Added by JOREL Jean-Charles <jjorel@silr.ireste.fr>
-    /* Since Callbacks of MenuItems are not yet processed, we put a
-    * background job which will be done when system will be idle.
-    * What awful hack!! :(
-    */
-
-    WorkProcMenuId = XtAppAddWorkProc(
-        (XtAppContext) wxTheApp->GetAppContext(),
-        (XtWorkProc) PostDeletionOfMenu,
-        (XtPointer) menu );
-    // Apparently not found in Motif headers
-    //  XtVaSetValues( w, XmNpopupEnabled, XmPOPUP_DISABLED, NULL );
+    m_menuId = -1;
 }
 
 /*
@@ -518,10 +488,12 @@ WXWidget wxMenu::CreateMenu (wxMenuBar * menuBar, WXWidget parent, wxMenu * topM
     if (!pullDown)
     {
         menu = XmCreatePopupMenu ((Widget) parent, "popup", args, 2);
+#if 0
         XtAddCallback(menu,
             XmNunmapCallback,
             (XtCallbackProc)wxMenuPopdownCallback,
             (XtPointer)this);
+#endif
     }
     else
     {
index c0006a04330e73fa8c21fada12023ef20baed479..6df0931d6cdd358ae66146a5559cc3adc69c7da1 100644 (file)
@@ -354,6 +354,7 @@ void wxMenuItemCallback (Widget WXUNUSED(w), XtPointer clientData,
 
             item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(commandEvent);
         }
+        // this is the child of a popup menu
         else if (item->GetTopMenu())
         {
             wxCommandEvent event (wxEVT_COMMAND_MENU_SELECTED, item->GetId());
@@ -361,6 +362,14 @@ void wxMenuItemCallback (Widget WXUNUSED(w), XtPointer clientData,
             event.SetInt( item->GetId() );
 
             item->GetTopMenu()->ProcessCommand (event);
+
+            // Since PopupMenu under Motif stills grab right mouse
+            // button events after it was closed, we need to delete
+            // the associated widgets to allow next PopUpMenu to
+            // appear; this needs to be done there because doing it in
+            // a WorkProc as before may cause crashes if a menu item causes
+            // the parent window of the menu to be destroyed
+            item->GetTopMenu()->DestroyWidgetAndDetach();
         }
     }
 }
index e77149f3a9823263d4c2283d394d660dece0fa79..4ee8f71d5bbe4f496f16e6781f869b5a10a8ab53 100644 (file)
@@ -45,6 +45,7 @@
 #include "wx/module.h"
 #include "wx/menuitem.h"
 #include "wx/log.h"
+#include "wx/evtloop.h"
 
 #if  wxUSE_DRAG_AND_DROP
     #include "wx/dnd.h"
@@ -1151,6 +1152,8 @@ void wxWindow::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
 // popup menus
 // ----------------------------------------------------------------------------
 
+#if wxUSE_MENUS
+
 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
 {
     Widget widget = (Widget) GetMainWidget();
@@ -1165,7 +1168,8 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
     if (menu->GetParent() && (menu->GetId() != -1))
         return FALSE;
 
-    if (menu->GetMainWidget()) {
+    if (menu->GetMainWidget())
+    {
         menu->DestroyMenu(TRUE);
     }
 
@@ -1214,7 +1218,6 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
     XmMenuPosition (menuWidget, &event);
     XtManageChild (menuWidget);
 
-    XEvent x_event;
     // The ID of a pop-up menu is 1 when active, and is set to 0 by the
     // idle-time destroy routine.
     // Waiting until this ID changes causes this function to block until
@@ -1222,29 +1225,19 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
     // In other words, once this routine returns, it is safe to delete
     // the menu object.
     // Ian Brown <ian.brown@printsoft.de>
-    while (menu->GetId() == 1)
-    {
-        XtAppNextEvent( (XtAppContext) wxTheApp->GetAppContext(), &x_event);
 
-        wxTheApp->ProcessXEvent((WXEvent*) & x_event);
+    wxEventLoop evtLoop;
 
-        if (XtAppPending( (XtAppContext) wxTheApp->GetAppContext() ) == 0)
-        {
-            if (!wxTheApp->ProcessIdle())
-            {
-#if wxUSE_THREADS
-                // leave the main loop to give other threads a chance to
-                // perform their GUI work
-                wxMutexGuiLeave();
-                wxUsleep(20);
-                wxMutexGuiEnter();
-#endif
-            }
-        }
+    while (menu->GetId() == 1)
+    {
+        wxDoEventLoopIteration( evtLoop );
     }
+
     return TRUE;
 }
 
+#endif
+
 // ---------------------------------------------------------------------------
 // moving and resizing
 // ---------------------------------------------------------------------------
@@ -1352,9 +1345,9 @@ void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
             y = oldY;
     }
 
-    if ( width == -1 )
+    if ( width <= 0 )
         width = oldW;
-    if ( height == -1 )
+    if ( height <= 0 )
         height = oldH;
 
     bool nothingChanged = (x == oldX) && (y == oldY) &&
@@ -1390,15 +1383,6 @@ void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
 
         if (managed)
             XtManageChild(widget);
-
-        // How about this bit. Maybe we don't need to generate size events
-        // all the time -- they'll be generated when the window is sized anyway.
-#if 0
-        wxSizeEvent sizeEvent(wxSize(width, height), GetId());
-        sizeEvent.SetEventObject(this);
-
-        GetEventHandler()->ProcessEvent(sizeEvent);
-#endif // 0
     }
 }
 
@@ -1727,6 +1711,7 @@ void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event))
 
 bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
 {
+#if wxUSE_ACCEL
     if (!m_acceleratorTable.Ok())
         return FALSE;
 
@@ -1753,6 +1738,7 @@ bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
             wxFrame* frame = wxDynamicCast(parent, wxFrame);
             if ( frame )
             {
+#if wxUSE_MENUS
                 // Try for a menu command
                 if (frame->GetMenuBar())
                 {
@@ -1767,6 +1753,7 @@ bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
                         return frame->GetEventHandler()->ProcessEvent(commandEvent);
                     }
                 }
+#endif
             }
 
             // Find a child matching the command id
@@ -1788,6 +1775,7 @@ bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
             return FALSE;
         } // matches event
     }// for
+#endif
 
     // We didn't match the key event against an accelerator.
     return FALSE;