Added X11 wxEventLoop implementation; rearranged event processing
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14064 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
338
src/x11/app.cpp
338
src/x11/app.cpp
@@ -30,6 +30,7 @@
|
||||
#include "wx/memory.h"
|
||||
#include "wx/log.h"
|
||||
#include "wx/intl.h"
|
||||
#include "wx/evtloop.h"
|
||||
|
||||
#if wxUSE_THREADS
|
||||
#include "wx/thread.h"
|
||||
@@ -68,15 +69,15 @@ BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
|
||||
typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
|
||||
|
||||
XErrorHandlerFunc gs_pfnXErrorHandler = 0;
|
||||
XErrorHandlerFunc gs_pfnXErrorHandler = 0;
|
||||
|
||||
static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
|
||||
{
|
||||
// just forward to the default handler for now
|
||||
return gs_pfnXErrorHandler(dpy, xevent);
|
||||
}
|
||||
static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
|
||||
{
|
||||
// just forward to the default handler for now
|
||||
return gs_pfnXErrorHandler(dpy, xevent);
|
||||
}
|
||||
#endif // __WXDEBUG__
|
||||
|
||||
long wxApp::sm_lastMessageTime = 0;
|
||||
@@ -259,6 +260,7 @@ wxApp::wxApp()
|
||||
m_topLevelWidget = (WXWindow) NULL;
|
||||
m_maxRequestSize = 0;
|
||||
m_initialDisplay = (WXDisplay*) 0;
|
||||
m_mainLoop = NULL;
|
||||
}
|
||||
|
||||
bool wxApp::Initialized()
|
||||
@@ -271,131 +273,168 @@ bool wxApp::Initialized()
|
||||
|
||||
int wxApp::MainLoop()
|
||||
{
|
||||
m_keepGoing = TRUE;
|
||||
int rt;
|
||||
m_mainLoop = new wxEventLoop;
|
||||
|
||||
/*
|
||||
* Sit around forever waiting to process X-events. Property Change
|
||||
* event are handled special, because they have to refer to
|
||||
* the root window rather than to a widget. therefore we can't
|
||||
* use an Xt-eventhandler.
|
||||
*/
|
||||
rt = m_mainLoop->Run();
|
||||
|
||||
XSelectInput(wxGetDisplay(),
|
||||
XDefaultRootWindow(wxGetDisplay()),
|
||||
PropertyChangeMask);
|
||||
|
||||
XEvent event;
|
||||
|
||||
// Use this flag to allow breaking the loop via wxApp::ExitMainLoop()
|
||||
while (m_keepGoing)
|
||||
{
|
||||
XNextEvent(wxGetDisplay(), & event);
|
||||
|
||||
ProcessXEvent((WXEvent*) & event);
|
||||
|
||||
if (XtPending(wxGetDisplay()) == 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;
|
||||
delete m_mainLoop;
|
||||
m_mainLoop = NULL;
|
||||
return rt;
|
||||
}
|
||||
|
||||
// Processes an X event.
|
||||
void wxApp::ProcessXEvent(WXEvent* _event)
|
||||
{
|
||||
XEvent* event = (XEvent*) _event;
|
||||
|
||||
if (event->type == KeyPress)
|
||||
|
||||
wxWindow* win = NULL;
|
||||
Window window = event->xany.window;
|
||||
Window actualWindow = window;
|
||||
|
||||
// Find the first wxWindow that corresponds to this event window
|
||||
// TODO: may need to translate coordinates from actualWindow
|
||||
// to window, if the receiving window != wxWindow window
|
||||
while (window && !(win = wxGetWindowFromTable(window)))
|
||||
window = XGetParent(window);
|
||||
|
||||
// TODO: shouldn't all the ProcessEvents below
|
||||
// be win->GetEventHandler()->ProcessEvent?
|
||||
switch (event->type)
|
||||
{
|
||||
if (CheckForAccelerator(_event))
|
||||
case KeyPress:
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// TODO for X11 implementation -- the equivalent of XtDispatchEvent.
|
||||
// Presumably, we need to form the wxEvents and
|
||||
// and send them to the appropriate windows.
|
||||
// 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
|
||||
{
|
||||
// TODO: The X equivalent of XtDispatchEvent
|
||||
// (see above)
|
||||
// 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.
|
||||
*/
|
||||
if (CheckForAccelerator(_event))
|
||||
{
|
||||
// Do nothing! We intercepted and processed the event as an
|
||||
// accelerator.
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
|
||||
wxTranslateKeyEvent(keyEvent, win, window, xEvent);
|
||||
|
||||
Display *disp = wxGetDisplay();
|
||||
Window win = event->xany.window;
|
||||
XEvent report;
|
||||
// We didn't process wxEVT_KEY_DOWN, so send
|
||||
// wxEVT_KEY_CHAR
|
||||
if (!win->ProcessEvent( keyEvent ))
|
||||
{
|
||||
keyEvent.SetEventType(wxEVT_KEY_CHAR);
|
||||
win->ProcessEvent( keyEvent );
|
||||
}
|
||||
|
||||
// We intercepted and processed the key down event
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case KeyRelease:
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
wxKeyEvent keyEvent(wxEVT_KEY_UP);
|
||||
wxTranslateKeyEvent(keyEvent, win, window, event);
|
||||
|
||||
// to avoid flicker
|
||||
report = * event;
|
||||
while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
|
||||
win->ProcessEvent( keyEvent );
|
||||
}
|
||||
return;
|
||||
}
|
||||
case PropertyNotify:
|
||||
{
|
||||
HandlePropertyChange(_event);
|
||||
return;
|
||||
}
|
||||
case 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.
|
||||
*/
|
||||
|
||||
// TODO: when implementing refresh optimization, we can use
|
||||
// XtAddExposureToRegion to expand the window's paint region.
|
||||
|
||||
// TODO: generate resize event
|
||||
// XtDispatchEvent(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: generate all other events
|
||||
// XtDispatchEvent(event);
|
||||
Display *disp = wxGetDisplay();
|
||||
XEvent report;
|
||||
|
||||
// to avoid flicker
|
||||
report = * event;
|
||||
while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report));
|
||||
|
||||
// TODO: when implementing refresh optimization, we can use
|
||||
// XtAddExposureToRegion to expand the window's paint region.
|
||||
|
||||
if (win)
|
||||
{
|
||||
wxSize sz = win->GetSize();
|
||||
wxSizeEvent sizeEvent(sz, win->GetId());
|
||||
sizeEvent.SetEventObject(win);
|
||||
|
||||
win->ProcessEvent( wxevent );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case Expose:
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
|
||||
event->xexpose.width, event->xexpose.height);
|
||||
|
||||
if (event -> xexpose.count == 0)
|
||||
{
|
||||
win->DoPaint();
|
||||
win->ClearUpdateRects();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case EnterNotify:
|
||||
case LeaveNotify:
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
case MotionNotify:
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
wxMouseEvent wxevent;
|
||||
wxTranslateMouseEvent(wxevent, win, window, event);
|
||||
win->ProcessEvent( wxevent );
|
||||
}
|
||||
return;
|
||||
}
|
||||
case FocusIn:
|
||||
{
|
||||
if (win && event->xfocus.detail != NotifyPointer)
|
||||
{
|
||||
wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId());
|
||||
focusEvent.SetEventObject(win);
|
||||
win->ProcessEvent(focusEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FocusOut:
|
||||
{
|
||||
if (win && event->xfocus.detail != NotifyPointer)
|
||||
{
|
||||
wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId());
|
||||
focusEvent.SetEventObject(win);
|
||||
win->ProcessEvent(focusEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns TRUE if more time is needed.
|
||||
// Note that this duplicates wxEventLoopImpl::SendIdleEvent
|
||||
// but ProcessIdle may be needed by apps, so is kept.
|
||||
bool wxApp::ProcessIdle()
|
||||
{
|
||||
wxIdleEvent event;
|
||||
@@ -407,23 +446,20 @@ bool wxApp::ProcessIdle()
|
||||
|
||||
void wxApp::ExitMainLoop()
|
||||
{
|
||||
m_keepGoing = FALSE;
|
||||
if (m_mainLoop)
|
||||
m_mainLoop->Exit(0);
|
||||
}
|
||||
|
||||
// Is a message/event pending?
|
||||
bool wxApp::Pending()
|
||||
{
|
||||
XFlush(wxGetDisplay());
|
||||
|
||||
return (XPending(wxGetDisplay()) > 0);
|
||||
return wxEventLoop::GetActive()->Pending();
|
||||
}
|
||||
|
||||
// Dispatch a message.
|
||||
void wxApp::Dispatch()
|
||||
{
|
||||
XEvent event;
|
||||
XNextEvent(wxGetDisplay(), & event);
|
||||
ProcessXEvent((WXEvent*) & event);
|
||||
wxEventLoop::GetActive()->Dispatch();
|
||||
}
|
||||
|
||||
// This should be redefined in a derived class for
|
||||
@@ -553,19 +589,15 @@ bool wxApp::OnInitGui()
|
||||
(const char*) className);
|
||||
exit(-1);
|
||||
}
|
||||
XSelectInput(m_initialDisplay,
|
||||
XDefaultRootWindow(m_initialDisplay),
|
||||
PropertyChangeMask);
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
// install the X error handler
|
||||
gs_pfnXErrorHandler = XSetErrorHandler(wxXErrorHandler);
|
||||
#endif // __WXDEBUG__
|
||||
|
||||
// Do we need to create the top-level window initially?
|
||||
#if 0
|
||||
wxTheApp->m_topLevelWidget = (WXWidget) XtAppCreateShell((String)NULL, (const char*) wxTheApp->GetClassName(),
|
||||
applicationShellWidgetClass,dpy,
|
||||
NULL,0) ;
|
||||
#endif
|
||||
|
||||
GetMainColormap(dpy);
|
||||
m_maxRequestSize = XMaxRequestSize((Display*) dpy);
|
||||
|
||||
@@ -634,54 +666,6 @@ bool wxApp::CheckForAccelerator(WXEvent* event)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool wxApp::CheckForKeyDown(WXEvent* event)
|
||||
{
|
||||
XEvent* xEvent = (XEvent*) event;
|
||||
if (xEvent->xany.type == KeyPress)
|
||||
{
|
||||
Window window = xEvent->xany.window;
|
||||
wxWindow* win = NULL;
|
||||
|
||||
// Find the first wxWindow that corresponds to this event window
|
||||
while (window && !(win = wxGetWindowFromTable(window)))
|
||||
window = XGetParent(window);
|
||||
|
||||
if (!window || !win)
|
||||
return FALSE;
|
||||
|
||||
wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
|
||||
wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
|
||||
|
||||
return win->ProcessEvent( keyEvent );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool wxApp::CheckForKeyUp(WXEvent* event)
|
||||
{
|
||||
XEvent* xEvent = (XEvent*) event;
|
||||
if (xEvent->xany.type == KeyRelease)
|
||||
{
|
||||
Window window = xEvent->xany.window;
|
||||
wxWindow* win = NULL;
|
||||
|
||||
// Find the first wxWindow that corresponds to this event window
|
||||
while (window && !(win = wxGetWindowFromTable(window)))
|
||||
window = XGetParent(window);
|
||||
|
||||
if (!window || !win)
|
||||
return FALSE;
|
||||
|
||||
wxKeyEvent keyEvent(wxEVT_KEY_UP);
|
||||
wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
|
||||
|
||||
return win->ProcessEvent( keyEvent );
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void wxExit()
|
||||
{
|
||||
int retValue = 0;
|
||||
|
Reference in New Issue
Block a user