diff options
Diffstat (limited to 'WebKitTools/Drosera/win/Drosera.cpp')
-rw-r--r-- | WebKitTools/Drosera/win/Drosera.cpp | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/WebKitTools/Drosera/win/Drosera.cpp b/WebKitTools/Drosera/win/Drosera.cpp new file mode 100644 index 0000000..820054f --- /dev/null +++ b/WebKitTools/Drosera/win/Drosera.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Drosera.h" + +#include "DebuggerClient.h" +#include "DebuggerDocument.h" +#include "resource.h" +#include "ServerConnection.h" + +#include <JavaScriptCore/JSStringRef.h> +#include <WebKit/ForEachCoClass.h> +#include <WebKit/WebKit.h> +#include <wtf/RetainPtr.h> + +const unsigned MAX_LOADSTRING = 100; + +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name + +static LPCTSTR s_DroseraPointerProp = TEXT("DroseraPointer"); +static HINSTANCE hInst; + +BSTR cfStringToBSTR(CFStringRef cfstr); + +void registerDroseraClass(HINSTANCE hInstance); +LRESULT CALLBACK droseraWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK aboutWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); + +HINSTANCE Drosera::getInst() { return hInst; } +void Drosera::setInst(HINSTANCE in) { hInst = in; } +void launchConsoleWindow(); + +extern "C" __declspec(dllimport) HANDLE* __pioinfo; + +int APIENTRY _tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + MSG msg; + +#ifndef NDEBUG + launchConsoleWindow(); +#endif + + Drosera drosera; + + HRESULT ret = drosera.init(hInstance, nCmdShow); + if (FAILED(ret)) + return ret; + + HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DROSERA)); + + // Main message loop: + while (GetMessage(&msg, 0, 0, 0)) { + if (!drosera.serverConnected()) + drosera.attemptToCreateServerConnection(); + + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return static_cast<int>(msg.wParam); +} + +void launchConsoleWindow() +{ + if (AllocConsole()) { + // MSVCRT exports __pioinfo which is an array of ioinfo handles. the first three are stdout, stdin, and stderr + // the first pointer in the ioinfo object is the kernel handle for the console, so we can simplify the expression + // to just deref the exported symbol, setting it to the newly allocated console handle. + *__pioinfo = GetStdHandle(STD_OUTPUT_HANDLE); + // When an app is created without a console, stdout, stderr and stdin are all invalid handles (i.e. negative) + // Since we've introduced new handles, we can reset their file index - which is the index into the ioinfo array. + // This hooks up the standard cruntime APIS to the new console, allowing a functional output. As for input YMMV. + stdout->_file = 0; + stderr->_file = 0; + } +} + +////////////////// Setup Windows Specific Interface ////////////////// + +void registerDroseraClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = ::droseraWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = sizeof(Drosera*); + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DROSERA)); + wcex.hCursor = LoadCursor(0, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCE(IDC_DROSERA); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + + RegisterClassEx(&wcex); +} + +//Processes messages for the main window. +LRESULT CALLBACK droseraWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + + LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0); + Drosera* drosera = reinterpret_cast<Drosera*>(longPtr); + + switch (message) { + case WM_COMMAND: + return drosera->handleCommand(hWnd, message, wParam, lParam); + break; + case WM_SIZE: + if (!drosera) + return 0; + return drosera->webViewLoaded() ? drosera->onSize(wParam, lParam) : 0; + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return 0; +} + +LRESULT CALLBACK Drosera::handleCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId = LOWORD(wParam); + switch (wmId) { + case ID_DEBUG_CONTINUE: + m_debuggerClient->resume(); + break; + case ID_DEBUG_PAUSE: + m_debuggerClient->pause(); + break; + case ID_DEBUG_STEPINTO: + m_debuggerClient->stepInto(); + break; + case ID_DEBUG_STEPOVER: + m_debuggerClient->stepOver(); + break; + case ID_DEBUG_STEPOUT: + m_debuggerClient->stepOut(); + break; + case ID_DEBUG_SHOWCONSOLE: + m_debuggerClient->showConsole(); + break; + case ID_HELP_ABOUT: + DialogBox(Drosera::getInst(), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, ::aboutWndProc); + break; + case ID_FILE_EXIT: + DestroyWindow(hWnd); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return 0; +} + +// Message handler for about box. +INT_PTR CALLBACK aboutWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + UNREFERENCED_PARAMETER(lParam); + switch (message) { + case WM_INITDIALOG: + return (INT_PTR)TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + return (INT_PTR)FALSE; +} + +////////////////// End Setup Windows Specific Interface ////////////////// + +Drosera::Drosera() + : m_hWnd(0) + , m_debuggerClient(new DebuggerClient()) +{ +} + +HRESULT Drosera::init(HINSTANCE hInstance, int nCmdShow) +{ + HRESULT ret = initUI(hInstance, nCmdShow); + if (FAILED(ret)) + return ret; + + ret = attach(); + return ret; +} + + +HRESULT Drosera::initUI(HINSTANCE hInstance, int nCmdShow) +{ + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, ARRAYSIZE(szTitle)); + LoadString(hInstance, IDC_DROSERA, szWindowClass, ARRAYSIZE(szWindowClass)); + registerDroseraClass(hInstance); + + Drosera::setInst(hInstance); // Store instance handle in our local variable + + m_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, 0); + + if (!m_hWnd) + return HRESULT_FROM_WIN32(GetLastError()); + + SetLastError(0); + SetWindowLongPtr(m_hWnd, 0, reinterpret_cast<LONG_PTR>(this)); + HRESULT ret = HRESULT_FROM_WIN32(GetLastError()); + if (FAILED(ret)) + return ret; + + CLSID clsid = CLSID_NULL; + ret = CLSIDFromProgID(PROGID(WebView), &clsid); + if (FAILED(ret)) + return ret; + + ret = CoCreateInstance(clsid, 0, CLSCTX_ALL, IID_IWebView, (void**)&m_webView); + if (FAILED(ret)) + return ret; + + m_webViewPrivate.query(m_webView.get()); + if (!m_webViewPrivate) + return E_FAIL; + + ret = m_webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(m_hWnd)); + if (FAILED(ret)) + return ret; + + RECT clientRect = {0}; + ::GetClientRect(m_hWnd, &clientRect); + ret = m_webView->initWithFrame(clientRect, 0, 0); + if (FAILED(ret)) + return ret; + + HWND viewWindow; + ret = m_webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)); + if (FAILED(ret)) + return ret; + + SetProp(viewWindow, s_DroseraPointerProp, (HANDLE)this); + + // FIXME: Implement window size/position save/restore + ShowWindow(m_hWnd, nCmdShow); + UpdateWindow(m_hWnd); + + return ret; +} + +LRESULT Drosera::onSize(WPARAM, LPARAM) +{ + if (!m_webViewPrivate) + return 0; + + RECT clientRect = {0}; + ::GetClientRect(m_hWnd, &clientRect); + + HWND viewWindow; + if (SUCCEEDED(m_webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) + // FIXME should this be the height-command bars height? + ::SetWindowPos(viewWindow, 0, clientRect.left, clientRect.top, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, SWP_NOZORDER); + + return 0; +} + +bool Drosera::webViewLoaded() const +{ + return m_debuggerClient->webViewLoaded(); +} + +// Server Detection Callbacks + +HRESULT Drosera::attach() +{ + // Get selected server + HRESULT ret = m_webView->setFrameLoadDelegate(m_debuggerClient.get()); + if (FAILED(ret)) + return ret; + + ret = m_webView->setUIDelegate(m_debuggerClient.get()); + if (FAILED(ret)) + return ret; + + CLSID clsid = CLSID_NULL; + ret = CLSIDFromProgID(PROGID(WebMutableURLRequest), &clsid); + if (FAILED(ret)) + return ret; + + COMPtr<IWebMutableURLRequest> request; + ret = CoCreateInstance(clsid, 0, CLSCTX_ALL, IID_IWebMutableURLRequest, (void**)&request); + if (FAILED(ret)) + return ret; + + RetainPtr<CFURLRef> htmlURLRef(AdoptCF, ::CFBundleCopyResourceURL(::CFBundleGetBundleWithIdentifier(CFSTR("org.webkit.drosera")), CFSTR("debugger"), CFSTR("html"), CFSTR("Drosera"))); + if (!htmlURLRef) + return E_FAIL; + + CFStringRef urlStringRef = ::CFURLGetString(htmlURLRef.get()); + BSTR tempStr = cfStringToBSTR(urlStringRef); // Both initWithRUL and SysFreeString can handle 0. + ret = request->initWithURL(tempStr, WebURLRequestUseProtocolCachePolicy, 60); + SysFreeString(tempStr); + if (FAILED(ret)) + return ret; + + COMPtr<IWebFrame> mainFrame; + ret = m_webView->mainFrame(&mainFrame); + if (FAILED(ret)) + return ret; + + ret = mainFrame->loadRequest(request.get()); + if (FAILED(ret)) + return ret; + + return ret; +} + +BSTR cfStringToBSTR(CFStringRef cfstr) +{ + if (!cfstr) + return 0; + + const UniChar* uniChars = CFStringGetCharactersPtr(cfstr); + if (uniChars) + return SysAllocStringLen((LPCTSTR)uniChars, CFStringGetLength(cfstr)); + + CFIndex length = CFStringGetLength(cfstr); + BSTR bstr = SysAllocStringLen(0, length); + CFStringGetCharacters(cfstr, CFRangeMake(0, length), (UniChar*)bstr); + bstr[length] = 0; + + return bstr; +} + +// Server Connection Functions + +bool Drosera::serverConnected() const +{ + return m_debuggerClient->serverConnected(); +} + +void Drosera::attemptToCreateServerConnection() +{ + m_debuggerClient->attemptToCreateServerConnection(); +} + |