1/*
2 * Copyright (C) 2006, 2008 Apple Computer, Inc.  All rights reserved.
3 * Copyright (C) 2009 Brent Fulgha.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "stdafx.h"
28#include "WinLauncher.h"
29#include <WebKit/WebKitCOMAPI.h>
30
31#include <commctrl.h>
32#include <commdlg.h>
33#include <objbase.h>
34#include <shlwapi.h>
35#include <wininet.h>
36
37#include "PrintWebUIDelegate.h"
38
39#define MAX_LOADSTRING 100
40#define URLBAR_HEIGHT  24
41
42// Global Variables:
43HINSTANCE hInst;                                // current instance
44HWND hMainWnd;
45HWND hURLBarWnd;
46long DefEditProc;
47IWebView* gWebView = 0;
48HWND gViewWindow = 0;
49WinLauncherWebHost* gWebHost = 0;
50PrintWebUIDelegate* gPrintDelegate = 0;
51TCHAR szTitle[MAX_LOADSTRING];                    // The title bar text
52TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
53
54// Forward declarations of functions included in this code module:
55ATOM                MyRegisterClass(HINSTANCE hInstance);
56BOOL                InitInstance(HINSTANCE, int);
57LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
58INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
59LRESULT CALLBACK    MyEditProc(HWND, UINT, WPARAM, LPARAM);
60
61static void loadURL(BSTR urlBStr);
62
63HRESULT WinLauncherWebHost::updateAddressBar(IWebView* webView)
64{
65    IWebFrame* mainFrame = 0;
66    IWebDataSource* dataSource = 0;
67    IWebMutableURLRequest* request = 0;
68    BSTR frameURL = 0;
69
70    HRESULT hr = S_OK;
71
72    hr = webView->mainFrame(&mainFrame);
73    if (FAILED(hr))
74        goto exit;
75
76    hr = mainFrame->dataSource(&dataSource);
77    if (FAILED(hr) || !dataSource)
78        hr = mainFrame->provisionalDataSource(&dataSource);
79    if (FAILED(hr) || !dataSource)
80        goto exit;
81
82    hr = dataSource->request(&request);
83    if (FAILED(hr) || !request)
84        goto exit;
85
86    hr = request->mainDocumentURL(&frameURL);
87    if (FAILED(hr))
88        goto exit;
89
90    SendMessage(hURLBarWnd, (UINT)WM_SETTEXT, 0, (LPARAM)frameURL);
91
92exit:
93    if (mainFrame)
94        mainFrame->Release();
95    if (dataSource)
96        dataSource->Release();
97    if (request)
98        request->Release();
99    SysFreeString(frameURL);
100    return 0;
101}
102
103HRESULT STDMETHODCALLTYPE WinLauncherWebHost::QueryInterface(REFIID riid, void** ppvObject)
104{
105    *ppvObject = 0;
106    if (IsEqualGUID(riid, IID_IUnknown))
107        *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
108    else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
109        *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
110    else
111        return E_NOINTERFACE;
112
113    AddRef();
114    return S_OK;
115}
116
117ULONG STDMETHODCALLTYPE WinLauncherWebHost::AddRef(void)
118{
119    return ++m_refCount;
120}
121
122ULONG STDMETHODCALLTYPE WinLauncherWebHost::Release(void)
123{
124    ULONG newRef = --m_refCount;
125    if (!newRef)
126        delete(this);
127
128    return newRef;
129}
130
131static void resizeSubViews()
132{
133    RECT rcClient;
134    GetClientRect(hMainWnd, &rcClient);
135    MoveWindow(hURLBarWnd, 0, 0, rcClient.right, URLBAR_HEIGHT, TRUE);
136    MoveWindow(gViewWindow, 0, URLBAR_HEIGHT, rcClient.right, rcClient.bottom - URLBAR_HEIGHT, TRUE);
137}
138
139int APIENTRY _tWinMain(HINSTANCE hInstance,
140                     HINSTANCE hPrevInstance,
141                     LPTSTR    lpCmdLine,
142                     int       nCmdShow)
143{
144#ifdef _CRTDBG_MAP_ALLOC
145    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
146    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
147#endif
148
149    UNREFERENCED_PARAMETER(hPrevInstance);
150    UNREFERENCED_PARAMETER(lpCmdLine);
151
152     // TODO: Place code here.
153    MSG msg = {0};
154    HACCEL hAccelTable;
155
156    INITCOMMONCONTROLSEX InitCtrlEx;
157
158    InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
159    InitCtrlEx.dwICC  = 0x00004000; //ICC_STANDARD_CLASSES;
160    InitCommonControlsEx(&InitCtrlEx);
161
162    // Initialize global strings
163    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
164    LoadString(hInstance, IDC_WINLAUNCHER, szWindowClass, MAX_LOADSTRING);
165    MyRegisterClass(hInstance);
166
167    // Perform application initialization:
168    if (!InitInstance (hInstance, nCmdShow))
169        return FALSE;
170
171    // Init COM
172    OleInitialize(NULL);
173
174    hURLBarWnd = CreateWindow(L"EDIT", 0,
175                        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL,
176                        0, 0, 0, 0,
177                        hMainWnd,
178                        0,
179                        hInstance, 0);
180
181    DefEditProc = GetWindowLong(hURLBarWnd, GWL_WNDPROC);
182    SetWindowLong(hURLBarWnd, GWL_WNDPROC,(long)MyEditProc);
183    SetFocus(hURLBarWnd);
184
185    HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&gWebView);
186    if (FAILED(hr))
187        goto exit;
188
189    gWebHost = new WinLauncherWebHost();
190    gWebHost->AddRef();
191    hr = gWebView->setFrameLoadDelegate(gWebHost);
192    if (FAILED(hr))
193        goto exit;
194
195    gPrintDelegate = new PrintWebUIDelegate;
196    gPrintDelegate->AddRef();
197    hr = gWebView->setUIDelegate(gPrintDelegate);
198    if (FAILED (hr))
199        goto exit;
200
201    hr = gWebView->setHostWindow((OLE_HANDLE) hMainWnd);
202    if (FAILED(hr))
203        goto exit;
204
205    RECT clientRect;
206    GetClientRect(hMainWnd, &clientRect);
207    hr = gWebView->initWithFrame(clientRect, 0, 0);
208    if (FAILED(hr))
209        goto exit;
210
211    IWebFrame* frame;
212    hr = gWebView->mainFrame(&frame);
213    if (FAILED(hr))
214        goto exit;
215
216    static BSTR defaultHTML = SysAllocString(TEXT("<p style=\"background-color: #00FF00\">Testing</p><img src=\"http://webkit.org/images/icon-gold.png\" alt=\"Face\"><div style=\"border: solid blue\" contenteditable=\"true\">div with blue border</div><ul><li>foo<li>bar<li>baz</ul>"));
217    frame->loadHTMLString(defaultHTML, 0);
218    frame->Release();
219
220    IWebViewPrivate* viewExt;
221    hr = gWebView->QueryInterface(IID_IWebViewPrivate, (void**)&viewExt);
222    if (FAILED(hr))
223        goto exit;
224
225    hr = viewExt->viewWindow((OLE_HANDLE*) &gViewWindow);
226    viewExt->Release();
227    if (FAILED(hr) || !gViewWindow)
228        goto exit;
229
230    resizeSubViews();
231
232    ShowWindow(gViewWindow, nCmdShow);
233    UpdateWindow(gViewWindow);
234
235    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINLAUNCHER));
236
237    // Main message loop:
238    while (GetMessage(&msg, NULL, 0, 0)) {
239        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
240            TranslateMessage(&msg);
241            DispatchMessage(&msg);
242        }
243    }
244
245exit:
246    gPrintDelegate->Release();
247    gWebView->Release();
248    shutDownWebKit();
249#ifdef _CRTDBG_MAP_ALLOC
250    _CrtDumpMemoryLeaks();
251#endif
252
253    // Shut down COM.
254    OleUninitialize();
255
256    return static_cast<int>(msg.wParam);
257}
258
259ATOM MyRegisterClass(HINSTANCE hInstance)
260{
261    WNDCLASSEX wcex;
262
263    wcex.cbSize = sizeof(WNDCLASSEX);
264
265    wcex.style          = CS_HREDRAW | CS_VREDRAW;
266    wcex.lpfnWndProc    = WndProc;
267    wcex.cbClsExtra     = 0;
268    wcex.cbWndExtra     = 0;
269    wcex.hInstance      = hInstance;
270    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINLAUNCHER));
271    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
272    wcex.hbrBackground  = 0;
273    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WINLAUNCHER);
274    wcex.lpszClassName  = szWindowClass;
275    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
276
277    return RegisterClassEx(&wcex);
278}
279
280BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
281{
282   hInst = hInstance; // Store instance handle in our global variable
283
284   hMainWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
285      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
286
287   if (!hMainWnd)
288      return FALSE;
289
290   ShowWindow(hMainWnd, nCmdShow);
291   UpdateWindow(hMainWnd);
292
293   return TRUE;
294}
295
296static BOOL CALLBACK AbortProc(HDC hDC, int Error)
297{
298    MSG msg;
299    while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
300        ::TranslateMessage(&msg);
301        ::DispatchMessage(&msg);
302    }
303
304    return TRUE;
305}
306
307static HDC getPrinterDC()
308{
309    PRINTDLG pdlg;
310    memset(&pdlg, 0, sizeof(PRINTDLG));
311    pdlg.lStructSize = sizeof(PRINTDLG);
312    pdlg.Flags = PD_PRINTSETUP | PD_RETURNDC;
313
314    ::PrintDlg(&pdlg);
315
316    return pdlg.hDC;
317}
318
319static void initDocStruct(DOCINFO* di, TCHAR* docname)
320{
321    memset(di, 0, sizeof(DOCINFO));
322    di->cbSize = sizeof(DOCINFO);
323    di->lpszDocName = docname;
324}
325
326void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
327{
328    HDC printDC = getPrinterDC();
329    if (!printDC) {
330        ::MessageBoxW(0, L"Error creating printing DC", L"Error", MB_APPLMODAL | MB_OK);
331        return;
332    }
333
334    if (::SetAbortProc(printDC, AbortProc) == SP_ERROR) {
335        ::MessageBoxW(0, L"Error setting up AbortProc", L"Error", MB_APPLMODAL | MB_OK);
336        return;
337    }
338
339    IWebFrame* frame = 0;
340    IWebFramePrivate* framePrivate = 0;
341    if (FAILED(gWebView->mainFrame(&frame)))
342        goto exit;
343
344    if (FAILED(frame->QueryInterface(&framePrivate)))
345        goto exit;
346
347    framePrivate->setInPrintingMode(TRUE, printDC);
348
349    UINT pageCount = 0;
350    framePrivate->getPrintedPageCount(printDC, &pageCount);
351
352    DOCINFO di;
353    initDocStruct(&di, L"WebKit Doc");
354    ::StartDoc(printDC, &di);
355
356    // FIXME: Need CoreGraphics implementation
357    void* graphicsContext = 0;
358    for (size_t page = 1; page <= pageCount; ++page) {
359        ::StartPage(printDC);
360        framePrivate->spoolPages(printDC, page, page, graphicsContext);
361        ::EndPage(printDC);
362    }
363
364    framePrivate->setInPrintingMode(FALSE, printDC);
365
366    ::EndDoc(printDC);
367    ::DeleteDC(printDC);
368
369exit:
370    if (frame)
371        frame->Release();
372    if (framePrivate)
373        framePrivate->Release();
374}
375
376LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
377{
378    int wmId, wmEvent;
379
380    switch (message) {
381    case WM_COMMAND:
382        wmId    = LOWORD(wParam);
383        wmEvent = HIWORD(wParam);
384        // Parse the menu selections:
385        switch (wmId) {
386            case IDM_ABOUT:
387                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
388                break;
389            case IDM_EXIT:
390                DestroyWindow(hWnd);
391                break;
392            case IDM_PRINT:
393                PrintView(hWnd, message, wParam, lParam);
394                break;
395            default:
396                return DefWindowProc(hWnd, message, wParam, lParam);
397        }
398        break;
399    case WM_DESTROY:
400        PostQuitMessage(0);
401        break;
402    case WM_SIZE:
403        if (!gWebView)
404            break;
405        resizeSubViews();
406        break;
407    default:
408        return DefWindowProc(hWnd, message, wParam, lParam);
409    }
410    return 0;
411}
412
413
414#define MAX_URL_LENGTH  1024
415
416LRESULT CALLBACK MyEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
417{
418    switch (message) {
419        case WM_CHAR:
420            if (wParam == 13) { // Enter Key
421                wchar_t strPtr[MAX_URL_LENGTH];
422                *((LPWORD)strPtr) = MAX_URL_LENGTH;
423                int strLen = SendMessage(hDlg, EM_GETLINE, 0, (LPARAM)strPtr);
424
425                BSTR bstr = SysAllocStringLen(strPtr, strLen);
426                loadURL(bstr);
427                SysFreeString(bstr);
428
429                return 0;
430            } else
431                return (LRESULT)CallWindowProc((WNDPROC)DefEditProc,hDlg,message,wParam,lParam);
432            break;
433        default:
434             return (LRESULT)CallWindowProc((WNDPROC)DefEditProc,hDlg,message,wParam,lParam);
435        break;
436    }
437}
438
439
440// Message handler for about box.
441INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
442{
443    UNREFERENCED_PARAMETER(lParam);
444    switch (message) {
445    case WM_INITDIALOG:
446        return (INT_PTR)TRUE;
447
448    case WM_COMMAND:
449        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
450            EndDialog(hDlg, LOWORD(wParam));
451            return (INT_PTR)TRUE;
452        }
453        break;
454    }
455    return (INT_PTR)FALSE;
456}
457
458static void loadURL(BSTR urlBStr)
459{
460    IWebFrame* frame = 0;
461    IWebMutableURLRequest* request = 0;
462
463    static BSTR methodBStr = SysAllocString(TEXT("GET"));
464
465    if (urlBStr && urlBStr[0] && (PathFileExists(urlBStr) || PathIsUNC(urlBStr))) {
466        TCHAR fileURL[INTERNET_MAX_URL_LENGTH];
467        DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]);
468
469        if (SUCCEEDED(UrlCreateFromPath(urlBStr, fileURL, &fileURLLength, 0)))
470            SysReAllocString(&urlBStr, fileURL);
471    }
472
473    HRESULT hr = gWebView->mainFrame(&frame);
474    if (FAILED(hr))
475        goto exit;
476
477    hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
478    if (FAILED(hr))
479        goto exit;
480
481    hr = request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
482    if (FAILED(hr))
483        goto exit;
484
485    hr = request->setHTTPMethod(methodBStr);
486    if (FAILED(hr))
487        goto exit;
488
489    hr = frame->loadRequest(request);
490    if (FAILED(hr))
491        goto exit;
492
493    SetFocus(gViewWindow);
494
495exit:
496    if (frame)
497        frame->Release();
498    if (request)
499        request->Release();
500}
501