RunLoopWin.cpp revision 65f03d4f644ce73618e5f4f50dd694b26f55ae12
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 2665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch#include "RunLoop.h" 2765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 2865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch#include "WorkItem.h" 2965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 3065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochstatic const UINT PerformWorkMessage = WM_USER + 1; 3165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochstatic const LPWSTR kRunLoopMessageWindowClassName = L"RunLoopMessageWindow"; 3265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 3365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochLRESULT CALLBACK RunLoop::RunLoopWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 3465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 3565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0); 3665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 3765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if (RunLoop* runLoop = reinterpret_cast<RunLoop*>(longPtr)) 3865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return runLoop->wndProc(hWnd, message, wParam, lParam); 3965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 4065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if (message == WM_CREATE) { 4165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); 4265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 4365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // Associate the RunLoop with the window. 4465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams); 4565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return 0; 4665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch } 4765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 4865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return ::DefWindowProc(hWnd, message, wParam, lParam); 4965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 5065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 5165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochLRESULT RunLoop::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 5265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 5365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch switch (message) { 5465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch case PerformWorkMessage: 5565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch performWork(); 5665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return 0; 5765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch case WM_TIMER: 5865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch RunLoop::TimerBase::timerFired(this, wParam); 5965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return 0; 6065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch } 6165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 6265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return ::DefWindowProc(hWnd, message, wParam, lParam); 6365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 6465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 6565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::run() 6665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 6765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch MSG message; 6865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch while (BOOL result = ::GetMessage(&message, 0, 0, 0)) { 6965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if (result == -1) 7065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch break; 7165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::TranslateMessage(&message); 7265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::DispatchMessage(&message); 7365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch } 7465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 7565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 7665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::stop() 7765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 7865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::PostQuitMessage(0); 7965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 8065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 8165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochbool RunLoop::registerRunLoopMessageWindowClass() 8265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 8365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // FIXME: This really only needs to be called once. 8465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 8565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch WNDCLASSEX windowClass = { 0 }; 8665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch windowClass.cbSize = sizeof(windowClass); 8765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch windowClass.lpfnWndProc = RunLoop::RunLoopWndProc; 8865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch windowClass.cbWndExtra = sizeof(RunLoop*); 8965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch windowClass.lpszClassName = kRunLoopMessageWindowClassName; 9065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 9165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return !!::RegisterClassEx(&windowClass); 9265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 9365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 9465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::RunLoop() 9565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 9665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch registerRunLoopMessageWindowClass(); 9765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 9865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch m_runLoopMessageWindow = ::CreateWindow(kRunLoopMessageWindowClassName, 0, 0, 9965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 10065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch HWND_MESSAGE, 0, 0, this); 10165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ASSERT(::IsWindow(m_runLoopMessageWindow)); 10265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 10365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 10465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::~RunLoop() 10565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 10665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // FIXME: Tear down the work item queue here. 10765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 10865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 10965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::wakeUp() 11065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 11165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // FIXME: No need to wake up the run loop if we've already called scheduleWork 11265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch // before the run loop has had the time to respond. 11365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::PostMessage(m_runLoopMessageWindow, PerformWorkMessage, reinterpret_cast<WPARAM>(this), 0); 11465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 11565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 11665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch// RunLoop::Timer 11765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 11865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::TimerBase::timerFired(RunLoop* runLoop, uint64_t ID) 11965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 12065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch TimerMap::iterator it = runLoop->m_activeTimers.find(ID); 12165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ASSERT(it != runLoop->m_activeTimers.end()); 12265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch TimerBase* timer = it->second; 12365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 12465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if (!timer->m_isRepeating) { 12565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch runLoop->m_activeTimers.remove(it); 12665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::KillTimer(runLoop->m_runLoopMessageWindow, ID); 12765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch } 12865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 12965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch timer->fired(); 13065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 13165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 13265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochstatic uint64_t generateTimerID() 13365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 13465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch static uint64_t uniqueTimerID = 1; 13565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return uniqueTimerID++; 13665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 13765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 13865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::TimerBase::TimerBase(RunLoop* runLoop) 13965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch : m_runLoop(runLoop) 14065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch , m_ID(generateTimerID()) 14165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch , m_isRepeating(false) 14265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 14365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 14465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 14565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochRunLoop::TimerBase::~TimerBase() 14665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 14765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch stop(); 14865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 14965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 15065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::TimerBase::start(double nextFireInterval, bool repeat) 15165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 15265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch m_isRepeating = repeat; 15365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch m_runLoop->m_activeTimers.set(m_ID, this); 15465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::SetTimer(m_runLoop->m_runLoopMessageWindow, m_ID, nextFireInterval, 0); 15565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 15665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 15765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochvoid RunLoop::TimerBase::stop() 15865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 15965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID); 16065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if (it == m_runLoop->m_activeTimers.end()) 16165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return; 16265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 16365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch m_runLoop->m_activeTimers.remove(it); 16465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch ::KillTimer(m_runLoop->m_runLoopMessageWindow, m_ID); 16565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 16665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 16765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochbool RunLoop::TimerBase::isActive() const 16865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch{ 16965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return m_runLoop->m_activeTimers.contains(m_ID); 17065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch} 171