added wxEVT_MOUSE_CAPTURE_LOST event and code for correctly handling capture loss (bug #1153662)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@40391 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2006-07-31 09:27:54 +00:00
parent f9c240ec1e
commit 63e819f298
10 changed files with 184 additions and 11 deletions

View File

@@ -257,6 +257,7 @@ An event object contains information about a specific event. Event handlers
\twocolitem{\helpref{wxMaximizeEvent}{wxmaximizeevent}}{A maximize event}
\twocolitem{\helpref{wxMenuEvent}{wxmenuevent}}{A menu event}
\twocolitem{\helpref{wxMouseCaptureChangedEvent}{wxmousecapturechangedevent}}{A mouse capture changed event}
\twocolitem{\helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}}{A mouse capture lost event}
\twocolitem{\helpref{wxMouseEvent}{wxmouseevent}}{A mouse event}
\twocolitem{\helpref{wxMoveEvent}{wxmoveevent}}{A move event}
\twocolitem{\helpref{wxNotebookEvent}{wxnotebookevent}}{A notebook control event}

View File

@@ -29,6 +29,7 @@ function that takes a wxMouseCaptureChangedEvent argument.
\wxheading{See also}
\helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}
\helpref{Event handling overview}{eventhandlingoverview},
\helpref{wxWindow::CaptureMouse}{wxwindowcapturemouse},
\helpref{wxWindow::ReleaseMouse}{wxwindowreleasemouse},
@@ -48,3 +49,51 @@ Constructor.
Returns the window that gained the capture, or NULL if it was a non-wxWidgets window.
\section{\class{wxMouseCaptureLostEvent}}\label{wxmousecapturelostevent}
An mouse capture lost event is sent to a window that obtained mouse capture,
which was subsequently loss due to "external" event, for example when a dialog
box is shown or if another application captures the mouse.
If this happens, this event is sent to all windows that are on capture stack
(i.e. called CaptureMouse, but didn't call ReleaseMouse yet). The event is
{\em not} sent if the capture changes because of a call to CaptureMouse or
ReleaseMouse.
This event is currently emitted under Windows only.
\wxheading{Derived from}
\helpref{wxEvent}{wxevent}\\
\helpref{wxObject}{wxobject}
\wxheading{Include files}
<wx/event.h>
\wxheading{Event table macros}
To process this event, use the following event handler macro to direct input to
a member function that takes a wxMouseCaptureLostEvent argument.
\twocolwidtha{7cm}
\begin{twocollist}\itemsep=0pt
\twocolitem{{\bf EVT\_MOUSE\_CAPTURE\_LOST(func)}}{Process a wxEVT\_MOUSE\_CAPTURE\_LOST event.}
\end{twocollist}
\wxheading{See also}
\helpref{wxMouseCaptureChangedEvent}{wxmousecapturechangedevent}
\helpref{Event handling overview}{eventhandlingoverview},
\helpref{wxWindow::CaptureMouse}{wxwindowcapturemouse},
\helpref{wxWindow::ReleaseMouse}{wxwindowreleasemouse},
\helpref{wxWindow::GetCapture}{wxwindowgetcapture}
\latexignore{\rtfignore{\wxheading{Members}}}
\membersection{wxMouseCaptureLostEvent::wxMouseCaptureLostEvent}\label{wxmousecapturelosteventctor}
\func{}{wxMouseCaptureLostEvent}{\param{wxWindowID }{windowId = 0}}
Constructor.

View File

@@ -203,11 +203,18 @@ Note that wxWidgets maintains the stack of windows having captured the mouse
and when the mouse is released the capture returns to the window which had had
captured it previously and it is only really released if there were no previous
window. In particular, this means that you must release the mouse as many times
as you capture it.
as you capture it, unless the window receives
the \helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent} event.
Any application which captures the mouse in the beginning of some operation
{\em must} handle \helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}
and cancel this operation when it receives the event. The event handler must
not recapture mouse.
\wxheading{See also}
\helpref{wxWindow::ReleaseMouse}{wxwindowreleasemouse}
\helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}
\membersection{wxWindow::Center}\label{wxwindowcenter}
@@ -787,6 +794,7 @@ Returns the currently captured window.
\helpref{wxWindow::HasCapture}{wxwindowhascapture},
\helpref{wxWindow::CaptureMouse}{wxwindowcapturemouse},
\helpref{wxWindow::ReleaseMouse}{wxwindowreleasemouse},
\helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}
\helpref{wxMouseCaptureChangedEvent}{wxmousecapturechangedevent}
@@ -1390,6 +1398,7 @@ Returns {\tt true} if this window has the current mouse capture.
\helpref{wxWindow::CaptureMouse}{wxwindowcapturemouse},
\helpref{wxWindow::ReleaseMouse}{wxwindowreleasemouse},
\helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}
\helpref{wxMouseCaptureChangedEvent}{wxmousecapturechangedevent}
@@ -2361,6 +2370,7 @@ Releases mouse input captured with \helpref{wxWindow::CaptureMouse}{wxwindowcapt
\helpref{wxWindow::CaptureMouse}{wxwindowcapturemouse},
\helpref{wxWindow::HasCapture}{wxwindowhascapture},
\helpref{wxWindow::ReleaseMouse}{wxwindowreleasemouse},
\helpref{wxMouseCaptureLostEvent}{wxmousecapturelostevent}
\helpref{wxMouseCaptureChangedEvent}{wxmousecapturechangedevent}

View File

@@ -238,14 +238,14 @@ BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_ICONIZE, 413)
DECLARE_EVENT_TYPE(wxEVT_MAXIMIZE, 414)
DECLARE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED, 415)
DECLARE_EVENT_TYPE(wxEVT_PAINT, 416)
DECLARE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND, 417)
DECLARE_EVENT_TYPE(wxEVT_NC_PAINT, 418)
DECLARE_EVENT_TYPE(wxEVT_PAINT_ICON, 419)
DECLARE_EVENT_TYPE(wxEVT_MENU_OPEN, 420)
DECLARE_EVENT_TYPE(wxEVT_MENU_CLOSE, 421)
DECLARE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT, 422)
// DECLARE_EVENT_TYPE(wxEVT_POPUP_MENU_INIT, 423) -- free slot
DECLARE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST, 416)
DECLARE_EVENT_TYPE(wxEVT_PAINT, 417)
DECLARE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND, 418)
DECLARE_EVENT_TYPE(wxEVT_NC_PAINT, 419)
DECLARE_EVENT_TYPE(wxEVT_PAINT_ICON, 420)
DECLARE_EVENT_TYPE(wxEVT_MENU_OPEN, 421)
DECLARE_EVENT_TYPE(wxEVT_MENU_CLOSE, 422)
DECLARE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT, 423)
DECLARE_EVENT_TYPE(wxEVT_CONTEXT_MENU, 424)
DECLARE_EVENT_TYPE(wxEVT_SYS_COLOUR_CHANGED, 425)
DECLARE_EVENT_TYPE(wxEVT_DISPLAY_CHANGED, 426)
@@ -1797,6 +1797,29 @@ private:
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxMouseCaptureChangedEvent)
};
/*
wxEVT_MOUSE_CAPTURE_LOST
The window losing the capture receives this message, unless it released it
it itself or unless wxWindow::CaptureMouse was called on another window
(and so capture will be restored when the new capturer releases it).
*/
class WXDLLIMPEXP_CORE wxMouseCaptureLostEvent : public wxEvent
{
public:
wxMouseCaptureLostEvent(wxWindowID winid = 0)
: wxEvent(winid, wxEVT_MOUSE_CAPTURE_LOST)
{}
wxMouseCaptureLostEvent(const wxMouseCaptureLostEvent& event)
: wxEvent(event)
{}
virtual wxEvent *Clone() const { return new wxMouseCaptureLostEvent(*this); }
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxMouseCaptureLostEvent)
};
/*
wxEVT_DISPLAY_CHANGED
*/
@@ -2584,6 +2607,7 @@ typedef void (wxEvtHandler::*wxNotifyEventFunction)(wxNotifyEvent&);
typedef void (wxEvtHandler::*wxHelpEventFunction)(wxHelpEvent&);
typedef void (wxEvtHandler::*wxContextMenuEventFunction)(wxContextMenuEvent&);
typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureChangedEvent&);
typedef void (wxEvtHandler::*wxMouseCaptureLostEventFunction)(wxMouseCaptureLostEvent&);
typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&);
// these typedefs don't have the same name structure as the others, keep for
@@ -2665,6 +2689,8 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxContextMenuEventFunction, &func)
#define wxMouseCaptureChangedEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxMouseCaptureChangedEventFunction, &func)
#define wxMouseCaptureLostEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxMouseCaptureLostEventFunction, &func)
#define wxClipboardTextEventHandler(func) \
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxClipboardTextEventFunction, &func)
@@ -2883,6 +2909,7 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
#define EVT_WINDOW_DESTROY(func) wx__DECLARE_EVT0(wxEVT_DESTROY, wxWindowDestroyEventHandler(func))
#define EVT_SET_CURSOR(func) wx__DECLARE_EVT0(wxEVT_SET_CURSOR, wxSetCursorEventHandler(func))
#define EVT_MOUSE_CAPTURE_CHANGED(func) wx__DECLARE_EVT0(wxEVT_MOUSE_CAPTURE_CHANGED, wxMouseCaptureChangedEventHandler(func))
#define EVT_MOUSE_CAPTURE_LOST(func) wx__DECLARE_EVT0(wxEVT_MOUSE_CAPTURE_LOST, wxMouseCaptureLostEventHandler(func))
// Mouse events
#define EVT_LEFT_DOWN(func) wx__DECLARE_EVT0(wxEVT_LEFT_DOWN, wxMouseEventHandler(func))

