RunLoopWin.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch/*
265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * Copyright (C) 2010 Apple Inc. All rights reserved.
365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch *
465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * Redistribution and use in source and binary forms, with or without
565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * modification, are permitted provided that the following conditions
665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * are met:
765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * 1. Redistributions of source code must retain the above copyright
865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch *    notice, this list of conditions and the following disclaimer.
965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * 2. Redistributions in binary form must reproduce the above copyright
1065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch *    notice, this list of conditions and the following disclaimer in the
1165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch *    documentation and/or other materials provided with the distribution.
1265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch *
1365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
1465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
1765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * THE POSSIBILITY OF SUCH DAMAGE.
2465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch */
2565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "config.h"
2765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch#include "RunLoop.h"
2865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
2965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch#include "WorkItem.h"
3065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
3165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochstatic const UINT PerformWorkMessage = WM_USER + 1;
3265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochstatic const LPWSTR kRunLoopMessageWindowClassName = L"RunLoopMessageWindow";
3365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
3465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochLRESULT CALLBACK RunLoop::RunLoopWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
3565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
3665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
3765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
3865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if (RunLoop* runLoop = reinterpret_cast<RunLoop*>(longPtr))
3965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return runLoop->wndProc(hWnd, message, wParam, lParam);
4065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
4165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if (message == WM_CREATE) {
4265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
4365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
4465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        // Associate the RunLoop with the window.
4565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
4665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return 0;
4765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    }
4865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
4965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return ::DefWindowProc(hWnd, message, wParam, lParam);
5065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
5165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
5265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochLRESULT RunLoop::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
5365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
5465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    switch (message) {
5565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    case PerformWorkMessage:
5665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        performWork();
5765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return 0;
5865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    case WM_TIMER:
5965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        RunLoop::TimerBase::timerFired(this, wParam);
6065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return 0;
6165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    }
6265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
6365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return ::DefWindowProc(hWnd, message, wParam, lParam);
6465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
6565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
6665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::run()
6765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
6865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    MSG message;
6965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    while (BOOL result = ::GetMessage(&message, 0, 0, 0)) {
7065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if (result == -1)
7165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            break;
7265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ::TranslateMessage(&message);
7365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ::DispatchMessage(&message);
7465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    }
7565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
7665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
7765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::stop()
7865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
7965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ::PostQuitMessage(0);
8065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
8165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
8265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochbool RunLoop::registerRunLoopMessageWindowClass()
8365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
8465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    // FIXME: This really only needs to be called once.
8565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
8665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    WNDCLASSEX windowClass = { 0 };
8765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    windowClass.cbSize          = sizeof(windowClass);
8865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    windowClass.lpfnWndProc     = RunLoop::RunLoopWndProc;
8965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    windowClass.cbWndExtra      = sizeof(RunLoop*);
9065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    windowClass.lpszClassName   = kRunLoopMessageWindowClassName;
9165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
9265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return !!::RegisterClassEx(&windowClass);
9365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
9465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
9565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::RunLoop()
9665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
9765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    registerRunLoopMessageWindowClass();
9865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
9965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    m_runLoopMessageWindow = ::CreateWindow(kRunLoopMessageWindowClassName, 0, 0,
10065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                                            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
10165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                                            HWND_MESSAGE, 0, 0, this);
10265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ASSERT(::IsWindow(m_runLoopMessageWindow));
10365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
10465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
10565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::~RunLoop()
10665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
10765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    // FIXME: Tear down the work item queue here.
10865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
10965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
11065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::wakeUp()
11165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
11265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    // FIXME: No need to wake up the run loop if we've already called scheduleWork
11365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    // before the run loop has had the time to respond.
11465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ::PostMessage(m_runLoopMessageWindow, PerformWorkMessage, reinterpret_cast<WPARAM>(this), 0);
11565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
11665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
11765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch// RunLoop::Timer
11865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
11965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::TimerBase::timerFired(RunLoop* runLoop, uint64_t ID)
12065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
12165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    TimerMap::iterator it = runLoop->m_activeTimers.find(ID);
1222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (it == runLoop->m_activeTimers.end()) {
1232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // The timer must have been stopped after the WM_TIMER message was posted to the message queue.
1242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return;
1252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
1262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
12765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    TimerBase* timer = it->second;
12865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
12965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if (!timer->m_isRepeating) {
13065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        runLoop->m_activeTimers.remove(it);
13165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ::KillTimer(runLoop->m_runLoopMessageWindow, ID);
13265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    }
13365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
13465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    timer->fired();
13565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
13665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
13765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochstatic uint64_t generateTimerID()
13865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
13965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    static uint64_t uniqueTimerID = 1;
14065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return uniqueTimerID++;
14165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
14265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
14365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::TimerBase::TimerBase(RunLoop* runLoop)
14465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    : m_runLoop(runLoop)
14565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    , m_ID(generateTimerID())
14665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    , m_isRepeating(false)
14765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
14865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
14965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
15065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::TimerBase::~TimerBase()
15165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
15265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    stop();
15365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
15465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
15565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::TimerBase::start(double nextFireInterval, bool repeat)
15665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
15765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    m_isRepeating = repeat;
15865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    m_runLoop->m_activeTimers.set(m_ID, this);
15981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    ::SetTimer(m_runLoop->m_runLoopMessageWindow, m_ID, nextFireInterval * 1000, 0);
16065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
16165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
16265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::TimerBase::stop()
16365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
16465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID);
16565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if (it == m_runLoop->m_activeTimers.end())
16665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        return;
16765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
16865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    m_runLoop->m_activeTimers.remove(it);
16965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ::KillTimer(m_runLoop->m_runLoopMessageWindow, m_ID);
17065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
17165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch
17265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochbool RunLoop::TimerBase::isActive() const
17365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{
17465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    return m_runLoop->m_activeTimers.contains(m_ID);
17565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch}
176