ウィンドウズシャットダウン時のwxWidgetsアプリケーション挙動に関与する部分のソースコードを示す。
本記事はwxWidgetsとシステムシャットダウン(以下、解説記事)で調査したソースコードをまとめる。解説記事はwxAppクラス、wxEventLoopクラス、wxTopLevelWindowクラスを説明するが、記述を簡潔とするため大きく省略し各メンバ関数はそれぞれのクラスで定義されているとした。実際はより複雑でメンバ関数の多くは基底クラスで定義されていて、また仮想メンバ関数のオーバーライドが基底メンバ関数をコール場合もある。本記事はより正確な参照に供すべく各メンバ関数のソースコードを記載するが、解説記事以上の内容は加えない。用語は解説記事に準ずる。
ダウンロードリンク
最新バージョンと過去バージョンは以下リンクからダウンロードできる。本記事調査はバージョン3.2.2.1ソースコードを用いた。
グローバル定義
wxEntry関数
wxEntry関数
[src\msw\main.cpp:169]
int wxEntry(int& argc, wxChar **argv)
{
DisableAutomaticSETranslator();
wxSEH_TRY
{
return wxEntryReal(argc, argv);
}
wxSEH_HANDLE(-1)
}
wxEntryReal関数
wxInitializerクラス[include\wx\init.h:81]はアプリケーションの初期化/終了処理を行うRAIIオブジェクトである。wxInitializerはコンストラクタからいくつかの関数を経由して最終的にはwxEntryStart関数[src\common\init.cpp:290]でライブラリの初期化行い、デストラクタからいくつかの関数を経由して最終的にはwxEntryCleanup関数(実際はwxEntryCleanupReal関数)[src\common\init.cpp:444]でライブラリの終了処理を行う。初期化はwxAppConsole派生のインスタンスであるwxAppConsoleBase::ms_appInstanceスタティックメンバ変数も構築し、終了処理はそれを解体する。
[src\common\int.cpp:475]
int wxEntryReal(int& argc, wxChar **argv)
{
wxInitializer initializer(argc, argv);
if ( !initializer.IsOk() )
{
#if wxUSE_LOG
delete wxLog::SetActiveTarget(NULL);
#endif
return -1;
}
wxTRY
{
if ( !wxTheApp->CallOnInit() )
{
return -1;
}
class CallOnExit
{
public:
~CallOnExit() { wxTheApp->OnExit(); }
} callOnExit;
WX_SUPPRESS_UNUSED_WARN(callOnExit);
return wxTheApp->OnRun();
}
wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
}
wxTheAppインスタンス
wxTheAppインスタンスの実装はwxAppConsoleBase::ms_appInstanceスタティックメンバ変数を返すマクロ定義による。
[include\wx\app.h:785]
#define wxTheApp static_cast<wxApp*>(wxApp::GetInstance())
[include\wx\app.h:73]
class WXDLLIMPEXP_BASE wxAppConsoleBase : public wxEvtHandler,
public wxEventFilter
{
public:
...
static wxAppConsole *GetInstance() { return ms_appInstance; }
static void SetInstance(wxAppConsole *app) { ms_appInstance = app; }
...
protected:
...
static wxAppConsole *ms_appInstance;
...
};
グローバル変数
解説記事でグローバル変数wxTopLevelWindow/wxPendingDeleteの型は説明目的のソースコード上に実在しない仮想クラステンプレートwxList<T>にwxWindow/wxObjectをテンプレート実引数に与えた特殊化とした。解説記事はstd::list<T*>との互換インターフェースで説明したがソースコードは非互換インターフェースが混在する。それぞれ実際のクラスはマクロ展開を用いて定義したwxWindowList/wxListで、wxList<T>特殊化で表せばwxList<wxWindow>/wxList<wxObject>である。ソースコード上に実在するwxListクラスと実在しないwxList<T>仮想クラステンプレートを混同しないように。
wxTopLevelWindows変数
[src\common\wincmn.cpp:88]
WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
wxWindowListクラスは仮想クラステンプレート特殊化であるwxList<wxWindow>で、クラス定義とメンバ関数定義はマクロ展開による。
[include\wx\window.h:153]
WX_DECLARE_LIST_3(wxWindow, wxWindowBase, wxWindowList, wxWindowListNode, class WXDLLIMPEXP_CORE);
[src\common\wincmn.cpp:3283]
WX_DEFINE_LIST(wxWindowList)
wxPendingDelete変数
[src\common\appbase.cpp:150]
WXDLLIMPEXP_DATA_BASE(wxList) wxPendingDelete;
wxListクラス[src\include\wx\list.h:1167]はwxObjectListクラスからの派生だが解説記事の範囲ではwxObjectListと同じと考えて良い。wxObjectListクラスは仮想クラステンプレート特殊化であるwxList<wxObject>で、クラス定義とメンバ関数定義はマクロ展開による。
[include\wx\list.h:1164]
WX_DECLARE_LIST_2(wxObject, wxObjectList, wxObjectListNode,
class WXDLLIMPEXP_BASE);
[src\common\list.cpp:736]
WX_DEFINE_LIST(wxObjectList)
wxAppクラス
イベントテーブル
[src\msw\app.cpp:624]
wxBEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
EVT_IDLE(wxApp::OnIdle)
EVT_END_SESSION(wxApp::OnEndSession)
EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
wxEND_EVENT_TABLE()
OnRunメンバ関数
wxAppBase::OnRunメンバ関数
[src\common\appcmn.cpp:324]
int wxAppBase::OnRun()
{
if ( m_exitOnFrameDelete == Later )
{
m_exitOnFrameDelete = Yes;
}
return wxAppConsole::OnRun();
}
wxAppConsoleBase::OnRunメンバ関数
[src\common\appbase.cpp:301]
int wxAppConsoleBase::OnRun()
{
return MainLoop();
}
wxAppConsoleBase::MainLoopメンバ関数
[src\common\appbase.cpp:374]
int wxAppConsoleBase::MainLoop()
{
wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());
if (wxTheApp)
wxTheApp->OnLaunched();
return m_mainLoop ? m_mainLoop->Run() : -1;
}
OnExitメンバ関数
wxAppBase::OnExitメンバ関数
[src\common\appcmn.cpp:337]
int wxAppBase::OnExit()
{
#ifdef __WXUNIVERSAL__
delete wxTheme::Set(NULL);
#endif
return wxAppConsole::OnExit();
}
wxAppConsoleBase::OnExitメンバ関数
[src\common\appbase:310]
int wxAppConsoleBase::OnExit()
{
DeletePendingObjects();
#if wxUSE_CONFIG
wxConfigBase::DontCreateOnDemand();
#endif
return 0;
}
wxAppConsoleBase::DeletePendingObjectsメンバ関数
[src\common\appbase.cpp:628]
void wxAppConsoleBase::DeletePendingObjects()
{
wxList::compatibility_iterator node = wxPendingDelete.GetFirst();
while (node)
{
wxObject *obj = node->GetData();
if ( wxPendingDelete.Member(obj) )
wxPendingDelete.Erase(node);
delete obj;
node = wxPendingDelete.GetFirst();
}
}
ExitMainLoopメンバ関数
wxAppConsoleBase::ExitMainLoopメンバ関数
[src\common\appbase.cpp:384]
void wxAppConsoleBase::ExitMainLoop()
{
if ( m_mainLoop && m_mainLoop->IsRunning() )
{
m_mainLoop->Exit(0);
}
}
ProcessIdleメンバ関数
wxAppConsoleBase::ProcessIdleメンバ関数
[src\common\appbase.cpp:430]
bool wxAppConsoleBase::ProcessIdle()
{
wxIdleEvent event;
event.SetEventObject(this);
ProcessEvent(event);
#if wxUSE_LOG
wxLog::FlushActive();
#endif
DeletePendingObjects();
return event.MoreRequested();
}
WakeUpIdleメンバ関数
wxApp::WakeUpIdleメンバ関数
[src\msw\app.cpp:805]
void wxApp::WakeUpIdle()
{
wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
if ( !evtLoop )
{
return;
}
evtLoop->WakeUp();
}
GetTopWindowメンバ関数
解体遅延されるTLWを除く処理はバージョン3.1.1で追加された(※1)。
wxAppBase::GetTopWindowメンバ関数
[src\common\appcmn.cpp:169]
wxWindow* wxAppBase::GetTopWindow() const
{
wxWindow* window = m_topWindow;
if ( !window || wxPendingDelete.Member(window) )
{
window = NULL;
wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
while ( node )
{
wxWindow* win = node->GetData();
if ( !wxPendingDelete.Member(win) )
{
window = win;
break;
}
node = node->GetNext();
}
}
return window;
}
OnQueryEndSessionメンバ関数
wxApp::OnQueryEndSessionメンバ関数
[src\msw\app.cpp:864]
void wxApp::OnQueryEndSession(wxCloseEvent& event)
{
if (GetTopWindow())
{
if (!GetTopWindow()->Close(!event.CanVeto()))
event.Veto(true);
}
}
OnEndSessionメンバ関数
C言語標準ライブラリexit関数でアプリケーションを終了してwxEntryReal関数に戻らないため、wxEntryCleanup関数をexit前にコールする。DeleteAllTLWsメンバ関数によるTLW全解体はバージョン3.2.1で加えられた(※3)。
wxApp::OnEndSessionメンバ関数
[src\msw\app.cpp:833]
void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
{
if ( !wxTopLevelWindows.empty() )
wxTopLevelWindows[0]->SetHWND(0);
DeleteAllTLWs();
const int rc = OnExit();
wxEntryCleanup();
exit(rc);
}
wxAppBase::DeleteAllTLWsメンバ関数
[src\common\appcmn.cpp:130]
void wxAppBase::DeleteAllTLWs()
{
while ( !wxTopLevelWindows.empty() )
{
delete wxTopLevelWindows.GetFirst()->GetData();
}
}
wxEventLoopクラス
wxEventLoopコンストラクタ
wxMSWEventLoopBase::wxMSWEventLoopBaseコンストラクタ
[src\msw\evtloopconsole.cpp:38]
wxMSWEventLoopBase::wxMSWEventLoopBase()
{
m_shouldExit = false;
m_exitcode = 0;
m_heventWake = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if ( !m_heventWake )
wxLogLastError(wxS("CreateEvent(wake)"));
}
~wxEventLoopデストラクタ
wxMSWEventLoopBase::~wxMSWEventLoopBaseデストラクタ
[src\msw\evtloopconsole.cpp:49]
wxMSWEventLoopBase::~wxMSWEventLoopBase()
{
if ( m_heventWake && !::CloseHandle(m_heventWake) )
wxLogLastError(wxS("CloseHandle(wake)"));
}
Runメンバ関数
関数コールは深いがDoRunメンバ関数のメッセージループとwxConsoleEventLoop::Dispatchメンバ関数における処理に要約できる。
wxEventLoopBase::Runメンバ関数
[src\common\evtloopcmn.cpp:68]
int wxEventLoopBase::Run()
{
wxCHECK_MSG( !IsInsideRun(), -1, wxT("can't reenter a message loop") );
wxEventLoopActivator activate(this);
m_shouldExit = false;
m_isInsideRun = true;
wxON_BLOCK_EXIT_SET(m_isInsideRun, false);
return DoRun();
}
wxEventLoopManual::DoRunメンバ関数
メッセージループを実装するが解説記事で省略した遅延イベント(wxEvtHandler::QueueEventメンバ関数[src\common\event.cpp:1285]で登録されて次のメッセージループまで処理遅延されるイベント)処理を含む。最外郭forループは例外処理で、次レベルのforループが遅延イベント処理を含むメッセージループであるが、それでも遅延イベントを残して抜ける場合があるので遅延イベント処理のみ行うforループが後続する。メッセージループ内のwhileループは終了フラグ(m_shouldExitメンバ変数)が立っておらずかつ遅延イベントが残っていなければ、アイドル処理としてwxTheApp->ProcessIdleコールがfalseを返すまで繰り返す。イベント処理は遅延イベントを含めてwxEventLoopManual::ProcessEventsコールが行うが、これがfalseを返す(WM_QUITメッセージがポストされた)かm_shouldExitフラグが立てばメッセージループは終了する。
[src\msw\evtloopconsole.cpp:246]
int wxEventLoopManual::DoRun()
{
#if wxUSE_EXCEPTIONS
for ( ;; )
{
try
{
#endif
for ( ;; )
{
OnNextIteration();
while ( !m_shouldExit
&& !Pending()
&& !(wxTheApp && wxTheApp->HasPendingEvents())
&& ProcessIdle() )
;
if ( m_shouldExit )
break;
if ( !ProcessEvents() || m_shouldExit )
break;
}
for ( ;; )
{
bool hasMoreEvents = false;
if ( wxTheApp && wxTheApp->HasPendingEvents() )
{
wxTheApp->ProcessPendingEvents();
hasMoreEvents = true;
}
if ( gs_eventLoopCount == 1 )
{
if ( Pending() )
{
Dispatch();
hasMoreEvents = true;
}
}
if ( !hasMoreEvents )
break;
}
#if wxUSE_EXCEPTIONS
break;
}
catch ( ... )
{
try
{
if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() )
{
OnExit();
break;
}
}
catch ( ... )
{
OnExit();
throw;
}
}
}
#endif
return m_exitcode;
}
wxEventLoopBase::ProcessIdleメンバ関数
[src\common\evtloopcmn.cpp:102]
bool wxEventLoopBase::ProcessIdle()
{
return wxTheApp && wxTheApp->ProcessIdle();
}
wxEventLoopManual::ProcessEventsメンバ関数
遅延イベント処理はwxAppConsoleBase::ProcessPendingEventsメンバ関数[src\common\appbase.cpp:546]に委ね、それ以外はwxConsoleEventLoop::Dispatchメンバ関数に委ねる。
[src\common\evtloopcmn.cpp:214]
bool wxEventLoopManual::ProcessEvents()
{
if ( wxTheApp )
{
wxTheApp->ProcessPendingEvents();
if ( m_shouldExit )
return false;
}
const bool res = Dispatch();
#if wxUSE_EXCEPTIONS
if ( wxTheApp )
wxTheApp->RethrowStoredException();
#endif
return res;
}
wxConsoleEventLoop::Dispatchメンバ関数
メッセージウェイトはwxMSWEventLoopBase::GetNextMessageメンバ関数による。
[src\msw\evtloopconsole.cpp:157]
bool wxConsoleEventLoop::Dispatch()
{
MSG msg;
if ( !GetNextMessage(&msg) )
return false;
ProcessMessage(&msg);
return !m_shouldExit;
}
wxMSWEventLoopBase::GetNextMessageメンバ関数
[src\msw\evtloopconsole.cpp:97]
bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
{
return GetNextMessageTimeout(msg, INFINITE) == TRUE;
}
wxMSWEventLoopBase::GetNextMessageTimeoutメンバ関数
[src\msw\evtloopconsole.cpp:102]
int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
{
while ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
{
DWORD rc = ::MsgWaitForMultipleObjects
(
1, &m_heventWake,
FALSE,
timeout,
QS_ALLINPUT | QS_ALLPOSTMESSAGE
);
switch ( rc )
{
default:
wxLogDebug("unexpected MsgWaitForMultipleObjects() return "
"value %lu", rc);
wxFALLTHROUGH;
case WAIT_TIMEOUT:
return -1;
case WAIT_OBJECT_0:
wxZeroMemory(*msg);
return TRUE;
case WAIT_OBJECT_0 + 1:
break;
}
}
return msg->message != WM_QUIT;
}
WakeUpメンバ関数
wxMSWEventLoopBase::WakeUpメンバ関数
[src\msw\evtloopconsole.cpp:65]
void wxMSWEventLoopBase::WakeUp()
{
if ( !::SetEvent(m_heventWake) )
wxLogLastError(wxS("SetEvent(wake)"));
}
Exitメンバ関数
Exitメンバ関数はDispatchメンバ関数によるメッセージ処理からコールされるので、リターンはDispatchへ戻る。m_exitcodeフラグを立ててウェイクアップする事でメッセージループを終了する。
wxEventLoopBase::Exitメンバ関数
[src\common\evtloopcmn.cpp:90]
void wxEventLoopBase::Exit(int rc)
{
wxCHECK_RET( IsRunning(), wxS("Use ScheduleExit() on not running loop") );
ScheduleExit(rc);
}
wxEventLoopManual::ScheduleExitメンバ関数
[src\common\evtloopcmn.cpp:376]
void wxEventLoopManual::ScheduleExit(int rc)
{
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not running") );
m_exitcode = rc;
m_shouldExit = true;
OnExit();
WakeUp();
}
wxTopLevelWindowクラス
wxTopLevelWindowMSWとwxWindowMSWは__WXMSW__定義かつ__WXUNIVERSAL__非定義として他プラットフォーム実装との共通名に#defineされる。定義/被定義が両者で逆だがソースコードには影響しない。
[include\wx\toplevel.h:375]
#if defined(__WXMSW__)
...
#define wxTopLevelWindowNative wxTopLevelWindowMSW
#elif ...
...
#endif
[include\wx\window.h:2070]
#if defined(__WXMSW__)
#ifdef __WXUNIVERSAL__
...
#else
#define wxWindowMSW wxWindow
#endif
...
#elif ...
...
#endif
イベントテーブル
[src\common\toplvcmn.cpp:37]
wxBEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow)
EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow)
EVT_SIZE(wxTopLevelWindowBase::OnSize)
wxEND_EVENT_TABLE()
Createメンバ関数
wxTopLevelWindowMSW::Createメンバ関数
[src\msw\toplevel.cpp:424]
bool wxTopLevelWindowMSW::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
wxSize sizeReal = size;
if ( !sizeReal.IsFullySpecified() )
{
sizeReal.SetDefaults(GetDefaultSize());
}
wxTopLevelWindows.Append(this);
if ( !CreateBase(parent, id, pos, sizeReal, style, name) )
return false;
if ( parent )
parent->AddChild(this);
...
return true;
}
~wxTopLevelWindowデストラクタ
IsLastBeforeExitメンバ関数コールで最後のTLWであればアプリケーションを終了する。解体されたTLWは基底wxWindowBaseデストラクタでwxwxPendingDeleteリストから削除される。
wxTopLevelWindowBase::~wxTopLevelWindowBaseデストラクタ
[src\common\toplvlcmn.cpp:58]
wxTopLevelWindowBase::~wxTopLevelWindowBase()
{
if ( wxTheApp && wxTheApp->GetTopWindow() == this )
wxTheApp->SetTopWindow(NULL);
wxTopLevelWindows.DeleteObject(this);
for ( wxObjectList::iterator i = wxPendingDelete.begin();
i != wxPendingDelete.end();
)
{
wxWindow * const win = wxDynamicCast(*i, wxWindow);
if ( win && wxGetTopLevelParent(win->GetParent()) == this )
{
wxPendingDelete.erase(i);
delete win;
i = wxPendingDelete.begin();
}
else
{
++i;
}
}
if ( IsLastBeforeExit() )
{
wxTheApp->ExitMainLoop();
}
}
wxTopLevelWindowBase::IsLastBeforeExitメンバ関数
[src\common\toplvcmn.cpp:143]
bool wxTopLevelWindowBase::IsLastBeforeExit() const
{
if ( !wxTheApp || !wxTheApp->GetExitOnFrameDelete() )
return false;
if ( GetParent() && !GetParent()->IsBeingDeleted() )
return false;
wxWindowList::const_iterator i;
const wxWindowList::const_iterator end = wxTopLevelWindows.end();
for ( i = wxTopLevelWindows.begin(); i != end; ++i )
{
wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
if ( win->ShouldPreventAppExit() )
{
return false;
}
}
for ( i = wxTopLevelWindows.begin(); i != end; ++i )
{
wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
if ( !wxPendingDelete.Member(win) && !win->Close() )
{
return false;
}
}
return true;
}
wxWindowBase::~wxWindowBaseデストラクタ
[src\common\wincmn.cpp:453]
wxWindowBase::~wxWindowBase()
{
wxASSERT_MSG( !wxMouseCapture::IsInCaptureStack(this),
"Destroying window before releasing mouse capture: this "
"will result in a crash later." );
wxPendingDelete.DeleteObject(this);
wxTopLevelWindows.DeleteObject(this);
...
}
Destroyメンバ関数
TLWは親ウィンドウが解体中でなければwxPendingDeleteに登録して解体遅延する。wxWakeUpIdle関数[src\common\appbase.cpp:1118]コール(wxTheApp->WakeUpIdleコールと等価)はバージョン3.1.4で追加された(※2)。
wxTopLevelWindowMSW::Destroyメンバ関数
[src\msw\toplevel.cpp:767]
bool wxTopLevelWindowMSW::Destroy()
{
if ( !wxTopLevelWindowBase::Destroy() )
return false;
wxWakeUpIdle();
return true;
}
wxTopLevelWindowBase::Destroyメンバ関数
[src\common\toplvcmn.cpp:101]
bool wxTopLevelWindowBase::Destroy()
{
wxWindow* parent = GetParent();
if ( (parent && parent->IsBeingDeleted()) || !GetHandle() )
{
return wxNonOwnedWindow::Destroy();
}
if ( !wxPendingDelete.Member(this) )
wxPendingDelete.Append(this);
for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
end = wxTopLevelWindows.end();
i != end;
++i )
{
wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
if ( win != this && win->IsShown() )
{
Hide();
break;
}
}
return true;
}
wxWindowBase::Destroyメンバ関数
[src\common\wincmn.cpp:561]
bool wxWindowBase::Destroy()
{
if ( GetHandle() )
SendDestroyEvent();
delete this;
return true;
}
Closeメンバ関数
wxWindowBase::Closeメンバ関数
[src\common\wincmn.cpp:577]
bool wxWindowBase::Close(bool force)
{
wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
event.SetEventObject(this);
event.SetCanVeto(!force);
return HandleWindowEvent(event) && !event.GetVeto();
}
wxWindowBase::HandleWindowEventメンバ関数
wxWindowBase::GetEventHandlerメンバ関数[include\wx\window.h:862]はウィンドウのイベントハンドラ(デフォルトは自身)を返す。wxEvtHandler::SafelyProcessEventメンバ関数[src\common\event.cpp:1644]は例外処理を除けばwxEvtHandler::ProcessEventメンバ関数[src\common\event.cpp:1502]と同じ。
[src\common\wincmn.cpp:1550]
bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
{
return GetEventHandler()->SafelyProcessEvent(event);
}
OnCloseWindowメンバ関数
wxTopLevelWindowBase::OnCloseWindowメンバ関数
[src\common\toplvcmn.cpp:474]
void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
{
Destroy();
}
SendIdleEventsメンバ関数
wxWindowBase::SendIdleEventsメンバ関数
[src\common\wincmn.cpp:2835]
{.cpp]
bool wxWindowBase::SendIdleEvents(wxIdleEvent& event)
{
bool needMore = false;
OnInternalIdle();
// should we send idle event to this window?
if (wxIdleEvent::GetMode() == wxIDLE_PROCESS_ALL ||
HasExtraStyle(wxWS_EX_PROCESS_IDLE))
{
event.SetEventObject(this);
HandleWindowEvent(event);
if (event.MoreRequested())
needMore = true;
}
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
for (; node; node = node->GetNext())
{
wxWindow* child = node->GetData();
if (child->SendIdleEvents(event))
needMore = true;
}
return needMore;
}
MSWHandleMessageメンバ関数
wxWindowMSW::MSWHandleMessageメンバ関数
[src\msw\window.cpp:2957]
bool
wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
WXUINT message,
WXWPARAM wParam,
WXLPARAM lParam)
{
bool processed = false;
union
{
bool allow;
WXLRESULT result;
WXHBRUSH hBrush;
} rc;
rc.result = 0;
...
switch ( message )
{
...
case WM_QUERYENDSESSION:
processed = HandleQueryEndSession(lParam, &rc.allow);
break;
case WM_ENDSESSION:
processed = HandleEndSession(wParam != 0, lParam);
break;
...
}
if ( !processed )
return false;
*result = rc.result;
return true;
}
HandleQueryEndSessionメンバ関数
wxWindowMSW::HandleQueryEndSessionメンバ関数
[src\msw\window.cpp:4236]
bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
{
wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
event.SetEventObject(wxTheApp);
event.SetCanVeto(true);
event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
bool rc = wxTheApp->SafelyProcessEvent(event);
if ( rc )
{
*mayEnd = !event.GetVeto();
}
return rc;
}
HandleEndSessionメンバ関数
メインTLWがDestroyメンバ関数で解体遅延されればバージョン3.1.1以降(※1)でwxApp::GetMainTopWindowスタティックメンバ関数[src\common\appcmn.cpp:195]コール(wxTheApp->GetTopWindowコールと等価)はNULLを返してwxEVT_END_SESSIONイベントを発生しない。
wxWindowMSW::HandleEndSessionメンバ関数
[src\msw\window.cpp:4255]
bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
{
if ( !endSession )
return false;
if ( this != wxApp::GetMainTopWindow() )
return false;
wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
event.SetEventObject(wxTheApp);
event.SetCanVeto(false);
event.SetLoggingOff((logOff & ENDSESSION_LOGOFF) != 0);
return wxTheApp->SafelyProcessEvent(event);
}