View File

@@ -409,6 +409,7 @@ protected:
void OnCopy(wxCommandEvent& event);
void OnMouseEnter(wxMouseEvent& event);
void OnMouseLeave(wxMouseEvent& event);
void OnMouseCaptureLost(wxMouseCaptureLostEvent& event);
#endif // wxUSE_CLIPBOARD
// Returns new filter (will be stored into m_DefaultFilter variable)

View File

@@ -1328,12 +1328,21 @@ protected:
// implements the window variants
virtual void DoSetWindowVariant( wxWindowVariant variant ) ;
// Must be called when mouse capture is lost to send
// wxMouseCaptureLostEvent to windows on capture stack. The argument is
// the window gaining capture or NULL if outside of wx code or none.
static void NotifyCaptureLost(wxWindow *gainedCapture);
private:
// contains the last id generated by NewControlId
static int ms_lastControlId;
// the stack of windows which have captured the mouse
static struct WXDLLEXPORT wxWindowNext *ms_winCaptureNext;
// the window that currently has mouse capture
static wxWindow *ms_winCaptureCurrent;
// indicates if execution is inside CaptureMouse/ReleaseMouse
static bool ms_winCaptureChanging;
DECLARE_ABSTRACT_CLASS(wxWindowBase)
DECLARE_NO_COPY_CLASS(wxWindowBase)

