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:
Julian Smart
2002-02-08 12:00:11 +00:00
parent b95edd4708
commit 1b0fb34be8
7 changed files with 626 additions and 1658 deletions

View File

@@ -32,6 +32,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
@@ -78,12 +79,6 @@ public:
// 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;
@@ -114,6 +109,7 @@ protected:
WXColormap m_mainColormap;
WXDisplay* m_initialDisplay;
long m_maxRequestSize;
wxEventLoop* m_mainLoop;
DECLARE_EVENT_TABLE()
};

View File

@@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////
// Name: private.h
// Purpose: Private declarations for wxMotif port
// Purpose: Private declarations for X11 port
// Author: Julian Smart
// Modified by:
// Created: 17/09/98
@@ -17,27 +17,26 @@
class wxMouseEvent;
class wxKeyEvent;
// Put any private declarations here: native Motif types may be used because
// this header is included after Xm/Xm.h
// ----------------------------------------------------------------------------
// common callbacks
// ----------------------------------------------------------------------------
#if 0
// All widgets should have this as their resize proc.
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 *);
#endif
// ----------------------------------------------------------------------------
// we maintain a hash table which contains the mapping from Widget to wxWindow
// corresponding to the window for this widget
// ----------------------------------------------------------------------------
extern void wxDeleteWindowFromTable(Widget w);
extern wxWindow *wxGetWindowFromTable(Widget w);
extern bool wxAddWindowToTable(Widget w, wxWindow *win);
extern void wxDeleteWindowFromTable(Window w);
extern wxWindow *wxGetWindowFromTable(Window w);
extern bool wxAddWindowToTable(Window w, wxWindow *win);
// ----------------------------------------------------------------------------
// key events related functions
@@ -46,7 +45,7 @@ extern bool wxAddWindowToTable(Widget w, wxWindow *win);
extern char wxFindMnemonic(const char* s);
extern char * wxFindAccelerator (const char *s);
extern XmString wxFindAcceleratorText (const char *s);
//extern XmString wxFindAcceleratorText (const char *s);
extern int wxCharCodeXToWX(KeySym keySym);
extern KeySym wxCharCodeWXToX(int id);
@@ -54,8 +53,8 @@ extern KeySym wxCharCodeWXToX(int id);
// ----------------------------------------------------------------------------
// 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 bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Window window, XEvent *xevent);
extern bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win, Window window, XEvent *xevent);
int wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap);
Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap );
@@ -78,43 +77,11 @@ extern XColor itemColors[5] ;
#define wxTOPS_INDEX 3
#define wxBOTS_INDEX 4
// ----------------------------------------------------------------------------
// utility classes
// ----------------------------------------------------------------------------
// XmString made easy to use in wxWindows (and has an added benefit of
// cleaning up automatically)
class wxXmString
{
public:
wxXmString(const wxString& str)
{
m_string = XmStringCreateLtoR((char *)str.c_str(),
XmSTRING_DEFAULT_CHARSET);
}
~wxXmString() { XmStringFree(m_string); }
// semi-implicit conversion to XmString (shouldn't rely on implicit
// conversion because many of Motif functions are macros)
XmString operator()() const { return m_string; }
private:
XmString m_string;
};
// ----------------------------------------------------------------------------
// macros to avoid casting WXFOO to Foo all the time
// ----------------------------------------------------------------------------
// argument is of type "wxWindow *"
#define GetWidget(w) ((Widget)(w)->GetHandle())
// ----------------------------------------------------------------------------
// accessors for C modules
// ----------------------------------------------------------------------------
extern "C" XtAppContext wxGetAppContext();
// extern "C" XtAppContext wxGetAppContext();
#endif
// _WX_PRIVATE_H_

View File

