Implemented wxEventLoop for wxMotif, and used it in wxDialog::ShowModal,

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
This commit is contained in:
Mattia Barbon
2003-02-02 15:48:50 +00:00
parent d894c20113
commit 7e1bcfa80e
12 changed files with 575 additions and 346 deletions

View File

@@ -584,6 +584,7 @@ dcclient.cpp Motif
dcmemory.cpp Motif dcmemory.cpp Motif
dcscreen.cpp Motif dcscreen.cpp Motif
dialog.cpp Motif dialog.cpp Motif
evtloop.cpp Motif
filedlg.cpp Motif filedlg.cpp Motif
font.cpp Motif font.cpp Motif
frame.cpp Motif frame.cpp Motif

View File

@@ -20,7 +20,6 @@
// headers // headers
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include "wx/gdicmn.h"
#include "wx/event.h" #include "wx/event.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -32,6 +31,7 @@ class WXDLLEXPORT wxWindow;
class WXDLLEXPORT wxApp; class WXDLLEXPORT wxApp;
class WXDLLEXPORT wxKeyEvent; class WXDLLEXPORT wxKeyEvent;
class WXDLLEXPORT wxLog; class WXDLLEXPORT wxLog;
class WXDLLEXPORT wxEventLoop;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// the wxApp class for Motif - see wxAppBase for more details // the wxApp class for Motif - see wxAppBase for more details
@@ -43,7 +43,7 @@ class WXDLLEXPORT wxApp : public wxAppBase
public: public:
wxApp(); wxApp();
~wxApp() {} virtual ~wxApp();
// override base class (pure) virtuals // override base class (pure) virtuals
// ----------------------------------- // -----------------------------------
@@ -71,20 +71,6 @@ public:
// Returns TRUE if more idle time is requested. // Returns TRUE if more idle time is requested.
bool SendIdleEvents(wxWindow* win); 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: protected:
bool m_showOnInit; bool m_showOnInit;
@@ -105,12 +91,11 @@ public:
// This handler is called when a property change event occurs // This handler is called when a property change event occurs
virtual void HandlePropertyChange(WXEvent *event); virtual void HandlePropertyChange(WXEvent *event);
public: private:
static long sm_lastMessageTime; static long sm_lastMessageTime;
int m_nCmdShow; int m_nCmdShow;
protected: wxEventLoop* m_eventLoop;
bool m_keepGoing;
// Motif-specific // Motif-specific
WXAppContext m_appContext; WXAppContext m_appContext;

View File

