//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Nestopia is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// #include "language/resource.h" #include "NstObjectPod.hpp" #include "NstApplicationException.hpp" #include "NstWindowParam.hpp" #include "NstWindowDynamic.hpp" namespace Nestopia { namespace Window { Dynamic::Instances Dynamic::instances; Dynamic::Dynamic() { Initialize(); } Dynamic::~Dynamic() { Destroy(); } void Dynamic::Initialize() { Messages().Add( WM_NCDESTROY, this, &Dynamic::OnNcDestroy ); } void Dynamic::Create(Context& create) { NST_ASSERT( create.className && *create.className ); Object::Pod winClass; winClass.cbSize = sizeof(winClass); winClass.style = create.classStyle; winClass.lpfnWndProc = WndProcCreate; winClass.hInstance = ::GetModuleHandle(NULL); winClass.hCursor = create.hCursor; winClass.hbrBackground = create.hBackground; winClass.lpszClassName = create.className; winClass.hIcon = winClass.hIconSm = create.hIcon; if (!RegisterClassEx( &winClass )) throw Application::Exception( IDS_ERR_FAILED, L"RegisterClassEx()" ); className = create.className; CreateWindowEx ( create.exStyle, create.className, create.windowName, create.winStyle, create.x, create.y, create.width, create.height, create.hParent, create.hMenu, ::GetModuleHandle(NULL), this ); if (!hWnd) throw Application::Exception( IDS_ERR_FAILED, L"CreateWindowEx()" ); } void Dynamic::Destroy() { Custom::Destroy(); if (className.Length()) { UnregisterClass( className.Ptr(), ::GetModuleHandle(NULL) ); className.Clear(); } } void Dynamic::OnCreate(HWND const handle) { NST_ASSERT( handle && !hWnd ); hWnd = handle; instances.PushBack( this ); const LONG_PTR ptr = reinterpret_cast( instances.Size() == 1 ? WndProcSingle : WndProcMulti ); if (!::SetWindowLongPtr( hWnd, GWLP_WNDPROC, ptr )) throw Application::Exception( IDS_ERR_FAILED, L"SetWindowLongPtr()" ); } ibool Dynamic::OnNcDestroy(Param&) { NST_ASSERT( hWnd ); Instances::Iterator instance; for (instance = instances.Ptr(); (*instance)->hWnd != hWnd; ++instance); instances.Erase( instance ); hWnd = NULL; return false; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("t", on) #endif LRESULT CALLBACK Dynamic::WndProcSingle(HWND const hWnd,const uint uMsg,WPARAM const wParam,LPARAM const lParam) { if (const MsgHandler::Item* const item = instances.Front()->msgHandler( uMsg )) { Param param = {wParam,lParam,0,hWnd}; if (item->callback( param )) return param.lResult; } return ::DefWindowProc( hWnd, uMsg, wParam, lParam ); } LRESULT CALLBACK Dynamic::WndProcMulti(HWND const hWnd,const uint uMsg,WPARAM const wParam,LPARAM const lParam) { Instances::ConstIterator instance; for (instance = instances.Ptr(); (*instance)->hWnd != hWnd; ++instance); if (const MsgHandler::Item* const item = (*instance)->msgHandler( uMsg )) { Param param = {wParam,lParam,0,hWnd}; if (item->callback( param )) return param.lResult; } return ::DefWindowProc( hWnd, uMsg, wParam, lParam ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif LRESULT CALLBACK Dynamic::WndProcCreate(HWND const hWnd,const uint uMsg,WPARAM const wParam,LPARAM const lParam) { if (uMsg == WM_CREATE && lParam) { if (Dynamic* const instance = static_cast(reinterpret_cast(lParam)->lpCreateParams)) { instance->OnCreate( hWnd ); if (const MsgHandler::Item* const item = instance->msgHandler( uMsg )) { Param param = {wParam,lParam,0,hWnd}; if (item->callback( param )) return param.lResult; } } } return ::DefWindowProc( hWnd, uMsg, wParam, lParam ); } } }