@@ -1,134 +1,101 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/motif/frame.h
// Purpose: wxFrame class
///////////////////////////////////////////////////////////////////////////////
// Name: wx/x11/toplevel.h
// Purpose: wxTopLevelWindowX11 is the X11 implementation of wxTLW
// Author: Julian Smart
// Modified by:
// Created: 17/09/98
// Created: 20.09.01
// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Copyright: (c) 2002 Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_MOTIF_FRAME_H_
#define _WX_MOTIF_FRAME_H_
#ifndef _WX_X11_TOPLEVEL_H_
#define _WX_X11_TOPLEVEL_H_
#ifdef __GNUG__
#pragma interface "frame.h"
#pragma interface "toplevel.h"
#endif
class WXDLLEXPORT wxFrame : public wxFrameBase
// ----------------------------------------------------------------------------
// wxTopLevelWindowX11
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxTopLevelWindowX11 : public wxTopLevelWindowBase
{
public:
wxFrame() { Init(); }
wxFrame(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = wxFrameNameStr)
// constructors and such
wxTopLevelWindowX11() { Init(); }
wxTopLevelWindowX11(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = wxFrameNameStr)
{
Init();
Create(parent, id, title, pos, size, style, name);
(void)Create(parent, id, title, pos, size, style, name);
}
bool Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = wxFrameNameStr);
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = wxFrameNameStr);
virtual ~wxFrame();
virtual ~wxTopLevelWindowX11();
// implement base class pure virtuals
virtual void Maximize(bool maximize = TRUE);
virtual bool IsMaximized() const;
virtual void Iconize(bool iconize = TRUE);
virtual bool IsIconized() const;
virtual void SetIcon(const wxIcon& icon);
virtual void Restore();
virtual bool Show(bool show = TRUE);
// Set menu bar
void SetMenuBar(wxMenuBar *menu_bar);
virtual bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL);
virtual bool IsFullScreen() const { return m_fsIsShowing; }
// Set title
void SetTitle(const wxString& title);
wxString GetTitle() const { return m_title; }
// Set icon
virtual void SetIcon(const wxIcon& icon);
#if wxUSE_STATUSBAR
virtual void PositionStatusBar();
#endif // wxUSE_STATUSBAR
// Create toolbar
#if wxUSE_TOOLBAR
virtual wxToolBar* CreateToolBar(long style = wxNO_BORDER|wxTB_HORIZONTAL, wxWindowID id = -1, const wxString& name = wxToolBarNameStr);
virtual void PositionToolBar();
#endif // wxUSE_TOOLBAR
// Iconize
virtual void Iconize(bool iconize);
virtual bool IsIconized() const;
// Is the frame maximized? Returns FALSE under Motif (but TRUE for
// wxMDIChildFrame due to the tabbed implementation).
virtual bool IsMaximized() const;
virtual void Maximize(bool maximize);
virtual void Raise();
virtual void Lower();
virtual void Restore();
// Implementation only from now on
// -------------------------------
void OnSysColourChanged(wxSysColourChangedEvent& event);
void OnActivate(wxActivateEvent& event);
virtual void ChangeFont(bool keepOriginalSize = TRUE);
virtual void ChangeBackgroundColour();
virtual void ChangeForegroundColour();
WXWidget GetMenuBarWidget() const;
WXWidget GetShellWidget() const { return m_frameShell; }
WXWidget GetWorkAreaWidget() const { return m_workArea; }
WXWidget GetClientAreaWidget() const { return m_clientArea; }
WXWidget GetTopWidget() const { return m_frameShell; }
virtual WXWidget GetMainWidget() const { return m_frameWidget; }
// The widget that can have children on it
WXWidget GetClientWidget() const;
bool GetVisibleStatus() const { return m_visibleStatus; }
bool PreResize();
// implementation from now on
// --------------------------
protected:
// common part of all ctors
void Init();
//// Motif-specific
WXWidget m_frameShell;
WXWidget m_frameWidget;
WXWidget m_workArea;
WXWidget m_clientArea;
wxString m_title;
bool m_visibleStatus;
bool m_iconized;
// create a new frame, return FALSE if it couldn't be created
bool CreateFrame(const wxString& title,
const wxPoint& pos,
const wxSize& size);
virtual void DoGetClientSize(int *width, int *height) const;
virtual void DoGetSize(int *width, int *height) const;
virtual void DoGetPosition(int *x, int *y) const;
virtual void DoSetSize(int x, int y,
int width, int height,
int sizeFlags = wxSIZE_AUTO);
virtual void DoSetClientSize(int width, int height);
// create a new dialog using the given dialog template from resources,
// return FALSE if it couldn't be created
bool CreateDialog(const wxString& title,
const wxPoint& pos,
const wxSize& size);
private:
DECLARE_EVENT_TABLE()
DECLARE_DYNAMIC_CLASS(wxFrame)
// is the frame currently iconized?
bool m_iconized;
// should the frame be maximized when it will be shown? set by Maximize()
// when it is called while the frame is hidden
bool m_maximizeOnShow;
// Data to save/restore when calling ShowFullScreen
long m_fsStyle; // Passed to ShowFullScreen
wxRect m_fsOldSize;
bool m_fsIsMaximized;
bool m_fsIsShowing;
};
#endif
// _WX_MOTIF_FRAME_H_
// list of all frames and modeless dialogs
;; extern WXDLLEXPORT_DATA(wxWindowList) wxModelessWindows;
#endif // _WX_X11_TOPLEVEL_H_

