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
dcscreen.cpp Motif
dialog.cpp Motif
evtloop.cpp Motif
filedlg.cpp Motif
font.cpp Motif
frame.cpp Motif

View 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;

View 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,

View 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;

View File

@ -25,10 +25,12 @@
// ----------------------------------------------------------------------------
// 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
// ----------------------------------------------------------------------------

View 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;

View 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

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/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 \

View 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
{

View 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();
}
}
}

View 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>
wxEventLoop evtLoop;
while (menu->GetId() == 1)
{
XtAppNextEvent( (XtAppContext) wxTheApp->GetAppContext(), &x_event);
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
}
}
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;