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