View File

@@ -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,45 +273,14 @@ 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.
@@ -317,85 +288,153 @@ void wxApp::ProcessXEvent(WXEvent* _event)
{
XEvent* event = (XEvent*) _event;
if (event->type == KeyPress)
{
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
{
// 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.
*/
wxWindow* win = NULL;
Window window = event->xany.window;
Window actualWindow = window;
Display *disp = wxGetDisplay();
Window win = event->xany.window;
XEvent report;
// 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);
// 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.
// TODO: generate resize event
// XtDispatchEvent(event);
}
else
// TODO: shouldn't all the ProcessEvents below
// be win->GetEventHandler()->ProcessEvent?
switch (event->type)
{
// TODO: generate all other events
// XtDispatchEvent(event);
case KeyPress:
{
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);
// 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);
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.
*/
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;

222
src/x11/evtloop.cpp Normal file
View File

@@ -0,0 +1,222 @@
///////////////////////////////////////////////////////////////////////////////
// Name: x11/evtloop.cpp
// Purpose: implements wxEventLoop for X11
// Author: Julian Smart
// Modified by:
// Created: 01.06.01
// RCS-ID: $Id$
// Copyright: (c) 2002 Julian Smart
// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "evtloop.h"
#endif
#include "wx/window.h"
#include "wx/app.h"
#include "wx/evtloop.h"
#include "wx/tooltip.h"
#include "wx/x11/private.h"
#include "X11/Xlib.h"
// ----------------------------------------------------------------------------
// wxEventLoopImpl
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxEventLoopImpl
{
public:
// ctor
wxEventLoopImpl() { SetExitCode(0); m_keepGoing = FALSE; }
// process an XEvent
void ProcessEvent(XEvent* event);
// generate an idle message, return TRUE if more idle time requested
bool SendIdleEvent();
// set/get the exit code
void SetExitCode(int exitcode) { m_exitcode = exitcode; }
int GetExitCode() const { return m_exitcode; }
public:
// preprocess an event, return TRUE if processed (i.e. no further
// dispatching required)
bool PreProcessMessage(XEvent* event);
// the exit code of the event loop
int m_exitcode;
bool m_keepGoing;
};
// ============================================================================
// wxEventLoopImpl implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxEventLoopImpl message processing
// ----------------------------------------------------------------------------
void wxEventLoopImpl::ProcessEvent(XEvent *event)
{
// give us the chance to preprocess the message first
if ( !PreProcessEvent(event) )
{
// if it wasn't done, dispatch it to the corresponding window
if (wxTheApp)
wxTheApp->ProcessXEvent((WXEvent*) event);
}
}
bool wxEventLoopImpl::PreProcessEvent(XEvent *event)
{
// TODO
#if 0
HWND hWnd = msg->hwnd;
wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd);
// try translations first; find the youngest window with a translation
// table.
wxWindow *wnd;
for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
{
if ( wnd->MSWTranslateMessage((WXMSG *)msg) )
return TRUE;
}
// Anyone for a non-translation message? Try youngest descendants first.
for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
{
if ( wnd->MSWProcessMessage((WXMSG *)msg) )
return TRUE;
}
#endif
return FALSE;
}
// ----------------------------------------------------------------------------
// wxEventLoopImpl idle event processing
// ----------------------------------------------------------------------------
bool wxEventLoopImpl::SendIdleEvent()
{
wxIdleEvent event;
event.SetEventObject(wxTheApp);
return wxTheApp->ProcessEvent(event) && event.MoreRequested();
}
// ============================================================================
// wxEventLoop implementation
// ============================================================================
wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
// ----------------------------------------------------------------------------
// wxEventLoop running and exiting
// ----------------------------------------------------------------------------
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") );
m_impl = new wxEventLoopImpl;
wxEventLoop *oldLoop = ms_activeLoop;
ms_activeLoop = this;
m_impl->m_keepGoing = TRUE;
while ( m_impl->m_keepGoing )
{
#if wxUSE_THREADS
wxMutexGuiLeaveOrEnter();
#endif // wxUSE_THREADS
// generate and process idle events for as long as we don't have
// anything else to do
while ( ! Pending() )
{
if (!m_impl->SendIdleEvent())
{
#if wxUSE_THREADS
// leave the main loop to give other threads a chance to
// perform their GUI work
wxMutexGuiLeave();
wxUsleep(20);
wxMutexGuiEnter();
#endif
// Break out of while loop
break;
}
}
// a message came or no more idle processing to do, sit in Dispatch()
// waiting for the next message
if ( !Dispatch() )
{
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->m_keepGoing = FALSE;
}
// ----------------------------------------------------------------------------
// wxEventLoop message processing dispatching
// ----------------------------------------------------------------------------
bool wxEventLoop::Pending() const
{
XFlush(wxGetDisplay());
return (XPending(wxGetDisplay()) > 0);
}
bool wxEventLoop::Dispatch()
{
XEvent event;
// TODO allowing for threads, as per e.g. wxMSW
XNextEvent(wxGetDisplay(), & event);
m_impl->ProcessEvent(& event);
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -61,22 +61,6 @@ static const int SCROLL_MARGIN = 4;
extern wxHashTable *wxWidgetHashTable;
static wxWindow* g_captureWindow = NULL;
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
static void wxCanvasRepaintProc(Widget, XtPointer, XmDrawingAreaCallbackStruct * cbs);
static void wxCanvasInputEvent(Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs);
static void wxCanvasMotionEvent(Widget, XButtonEvent * event);
static void wxCanvasEnterLeave(Widget drawingArea, XtPointer clientData, XCrossingEvent * event);
static void wxScrollBarCallback(Widget widget, XtPointer clientData,
XmScrollBarCallbackStruct *cbs);
static void wxPanelItemEventHandler(Widget wid,
XtPointer client_data,
XEvent* event,
Boolean *continueToDispatch);
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
@@ -1583,401 +1567,8 @@ WXWindow wxWindowX11::GetLabelWindow() const
// callbacks
// ----------------------------------------------------------------------------
// TODO
// TODO: implement wxWindow scrollbar, presumably using wxScrollBar
#if 0
// All widgets should have this as their resize proc.
// OnSize sent to wxWindow via client data.
void wxWidgetResizeProc(Widget w, XConfigureEvent *WXUNUSED(event), String WXUNUSED(args)[], int *WXUNUSED(num_args))
{
wxWindow *win = wxGetWindowFromTable(w);
if (!win)
return;
if (win->PreResize())
{
int width, height;
win->GetSize(&width, &height);
wxSizeEvent sizeEvent(wxSize(width, height), win->GetId());
sizeEvent.SetEventObject(win);
win->GetEventHandler()->ProcessEvent(sizeEvent);
}
}
static void wxCanvasRepaintProc(Widget drawingArea,
XtPointer clientData,
XmDrawingAreaCallbackStruct * cbs)
{
if (!wxGetWindowFromTable(drawingArea))
return;
XEvent * event = cbs->event;
wxWindow * win = (wxWindow *) clientData;
switch (event->type)
{
case Expose:
{
win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
if (event -> xexpose.count == 0)
{
win->DoPaint();
win->ClearUpdateRects();
}
break;
}
}
}
// Unable to deal with Enter/Leave without a separate EventHandler (Motif 1.1.4)
static void wxCanvasEnterLeave(Widget drawingArea,
XtPointer WXUNUSED(clientData),
XCrossingEvent * event)
{
XmDrawingAreaCallbackStruct cbs;
XEvent ev;
((XCrossingEvent &) ev) = *event;
cbs.reason = XmCR_INPUT;
cbs.event = &ev;
wxCanvasInputEvent(drawingArea, (XtPointer) NULL, &cbs);
}
// Fix to make it work under Motif 1.0 (!)
static void wxCanvasMotionEvent (Widget WXUNUSED(drawingArea), XButtonEvent * WXUNUSED(event))
{
#if XmVersion <= 1000
XmDrawingAreaCallbackStruct cbs;
XEvent ev;
ev = *((XEvent *) event);
cbs.reason = XmCR_INPUT;
cbs.event = &ev;
wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs);
#endif // XmVersion <= 1000
}
static void wxCanvasInputEvent(Widget drawingArea,
XtPointer WXUNUSED(data),
XmDrawingAreaCallbackStruct * cbs)
{
wxWindow *canvas = wxGetWindowFromTable(drawingArea);
XEvent local_event;
if (canvas==NULL)
return;
if (cbs->reason != XmCR_INPUT)
return;
local_event = *(cbs->event); // We must keep a copy!
switch (local_event.xany.type)
{
case EnterNotify:
case LeaveNotify:
case ButtonPress:
case ButtonRelease:
case MotionNotify:
{
// FIXME: most of this mouse event code is more or less
// duplicated in wxTranslateMouseEvent
//
wxEventType eventType = wxEVT_NULL;
if (local_event.xany.type == EnterNotify)
{
//if (local_event.xcrossing.mode!=NotifyNormal)
// return ; // Ignore grab events
eventType = wxEVT_ENTER_WINDOW;
// canvas->GetEventHandler()->OnSetFocus();
}
else if (local_event.xany.type == LeaveNotify)
{
//if (local_event.xcrossingr.mode!=NotifyNormal)
// return ; // Ignore grab events
eventType = wxEVT_LEAVE_WINDOW;
// canvas->GetEventHandler()->OnKillFocus();
}
else if (local_event.xany.type == MotionNotify)
{
eventType = wxEVT_MOTION;
}
else if (local_event.xany.type == ButtonPress)
{
if (local_event.xbutton.button == Button1)
{
eventType = wxEVT_LEFT_DOWN;
canvas->SetButton1(TRUE);
}
else if (local_event.xbutton.button == Button2)
{
eventType = wxEVT_MIDDLE_DOWN;
canvas->SetButton2(TRUE);
}
else if (local_event.xbutton.button == Button3)
{
eventType = wxEVT_RIGHT_DOWN;
canvas->SetButton3(TRUE);
}
}
else if (local_event.xany.type == ButtonRelease)
{
if (local_event.xbutton.button == Button1)
{
eventType = wxEVT_LEFT_UP;
canvas->SetButton1(FALSE);
}
else if (local_event.xbutton.button == Button2)
{
eventType = wxEVT_MIDDLE_UP;
canvas->SetButton2(FALSE);
}
else if (local_event.xbutton.button == Button3)
{
eventType = wxEVT_RIGHT_UP;
canvas->SetButton3(FALSE);
}
}
wxMouseEvent wxevent (eventType);
wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
|| (event_left_is_down (&local_event)
&& (eventType != wxEVT_LEFT_UP)));
wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN)
|| (event_middle_is_down (&local_event)
&& (eventType != wxEVT_MIDDLE_UP)));
wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN)
|| (event_right_is_down (&local_event)
&& (eventType != wxEVT_RIGHT_UP)));
wxevent.m_shiftDown = local_event.xbutton.state & ShiftMask;
wxevent.m_controlDown = local_event.xbutton.state & ControlMask;
wxevent.m_altDown = local_event.xbutton.state & Mod3Mask;
wxevent.m_metaDown = local_event.xbutton.state & Mod1Mask;
wxevent.SetTimestamp(local_event.xbutton.time);
if ( eventType == wxEVT_MOTION )
{
if (local_event.xmotion.is_hint == NotifyHint)
{
Window root, child;
Display *dpy = XtDisplay (drawingArea);
XQueryPointer (dpy, XtWindow (drawingArea),
&root, &child,
&local_event.xmotion.x_root,
&local_event.xmotion.y_root,
&local_event.xmotion.x,
&local_event.xmotion.y,
&local_event.xmotion.state);
}
else
{
}
}
// Now check if we need to translate this event into a double click
if (TRUE) // canvas->doubleClickAllowed)
{
if (wxevent.ButtonDown())
{
long dclickTime = XtGetMultiClickTime((Display*) wxGetDisplay());
// get button and time-stamp
int button = 0;
if (wxevent.LeftDown())
button = 1;
else if (wxevent.MiddleDown())
button = 2;
else if (wxevent.RightDown())
button = 3;
long ts = wxevent.GetTimestamp();
// check, if single or double click
int buttonLast = canvas->GetLastClickedButton();
long lastTS = canvas->GetLastClickTime();
if ( buttonLast && buttonLast == button && (ts - lastTS) < dclickTime )
{
// I have a dclick
canvas->SetLastClick(0, ts);
wxEventType typeDouble;
if ( eventType == wxEVT_LEFT_DOWN )
typeDouble = wxEVT_LEFT_DCLICK;
else if ( eventType == wxEVT_MIDDLE_DOWN )
typeDouble = wxEVT_MIDDLE_DCLICK;
else if ( eventType == wxEVT_RIGHT_DOWN )
typeDouble = wxEVT_RIGHT_DCLICK;
else
typeDouble = wxEVT_NULL;
if ( typeDouble != wxEVT_NULL )
{
wxevent.SetEventType(typeDouble);
}
}
else
{
// not fast enough or different button
canvas->SetLastClick(button, ts);
}
}
}
wxevent.SetId(canvas->GetId());
wxevent.SetEventObject(canvas);
wxevent.m_x = local_event.xbutton.x;
wxevent.m_y = local_event.xbutton.y;
canvas->GetEventHandler()->ProcessEvent (wxevent);
#if 0
if (eventType == wxEVT_ENTER_WINDOW ||
eventType == wxEVT_LEAVE_WINDOW ||
eventType == wxEVT_MOTION
)
return;
#endif // 0
break;
}
case KeyPress:
{
KeySym keySym;
#if 0
XComposeStatus compose;
(void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, &compose);
#endif // 0
(void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, NULL);
int id = wxCharCodeXToWX (keySym);
wxEventType eventType = wxEVT_CHAR;
wxKeyEvent event (eventType);
if (local_event.xkey.state & ShiftMask)
event.m_shiftDown = TRUE;
if (local_event.xkey.state & ControlMask)
event.m_controlDown = TRUE;
if (local_event.xkey.state & Mod3Mask)
event.m_altDown = TRUE;
if (local_event.xkey.state & Mod1Mask)
event.m_metaDown = TRUE;
event.SetEventObject(canvas);
event.m_keyCode = id;
event.SetTimestamp(local_event.xkey.time);
if (id > -1)
{
// Implement wxFrame::OnCharHook by checking ancestor.
wxWindow *parent = canvas->GetParent();
while (parent && !parent->IsKindOf(CLASSINFO(wxFrame)))
parent = parent->GetParent();
if (parent)
{
event.SetEventType(wxEVT_CHAR_HOOK);
if (parent->GetEventHandler()->ProcessEvent(event))
return;
}
// For simplicity, OnKeyDown is the same as OnChar
// TODO: filter modifier key presses from OnChar
event.SetEventType(wxEVT_KEY_DOWN);
// Only process OnChar if OnKeyDown didn't swallow it
if (!canvas->GetEventHandler()->ProcessEvent (event))
{
event.SetEventType(wxEVT_CHAR);
canvas->GetEventHandler()->ProcessEvent (event);
}
}
break;
}
case KeyRelease:
{
KeySym keySym;
(void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, NULL);
int id = wxCharCodeXToWX (keySym);
wxKeyEvent event (wxEVT_KEY_UP);
if (local_event.xkey.state & ShiftMask)
event.m_shiftDown = TRUE;
if (local_event.xkey.state & ControlMask)
event.m_controlDown = TRUE;
if (local_event.xkey.state & Mod3Mask)
event.m_altDown = TRUE;
if (local_event.xkey.state & Mod1Mask)
event.m_metaDown = TRUE;
event.SetEventObject(canvas);
event.m_keyCode = id;
event.SetTimestamp(local_event.xkey.time);
if (id > -1)
{
canvas->GetEventHandler()->ProcessEvent (event);
}
break;
}
case FocusIn:
{
if (local_event.xfocus.detail != NotifyPointer)
{
wxFocusEvent event(wxEVT_SET_FOCUS, canvas->GetId());
event.SetEventObject(canvas);
canvas->GetEventHandler()->ProcessEvent(event);
}
break;
}
case FocusOut:
{
if (local_event.xfocus.detail != NotifyPointer)
{
wxFocusEvent event(wxEVT_KILL_FOCUS, canvas->GetId());
event.SetEventObject(canvas);
canvas->GetEventHandler()->ProcessEvent(event);
}
break;
}
default:
break;
}
}
static void wxPanelItemEventHandler(Widget wid,
XtPointer WXUNUSED(client_data),
XEvent* event,
Boolean *continueToDispatch)
{
// Widget can be a label or the actual widget.
wxWindow *window = wxGetWindowFromTable(wid);
if (window)
{
wxMouseEvent wxevent(0);
if (wxTranslateMouseEvent(wxevent, window, wid, event))
{
window->GetEventHandler()->ProcessEvent(wxevent);
}
}
// TODO: probably the key to allowing default behaviour to happen. Say we
// set a m_doDefault flag to FALSE at the start of this function. Then in
// e.g. wxWindowX11::OnMouseEvent we can call Default() which sets this flag to
// TRUE, indicating that default processing can happen. Thus, behaviour can
// appear to be overridden just by adding an event handler and not calling
// wxWindowX11::OnWhatever. ALSO, maybe we can use this instead of the current
// way of handling drawing area events, to simplify things.
*continueToDispatch = True;
}
static void wxScrollBarCallback(Widget scrollbar,
XtPointer clientData,
XmScrollBarCallbackStruct *cbs)
@@ -2043,43 +1634,8 @@ static void wxScrollBarCallback(Widget scrollbar,
event.SetEventObject( win );
win->GetEventHandler()->ProcessEvent(event);
}
// For repainting arbitrary windows
void wxUniversalRepaintProc(Widget w, XtPointer WXUNUSED(c_data), XEvent *event, char *)
{
Window window;
Display *display;
wxWindow* win = wxGetWindowFromTable(w);
if (!win)
return;
switch(event -> type)
{
case Expose:
{
window = (Window) win -> GetXWindow();
display = (Display *) win -> GetXDisplay();
if (event -> xexpose.count == 0)
{
win->DoPaint();
win->ClearUpdateRects();
}
else
{
win->AddUpdateRect(event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
}
break;
}
}
}
#endif
// 0
// ----------------------------------------------------------------------------
// CanvaseXXXSize() functions
@@ -2291,28 +1847,31 @@ void wxWindowX11::CanvasGetPosition (int *x, int *y) const
// TranslateXXXEvent() functions
// ----------------------------------------------------------------------------
bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Widget widget, XEvent *xevent)
bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Window window, XEvent *xevent)
{
// TODO
#if 0
switch (xevent->xany.type)
{
case EnterNotify: // never received here - yes ? MB
case LeaveNotify: // never received here - yes ? MB
case EnterNotify:
case LeaveNotify:
case ButtonPress:
case ButtonRelease:
case MotionNotify:
{
wxEventType eventType = wxEVT_NULL;
// FIXME: this is never true I think - MB
//
if (xevent->xany.type == LeaveNotify)
if (xevent->xany.type == EnterNotify)
{
win->SetButton1(FALSE);
win->SetButton2(FALSE);
win->SetButton3(FALSE);
return FALSE;
//if (local_event.xcrossing.mode!=NotifyNormal)
// return ; // Ignore grab events
eventType = wxEVT_ENTER_WINDOW;
// canvas->GetEventHandler()->OnSetFocus();
}
else if (xevent->xany.type == LeaveNotify)
{
//if (local_event.xcrossingr.mode!=NotifyNormal)
// return ; // Ignore grab events
eventType = wxEVT_LEAVE_WINDOW;
// canvas->GetEventHandler()->OnKillFocus();
}
else if (xevent->xany.type == MotionNotify)
{
@@ -2342,8 +1901,9 @@ bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Widget widget,
}
// check for a double click
//
long dclickTime = XtGetMultiClickTime((Display*) wxGetDisplay());
// TODO: where can we get this value from?
//long dclickTime = XtGetMultiClickTime((Display*) wxGetDisplay());
long dClickTime = 200;
long ts = wxevent.GetTimestamp();
int buttonLast = win->GetLastClickedButton();
@@ -2391,25 +1951,8 @@ bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Widget widget,
wxevent.SetEventType(eventType);
Position x1, y1;
XtVaGetValues(widget, XmNx, &x1, XmNy, &y1, NULL);
int x2, y2;
win->GetPosition(&x2, &y2);
// The button x/y must be translated to wxWindows
// window space - the widget might be a label or button,
// within a form.
int dx = 0;
int dy = 0;
if (widget != (Widget)win->GetMainWidget())
{
dx = x1;
dy = y1;
}
wxevent.m_x = xevent->xbutton.x + dx;
wxevent.m_y = xevent->xbutton.y + dy;
wxevent.m_x = xevent->xbutton.x;
wxevent.m_y = xevent->xbutton.y;
wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
|| (event_left_is_down (xevent)
@@ -2432,7 +1975,6 @@ bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Widget widget,
return TRUE;
}
}
#endif
return FALSE;
}