View File

@@ -87,6 +87,7 @@
IMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent)
#endif // wxUSE_GUI
@@ -260,6 +261,7 @@ DEFINE_EVENT_TYPE(wxEVT_SHOW)
DEFINE_EVENT_TYPE(wxEVT_ICONIZE)
DEFINE_EVENT_TYPE(wxEVT_MAXIMIZE)
DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED)
DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST)
DEFINE_EVENT_TYPE(wxEVT_PAINT)
DEFINE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND)
DEFINE_EVENT_TYPE(wxEVT_NC_PAINT)

View File

@@ -2334,11 +2334,17 @@ struct WXDLLEXPORT wxWindowNext
wxWindow *win;
wxWindowNext *next;
} *wxWindowBase::ms_winCaptureNext = NULL;
wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL;
bool wxWindowBase::ms_winCaptureChanging = false;
void wxWindowBase::CaptureMouse()
{
wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this));
wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") );
ms_winCaptureChanging = true;
wxWindow *winOld = GetCapture();
if ( winOld )
{
@@ -2353,19 +2359,28 @@ void wxWindowBase::CaptureMouse()
//else: no mouse capture to save
DoCaptureMouse();
ms_winCaptureCurrent = (wxWindow*)this;
ms_winCaptureChanging = false;
}
void wxWindowBase::ReleaseMouse()
{
wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this));
wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") );
wxASSERT_MSG( GetCapture() == this, wxT("attempt to release mouse, but this window hasn't captured it") );
ms_winCaptureChanging = true;
DoReleaseMouse();
ms_winCaptureCurrent = NULL;
if ( ms_winCaptureNext )
{
((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse();
ms_winCaptureCurrent = ms_winCaptureNext->win;
wxWindowNext *item = ms_winCaptureNext;
ms_winCaptureNext = item->next;
@@ -2373,11 +2388,51 @@ void wxWindowBase::ReleaseMouse()
}
//else: stack is empty, no previous capture
ms_winCaptureChanging = false;
wxLogTrace(_T("mousecapture"),
(const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"),
wx_static_cast(void*, GetCapture()));
}
static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
{
wxMouseCaptureLostEvent event(win->GetId());
event.SetEventObject(win);
bool processed = win->GetEventHandler()->ProcessEvent(event);
wxASSERT_MSG( processed,
_T("window that captured mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
}
/* static */
void wxWindowBase::NotifyCaptureLost(wxWindow *gainedCapture)
{
// don't do anything if capture lost was expected, i.e. resulted from
// a wx call to ReleaseMouse or CaptureMouse:
if ( ms_winCaptureChanging )
return;
// if the capture was lost unexpectedly, notify every window that has
// capture (on stack or current) about it and clear the stack:
if ( ms_winCaptureCurrent )
{
DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent);
ms_winCaptureCurrent = NULL;
}
while ( ms_winCaptureNext )
{
wxWindowNext *item = ms_winCaptureNext;
ms_winCaptureNext = item->next;
DoNotifyWindowAboutCaptureLost(item->win);
delete item;
}
}
#if wxUSE_HOTKEY
bool

View File

@@ -1135,6 +1135,19 @@ void wxHtmlWindow::OnMouseUp(wxMouseEvent& event)
wxHtmlWindowMouseHelper::HandleMouseClick(m_Cell, pos, event);
}
#if wxUSE_CLIPBOARD
void wxHtmlWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
{
if ( !m_makingSelection )
return;
// discard the selecting operation
m_makingSelection = false;
wxDELETE(m_selection);
m_tmpSelFromCell = NULL;
Refresh();
}
#endif // wxUSE_CLIPBOARD
void wxHtmlWindow::OnInternalIdle()
@@ -1499,6 +1512,7 @@ BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick)
EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter)
EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave)
EVT_MOUSE_CAPTURE_LOST(wxHtmlWindow::OnMouseCaptureLost)
EVT_KEY_UP(wxHtmlWindow::OnKeyUp)
EVT_MENU(wxID_COPY, wxHtmlWindow::OnCopy)
#endif // wxUSE_CLIPBOARD

View File

@@ -4107,9 +4107,14 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
{
wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
event.SetEventObject(this);
wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
// notify windows on the capture stack about lost capture
// (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
wxWindowBase::NotifyCaptureLost(win);
wxMouseCaptureChangedEvent event(GetId(), win);
event.SetEventObject(this);
return GetEventHandler()->ProcessEvent(event);
}