@@ -18,6 +18,8 @@
WXDLLEXPORT_DATA(extern const char*) wxDialogNameStr; WXDLLEXPORT_DATA(extern const char*) wxDialogNameStr;
class WXDLLEXPORT wxEventLoop;
// Dialog boxes // Dialog boxes
class WXDLLEXPORT wxDialog : public wxDialogBase class WXDLLEXPORT wxDialog : public wxDialogBase
{ {
@@ -102,6 +104,7 @@ private:
//// Motif-specific //// Motif-specific
bool m_modalShowing; bool m_modalShowing;
wxEventLoop* m_eventLoop;
protected: protected:
virtual void DoSetSize(int x, int y, virtual void DoSetSize(int x, int y,

View File

@@ -94,6 +94,7 @@ public:
bool IsTearOff() const { return (m_style & wxMENU_TEAROFF) != 0; } bool IsTearOff() const { return (m_style & wxMENU_TEAROFF) != 0; }
void DestroyWidgetAndDetach();
public: public:
// Motif-specific data // Motif-specific data
int m_numColumns; int m_numColumns;

View File

@@ -25,10 +25,12 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// All widgets should have this as their resize proc. // 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 // 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 // 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 // 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 bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win,
extern void wxDoChangeBackgroundColour(WXWidget widget, wxColour& backgroundColour, bool changeArmColour = FALSE); 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 wxNO_COLORS 0x00
#define wxBACK_COLORS 0x01 #define wxBACK_COLORS 0x01
@@ -78,6 +86,11 @@ extern XColor itemColors[5] ;
class wxXmString class wxXmString
{ {
public: public:
wxXmString(const char* str)
{
m_string = XmStringCreateLtoR((char *)str, XmSTRING_DEFAULT_CHARSET);
}
wxXmString(const wxString& str) wxXmString(const wxString& str)
{ {
m_string = XmStringCreateLtoR((char *)str.c_str(), m_string = XmStringCreateLtoR((char *)str.c_str(),
@@ -94,6 +107,15 @@ private:
XmString m_string; 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 // macros to avoid casting WXFOO to Foo all the time
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -35,6 +35,7 @@
#include "wx/memory.h" #include "wx/memory.h"
#include "wx/log.h" #include "wx/log.h"
#include "wx/intl.h" #include "wx/intl.h"
#include "wx/evtloop.h"
#if wxUSE_THREADS #if wxUSE_THREADS
#include "wx/thread.h" #include "wx/thread.h"
@@ -61,6 +62,7 @@
#include <string.h> #include <string.h>
extern wxList wxPendingDelete; extern wxList wxPendingDelete;
extern bool wxAddIdleCallback();
wxApp *wxTheApp = NULL; wxApp *wxTheApp = NULL;
@@ -267,6 +269,7 @@ wxApp::wxApp()
argc = 0; argc = 0;
argv = NULL; argv = NULL;
m_eventLoop = new wxEventLoop;
m_mainColormap = (WXColormap) NULL; m_mainColormap = (WXColormap) NULL;
m_appContext = (WXAppContext) NULL; m_appContext = (WXAppContext) NULL;
m_topLevelWidget = (WXWidget) NULL; m_topLevelWidget = (WXWidget) NULL;
@@ -274,6 +277,11 @@ wxApp::wxApp()
m_initialDisplay = (WXDisplay*) 0; m_initialDisplay = (WXDisplay*) 0;
} }
wxApp::~wxApp()
{
delete m_eventLoop;
}
bool wxApp::Initialized() bool wxApp::Initialized()
{ {
if (GetTopWindow()) if (GetTopWindow())
@@ -284,8 +292,6 @@ bool wxApp::Initialized()
int wxApp::MainLoop() int wxApp::MainLoop()
{ {
m_keepGoing = TRUE;
/* /*
* Sit around forever waiting to process X-events. Property Change * Sit around forever waiting to process X-events. Property Change
* event are handled special, because they have to refer to * event are handled special, because they have to refer to
@@ -297,129 +303,23 @@ int wxApp::MainLoop()
XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())), XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())),
PropertyChangeMask); PropertyChangeMask);
XEvent event; m_eventLoop->Run();
// 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
}
}
}
return 0; return 0;
} }
// Processes an X event. // Processes an idle 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);
}
}
// Returns TRUE if more time is needed. // Returns TRUE if more time is needed.
bool wxApp::ProcessIdle() bool wxApp::ProcessIdle()
{ {
wxIdleEvent event; wxIdleEvent event;
event.SetEventObject(this);
ProcessEvent(event);
return event.MoreRequested(); return ProcessEvent(event) && event.MoreRequested();
} }
void wxApp::ExitMainLoop() void wxApp::ExitMainLoop()
{ {
m_keepGoing = FALSE; m_eventLoop->Exit();
} }
// Is a message/event pending? // Is a message/event pending?
@@ -435,11 +335,7 @@ bool wxApp::Pending()
// Dispatch a message. // Dispatch a message.
void wxApp::Dispatch() void wxApp::Dispatch()
{ {
// XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll); m_eventLoop->Dispatch();
XEvent event;
XtAppNextEvent((XtAppContext) GetAppContext(), &event);
ProcessXEvent((WXEvent*) & event);
} }
// This should be redefined in a derived class for // This should be redefined in a derived class for
@@ -489,13 +385,6 @@ void wxApp::OnIdle(wxIdleEvent& event)
inOnIdle = FALSE; 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 // Send idle event to all top-level windows
bool wxApp::SendIdleEvents() bool wxApp::SendIdleEvents()
{ {
@@ -539,7 +428,7 @@ bool wxApp::SendIdleEvents(wxWindow* win)
void wxApp::DeletePendingObjects() void wxApp::DeletePendingObjects()
{ {
wxNode *node = wxPendingDelete.GetFirst(); wxList::Node *node = wxPendingDelete.GetFirst();
while (node) while (node)
{ {
wxObject *obj = node->GetData(); wxObject *obj = node->GetData();
@@ -610,6 +499,8 @@ bool wxApp::OnInitGui()
GetMainColormap(dpy); GetMainColormap(dpy);
m_maxRequestSize = XMaxRequestSize((Display*) dpy); m_maxRequestSize = XMaxRequestSize((Display*) dpy);
wxAddIdleCallback();
return TRUE; return TRUE;
} }
@@ -629,91 +520,6 @@ WXColormap wxApp::GetMainColormap(WXDisplay* display)
return (WXColormap) c; 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() void wxExit()
{ {
int retValue = 0; int retValue = 0;

View File

@@ -24,6 +24,7 @@
#include "wx/utils.h" #include "wx/utils.h"
#include "wx/app.h" #include "wx/app.h"
#include "wx/settings.h" #include "wx/settings.h"
#include "wx/evtloop.h"
#ifdef __VMS__ #ifdef __VMS__
#pragma message disable nosimpint #pragma message disable nosimpint
@@ -56,7 +57,7 @@
// A stack of modal_showing flags, since we can't rely // A stack of modal_showing flags, since we can't rely
// on accessing wxDialog::m_modalShowing within // on accessing wxDialog::m_modalShowing within
// wxDialog::Show in case a callback has deleted the wxDialog. // 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 // Lists to keep track of windows, so we can disable/enable them
// for modal dialogs // for modal dialogs
@@ -81,6 +82,7 @@ END_EVENT_TABLE()
wxDialog::wxDialog() wxDialog::wxDialog()
{ {
m_modalShowing = FALSE; m_modalShowing = FALSE;
m_eventLoop = NULL;
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
} }
@@ -98,6 +100,7 @@ bool wxDialog::Create(wxWindow *parent, wxWindowID id,
return FALSE; return FALSE;
m_modalShowing = FALSE; m_modalShowing = FALSE;
m_eventLoop = NULL;
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
m_foregroundColour = *wxBLACK; m_foregroundColour = *wxBLACK;
@@ -204,6 +207,7 @@ void wxDialog::SetModal(bool flag)
wxDialog::~wxDialog() wxDialog::~wxDialog()
{ {
m_isBeingDeleted = TRUE; m_isBeingDeleted = TRUE;
delete m_eventLoop;
if (m_mainWidget) if (m_mainWidget)
{ {
@@ -312,52 +316,24 @@ int wxDialog::ShowModal()
if (m_modalShowing) if (m_modalShowing)
return 0; return 0;
m_eventLoop = new wxEventLoop;
wxModalShowingStack.Insert((wxObject *)TRUE);
m_modalShowing = TRUE; m_modalShowing = TRUE;
XtAddGrab((Widget) m_mainWidget, TRUE, FALSE); XtAddGrab((Widget) m_mainWidget, TRUE, FALSE);
XEvent event; m_eventLoop->Run();
// 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;
// Now process all events in case they get sent to a destroyed dialog // Now process all events in case they get sent to a destroyed dialog
XSync(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()), FALSE); XSync(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()), FALSE);
while (XtAppPending((XtAppContext) wxTheApp->GetAppContext())) while (m_eventLoop->Pending())
{ {
XFlush(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())); XFlush(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()));
XtAppNextEvent((XtAppContext) wxTheApp->GetAppContext(), &event); m_eventLoop->Dispatch();
wxTheApp->ProcessXEvent((WXEvent*) &event);
} }
delete m_eventLoop;
m_eventLoop = NULL;
// TODO: is it safe to call this, if the dialog may have been deleted // 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. // by now? Probably only if we're using delayed deletion of dialogs.
return GetReturnCode(); return GetReturnCode();
@@ -376,10 +352,7 @@ void wxDialog::EndModal(int retCode)
Show(FALSE); Show(FALSE);
m_modalShowing = FALSE; m_modalShowing = FALSE;
m_eventLoop->Exit();
wxNode *node = wxModalShowingStack.First();
if (node)
node->SetData((wxObject *)FALSE);
} }
// Standard buttons // Standard buttons

467
src/motif/evtloop.cpp Normal file
View File

@@ -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;
}

View File

@@ -199,6 +199,7 @@ ALL_SOURCES = \
motif/dcmemory.cpp \ motif/dcmemory.cpp \
motif/dcscreen.cpp \ motif/dcscreen.cpp \
motif/dialog.cpp \ motif/dialog.cpp \
motif/evtloop.cpp \
motif/filedlg.cpp \ motif/filedlg.cpp \
motif/font.cpp \ motif/font.cpp \
motif/frame.cpp \ motif/frame.cpp \
@@ -834,6 +835,7 @@ GUIOBJS = \
dcmemory.o \ dcmemory.o \
dcscreen.o \ dcscreen.o \
dialog.o \ dialog.o \
evtloop.o \
filedlg.o \ filedlg.o \
font.o \ font.o \
frame.o \ frame.o \

View File

@@ -440,28 +440,20 @@ bool wxMenuBar::DestroyMenuBar()
return TRUE; return TRUE;
} }
//// Motif-specific // Since PopupMenu under Motif stills grab right mouse button events
static XtWorkProcId WorkProcMenuId; // after it was closed, we need to delete the associated widgets to
// allow next PopUpMenu to appear...
/* Since PopupMenu under Motif stills grab right mouse button events void wxMenu::DestroyWidgetAndDetach()
* after it was closed, we need to delete the associated widgets to
* allow next PopUpMenu to appear...
*/
int PostDeletionOfMenu( XtPointer* clientData )
{ {
XtRemoveWorkProc(WorkProcMenuId); if (GetMainWidget())
wxMenu *menu = (wxMenu *)clientData;
if (menu->GetMainWidget())
{ {
wxMenu *menuParent = menu->GetParent(); wxMenu *menuParent = GetParent();
if ( menuParent ) if ( menuParent )
{ {
wxMenuItemList::Node *node = menuParent->GetMenuItems().GetFirst(); wxMenuItemList::Node *node = menuParent->GetMenuItems().GetFirst();
while ( node ) while ( node )
{ {
if ( node->GetData()->GetSubMenu() == menu ) if ( node->GetData()->GetSubMenu() == this )
{ {
menuParent->GetMenuItems().DeleteNode(node); menuParent->GetMenuItems().DeleteNode(node);
@@ -472,33 +464,11 @@ int PostDeletionOfMenu( XtPointer* clientData )
} }
} }
menu->DestroyMenu(TRUE); DestroyMenu(TRUE);
} }
// Mark as no longer popped up // Mark as no longer popped up
menu->m_menuId = -1; 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 );
} }
/* /*
@@ -518,10 +488,12 @@ WXWidget wxMenu::CreateMenu (wxMenuBar * menuBar, WXWidget parent, wxMenu * topM
if (!pullDown) if (!pullDown)
{ {
menu = XmCreatePopupMenu ((Widget) parent, "popup", args, 2); menu = XmCreatePopupMenu ((Widget) parent, "popup", args, 2);
#if 0
XtAddCallback(menu, XtAddCallback(menu,
XmNunmapCallback, XmNunmapCallback,
(XtCallbackProc)wxMenuPopdownCallback, (XtCallbackProc)wxMenuPopdownCallback,
(XtPointer)this); (XtPointer)this);
#endif
} }
else else
{ {

View File

@@ -354,6 +354,7 @@ void wxMenuItemCallback (Widget WXUNUSED(w), XtPointer clientData,
item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(commandEvent); item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(commandEvent);
} }
// this is the child of a popup menu
else if (item->GetTopMenu()) else if (item->GetTopMenu())
{ {
wxCommandEvent event (wxEVT_COMMAND_MENU_SELECTED, item->GetId()); wxCommandEvent event (wxEVT_COMMAND_MENU_SELECTED, item->GetId());
@@ -361,6 +362,14 @@ void wxMenuItemCallback (Widget WXUNUSED(w), XtPointer clientData,
event.SetInt( item->GetId() ); event.SetInt( item->GetId() );
item->GetTopMenu()->ProcessCommand (event); 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();
} }
} }
} }

View File

@@ -45,6 +45,7 @@
#include "wx/module.h" #include "wx/module.h"
#include "wx/menuitem.h" #include "wx/menuitem.h"
#include "wx/log.h" #include "wx/log.h"
#include "wx/evtloop.h"
#if wxUSE_DRAG_AND_DROP #if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h" #include "wx/dnd.h"
@@ -1151,6 +1152,8 @@ void wxWindow::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
// popup menus // popup menus
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#if wxUSE_MENUS
bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y) bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
{ {
Widget widget = (Widget) GetMainWidget(); Widget widget = (Widget) GetMainWidget();
@@ -1165,7 +1168,8 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
if (menu->GetParent() && (menu->GetId() != -1)) if (menu->GetParent() && (menu->GetId() != -1))
return FALSE; return FALSE;
if (menu->GetMainWidget()) { if (menu->GetMainWidget())
{
menu->DestroyMenu(TRUE); menu->DestroyMenu(TRUE);
} }
@@ -1214,7 +1218,6 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
XmMenuPosition (menuWidget, &event); XmMenuPosition (menuWidget, &event);
XtManageChild (menuWidget); XtManageChild (menuWidget);
XEvent x_event;
// The ID of a pop-up menu is 1 when active, and is set to 0 by the // The ID of a pop-up menu is 1 when active, and is set to 0 by the
// idle-time destroy routine. // idle-time destroy routine.
// Waiting until this ID changes causes this function to block until // 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 // In other words, once this routine returns, it is safe to delete
// the menu object. // the menu object.
// Ian Brown <ian.brown@printsoft.de> // Ian Brown <ian.brown@printsoft.de>
wxEventLoop evtLoop;
while (menu->GetId() == 1) while (menu->GetId() == 1)
{ {
XtAppNextEvent( (XtAppContext) wxTheApp->GetAppContext(), &x_event); wxDoEventLoopIteration( evtLoop );
wxTheApp->ProcessXEvent((WXEvent*) & x_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
}
}
} }
return TRUE; return TRUE;
} }
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// moving and resizing // moving and resizing
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -1352,9 +1345,9 @@ void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
y = oldY; y = oldY;
} }
if ( width == -1 ) if ( width <= 0 )
width = oldW; width = oldW;
if ( height == -1 ) if ( height <= 0 )
height = oldH; height = oldH;
bool nothingChanged = (x == oldX) && (y == oldY) && bool nothingChanged = (x == oldX) && (y == oldY) &&
@@ -1390,15 +1383,6 @@ void wxWindow::DoSetSizeIntr(int x, int y, int width, int height,
if (managed) if (managed)
XtManageChild(widget); 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) bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
{ {
#if wxUSE_ACCEL
if (!m_acceleratorTable.Ok()) if (!m_acceleratorTable.Ok())
return FALSE; return FALSE;
@@ -1753,6 +1738,7 @@ bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
wxFrame* frame = wxDynamicCast(parent, wxFrame); wxFrame* frame = wxDynamicCast(parent, wxFrame);
if ( frame ) if ( frame )
{ {
#if wxUSE_MENUS
// Try for a menu command // Try for a menu command
if (frame->GetMenuBar()) if (frame->GetMenuBar())
{ {
@@ -1767,6 +1753,7 @@ bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
return frame->GetEventHandler()->ProcessEvent(commandEvent); return frame->GetEventHandler()->ProcessEvent(commandEvent);
} }
} }
#endif
} }
// Find a child matching the command id // Find a child matching the command id
@@ -1788,6 +1775,7 @@ bool wxWindow::ProcessAccelerator(wxKeyEvent& event)
return FALSE; return FALSE;
} // matches event } // matches event
}// for }// for
#endif
// We didn't match the key event against an accelerator. // We didn't match the key event against an accelerator.
return FALSE; return FALSE;