0b4e17051f8d89ff50e25dc6c3bee08f5c95969c
[WebKit.git] / WebKitTools / MiniBrowser / mac / BrowserWindowController.m
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "BrowserWindowController.h"
27
28 #import <WebKit2/WKPagePrivate.h>
29 #import <WebKit2/WKStringCF.h>
30 #import <WebKit2/WKURLCF.h>
31
32 @interface BrowserWindowController ()
33 - (void)didStartProgress;
34 - (void)didChangeProgress:(double)value;
35 - (void)didFinishProgress;
36 - (void)didStartProvisionalLoadForFrame:(WKFrameRef)frame;
37 - (void)didCommitLoadForFrame:(WKFrameRef)frame;
38 - (void)didReceiveServerRedirectForProvisionalLoadForFrame:(WKFrameRef)frame;
39 - (void)didFailProvisionalLoadWithErrorForFrame:(WKFrameRef)frame;
40 - (void)didFailLoadWithErrorForFrame:(WKFrameRef)frame;
41 @end
42
43 @implementation BrowserWindowController
44
45 - (id)initWithPageNamespace:(WKPageNamespaceRef)pageNamespace
46 {
47     if ((self = [super initWithWindowNibName:@"BrowserWindow"]))
48         _pageNamespace = WKRetain(pageNamespace);
49     
50     return self;
51 }
52
53 - (void)dealloc
54 {
55     assert(!_pageNamespace);
56     [super dealloc];
57 }
58
59 - (IBAction)fetch:(id)sender
60 {
61     CFURLRef cfURL = CFURLCreateWithString(0, (CFStringRef)[urlText stringValue], 0);
62     WKURLRef url = WKURLCreateWithCFURL(cfURL);
63     CFRelease(cfURL);
64
65     WKPageLoadURL(_webView.pageRef, url);
66     WKRelease(url);
67 }
68
69 - (IBAction)showHideWebView:(id)sender
70 {
71     BOOL hidden = ![_webView isHidden];
72     
73     [_webView setHidden:hidden];
74 }
75
76 - (IBAction)removeReinsertWebView:(id)sender
77 {
78     if ([_webView window]) {
79         [_webView retain];
80         [_webView removeFromSuperview]; 
81     } else {
82         [containerView addSubview:_webView];
83         [_webView release];
84     }
85 }
86
87 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
88 {
89     if ([menuItem action] == @selector(showHideWebView:))
90         [menuItem setTitle:[_webView isHidden] ? @"Show Web View" : @"Hide Web View"];
91     else if ([menuItem action] == @selector(removeReinsertWebView:))
92         [menuItem setTitle:[_webView window] ? @"Remove Web View" : @"Insert Web View"];
93     return YES;
94 }
95
96 - (IBAction)reload:(id)sender
97 {
98     WKPageReload(_webView.pageRef);
99 }
100
101 - (IBAction)forceRepaint:(id)sender
102 {
103     [_webView setNeedsDisplay:YES];
104 }
105
106 - (IBAction)goBack:(id)sender
107 {
108     WKPageGoBack(_webView.pageRef);
109 }
110
111 - (IBAction)goForward:(id)sender
112 {
113     WKPageGoForward(_webView.pageRef);
114 }
115
116 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
117 {
118     SEL action = [item action];
119     
120     if (action == @selector(goBack:))
121         return _webView && WKPageCanGoBack(_webView.pageRef);
122     
123     if (action == @selector(goForward:))
124         return _webView && WKPageCanGoForward(_webView.pageRef);
125     
126     return YES;
127 }
128
129 - (void)validateToolbar
130 {
131     [toolbar validateVisibleItems];
132 }
133
134 - (BOOL)windowShouldClose:(id)sender
135 {
136     LOG(@"windowShouldClose");
137     BOOL canCloseImmediately = WKPageTryClose(_webView.pageRef);
138     return canCloseImmediately;
139 }
140
141 - (void)windowWillClose:(NSNotification *)notification
142 {
143     WKRelease(_pageNamespace);
144     _pageNamespace = 0;
145 }
146
147 - (void)applicationTerminating
148 {
149     WKPageClose(_webView.pageRef);
150     WKRelease(_webView.pageRef);
151 }
152
153 #pragma mark Loader Client Callbacks
154
155 static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
156 {
157     [(BrowserWindowController *)clientInfo didStartProvisionalLoadForFrame:frame];
158 }
159
160 static void didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
161 {
162     [(BrowserWindowController *)clientInfo didReceiveServerRedirectForProvisionalLoadForFrame:frame];
163 }
164
165 static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
166 {
167     [(BrowserWindowController *)clientInfo didFailProvisionalLoadWithErrorForFrame:frame];
168 }
169
170 static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
171 {
172     [(BrowserWindowController *)clientInfo didCommitLoadForFrame:frame];
173 }
174
175 static void didFinishDocumentLoadForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
176 {
177     LOG(@"didFinishDocumentLoadForFrame");
178 }
179
180 static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
181 {
182     LOG(@"didFinishLoadForFrame");
183 }
184
185 static void didFailLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
186 {
187     [(BrowserWindowController *)clientInfo didFailLoadWithErrorForFrame:frame];
188 }
189
190 static void didReceiveTitleForFrame(WKPageRef page, WKStringRef title, WKFrameRef frame, const void *clientInfo)
191 {
192     CFStringRef cfTitle = WKStringCopyCFString(0, title);
193     LOG(@"didReceiveTitleForFrame \"%@\"", (NSString *)cfTitle);
194     CFRelease(cfTitle);
195 }
196
197 static void didFirstLayoutForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
198 {
199     LOG(@"didFirstLayoutForFrame");
200 }
201
202 static void didFirstVisuallyNonEmptyLayoutForFrame(WKPageRef page, WKFrameRef frame, const void *clientInfo)
203 {
204     LOG(@"didFirstVisuallyNonEmptyLayoutForFrame");
205 }
206
207 static void didStartProgress(WKPageRef page, const void *clientInfo)
208 {
209     [(BrowserWindowController *)clientInfo didStartProgress];
210 }
211
212 static void didChangeProgress(WKPageRef page, const void *clientInfo)
213 {
214     [(BrowserWindowController *)clientInfo didChangeProgress:WKPageGetEstimatedProgress(page)];
215 }
216
217 static void didFinishProgress(WKPageRef page, const void *clientInfo)
218 {
219     [(BrowserWindowController *)clientInfo didFinishProgress];
220 }
221
222 static void didBecomeUnresponsive(WKPageRef page, const void *clientInfo)
223 {
224     LOG(@"didBecomeUnresponsive");
225 }
226
227 static void didBecomeResponsive(WKPageRef page, const void *clientInfo)
228 {
229     LOG(@"didBecomeResponsive");
230 }
231
232 static void processDidExit(WKPageRef page, const void *clientInfo)
233 {
234     LOG(@"processDidExit");
235 }
236
237 static void didChangeBackForwardList(WKPageRef page, const void *clientInfo)
238 {
239     [(BrowserWindowController *)clientInfo validateToolbar];
240 }
241
242 #pragma mark Policy Client Callbacks
243
244 static void decidePolicyForNavigationAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
245 {
246     LOG(@"decidePolicyForNavigationAction");
247     WKFramePolicyListenerUse(listener);
248 }
249
250 static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
251 {
252     LOG(@"decidePolicyForNewWindowAction");
253     WKFramePolicyListenerUse(listener);
254 }
255
256 static void decidePolicyForMIMEType(WKPageRef page, WKStringRef MIMEType, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
257 {
258     WKFramePolicyListenerUse(listener);
259 }
260
261 #pragma mark UI Client Callbacks
262
263 static WKPageRef createNewPage(WKPageRef page, const void* clientInfo)
264 {
265     LOG(@"createNewPage");
266     BrowserWindowController *controller = [[BrowserWindowController alloc] initWithPageNamespace:WKPageGetPageNamespace(page)];
267     [controller loadWindow];
268
269     return controller->_webView.pageRef;
270 }
271
272 static void showPage(WKPageRef page, const void *clientInfo)
273 {
274     LOG(@"showPage");
275     [[(BrowserWindowController *)clientInfo window] orderFront:nil];
276 }
277
278 static void closePage(WKPageRef page, const void *clientInfo)
279 {
280     LOG(@"closePage");
281     WKPageClose(page);
282     [[(BrowserWindowController *)clientInfo window] close];
283     WKRelease(page);
284 }
285
286 static void runJavaScriptAlert(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
287 {
288     NSAlert* alert = [[NSAlert alloc] init];
289
290     WKURLRef wkURL = WKFrameCopyURL(frame);
291     CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
292     WKRelease(wkURL);
293
294     [alert setMessageText:[NSString stringWithFormat:@"JavaScript alert dialog from %@.", [(NSURL *)cfURL absoluteString]]];
295     CFRelease(cfURL);
296
297     CFStringRef cfMessage = WKStringCopyCFString(0, message);
298     [alert setInformativeText:(NSString *)cfMessage];
299     CFRelease(cfMessage);
300
301     [alert addButtonWithTitle:@"OK"];
302
303     [alert runModal];
304     [alert release];
305 }
306
307 static bool runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
308 {
309     NSAlert* alert = [[NSAlert alloc] init];
310
311     WKURLRef wkURL = WKFrameCopyURL(frame);
312     CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
313     WKRelease(wkURL);
314
315     [alert setMessageText:[NSString stringWithFormat:@"JavaScript confirm dialog from %@.", [(NSURL *)cfURL absoluteString]]];
316     CFRelease(cfURL);
317
318     CFStringRef cfMessage = WKStringCopyCFString(0, message);
319     [alert setInformativeText:(NSString *)cfMessage];
320     CFRelease(cfMessage);
321
322     [alert addButtonWithTitle:@"OK"];
323     [alert addButtonWithTitle:@"Cancel"];
324
325     NSInteger button = [alert runModal];
326     [alert release];
327
328     return button == NSAlertFirstButtonReturn;
329 }
330
331 static WKStringRef runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, const void* clientInfo)
332 {
333     NSAlert* alert = [[NSAlert alloc] init];
334
335     WKURLRef wkURL = WKFrameCopyURL(frame);
336     CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
337     WKRelease(wkURL);
338
339     [alert setMessageText:[NSString stringWithFormat:@"JavaScript prompt dialog from %@.", [(NSURL *)cfURL absoluteString]]];
340     CFRelease(cfURL);
341
342     CFStringRef cfMessage = WKStringCopyCFString(0, message);
343     [alert setInformativeText:(NSString *)cfMessage];
344     CFRelease(cfMessage);
345
346     [alert addButtonWithTitle:@"OK"];
347     [alert addButtonWithTitle:@"Cancel"];
348
349     NSTextField* input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
350     CFStringRef cfDefaultValue = WKStringCopyCFString(0, defaultValue);
351     [input setStringValue:(NSString *)cfDefaultValue];
352     CFRelease(cfDefaultValue);
353
354     [alert setAccessoryView:input];
355
356     NSInteger button = [alert runModal];
357
358     NSString* result = nil;
359     if (button == NSAlertFirstButtonReturn) {
360         [input validateEditing];
361         result = [input stringValue];
362     }
363
364     [alert release];
365
366     if (!result)
367         return 0;
368     return WKStringCreateWithCFString((CFStringRef)result);
369 }
370
371 - (void)awakeFromNib
372 {
373     _webView = [[WKView alloc] initWithFrame:[containerView frame] pageNamespaceRef:_pageNamespace];
374
375     [containerView addSubview:_webView];
376     [_webView setFrame:[containerView frame]];
377     
378     [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
379     
380     WKPageLoaderClient loadClient = {
381         0,      /* version */
382         self,   /* clientInfo */
383         didStartProvisionalLoadForFrame,
384         didReceiveServerRedirectForProvisionalLoadForFrame,
385         didFailProvisionalLoadWithErrorForFrame,
386         didCommitLoadForFrame,
387         didFinishDocumentLoadForFrame,
388         didFinishLoadForFrame,
389         didFailLoadWithErrorForFrame,
390         didReceiveTitleForFrame,
391         didFirstLayoutForFrame,
392         didFirstVisuallyNonEmptyLayoutForFrame,
393         didStartProgress,
394         didChangeProgress,
395         didFinishProgress,
396         didBecomeUnresponsive,
397         didBecomeResponsive,
398         processDidExit,
399         didChangeBackForwardList
400     };
401     WKPageSetPageLoaderClient(_webView.pageRef, &loadClient);
402     
403     WKPagePolicyClient policyClient = {
404         0,          /* version */
405         self,       /* clientInfo */
406         decidePolicyForNavigationAction,
407         decidePolicyForNewWindowAction,
408         decidePolicyForMIMEType
409     };
410     WKPageSetPagePolicyClient(_webView.pageRef, &policyClient);
411
412     WKPageUIClient uiClient = {
413         0,          /* version */
414         self,       /* clientInfo */
415         createNewPage,
416         showPage,
417         closePage,
418         runJavaScriptAlert,
419         runJavaScriptConfirm,
420         runJavaScriptPrompt,
421         0           /* contentsSizeChanged */
422     };
423     WKPageSetPageUIClient(_webView.pageRef, &uiClient);
424 }
425
426 - (void)didStartProgress
427 {
428     [progressIndicator setDoubleValue:0.0];
429     [progressIndicator setHidden:NO];
430 }
431
432 - (void)didChangeProgress:(double)value
433 {
434     [progressIndicator setDoubleValue:value];
435 }
436
437 - (void)didFinishProgress
438 {
439     [progressIndicator setHidden:YES];
440     [progressIndicator setDoubleValue:1.0];
441 }
442
443 - (void)updateProvisionalURLForFrame:(WKFrameRef)frame
444 {
445     WKURLRef url = WKFrameCopyProvisionalURL(frame);
446     if (!url)
447         return;
448
449     CFURLRef cfSourceURL = WKURLCopyCFURL(0, url);
450     WKRelease(url);
451
452     [urlText setStringValue:(NSString*)CFURLGetString(cfSourceURL)];
453     CFRelease(cfSourceURL);
454 }
455
456 - (void)didStartProvisionalLoadForFrame:(WKFrameRef)frame
457 {
458     if (!WKFrameIsMainFrame(frame))
459         return;
460
461     [self updateProvisionalURLForFrame:frame];
462 }
463
464 - (void)didReceiveServerRedirectForProvisionalLoadForFrame:(WKFrameRef)frame
465 {
466     if (!WKFrameIsMainFrame(frame))
467         return;
468
469     [self updateProvisionalURLForFrame:frame];
470 }
471
472 - (void)didFailProvisionalLoadWithErrorForFrame:(WKFrameRef)frame
473 {
474     if (!WKFrameIsMainFrame(frame))
475         return;
476
477     [self updateProvisionalURLForFrame:frame];
478 }
479
480 - (void)didFailLoadWithErrorForFrame:(WKFrameRef)frame
481 {
482     if (!WKFrameIsMainFrame(frame))
483         return;
484
485     [self updateProvisionalURLForFrame:frame];
486 }
487
488 - (void)didCommitLoadForFrame:(WKFrameRef)frame
489 {
490 }
491
492 - (void)loadURLString:(NSString *)urlString
493 {
494     // FIXME: We shouldn't have to set the url text here.
495     [urlText setStringValue:urlString];
496     [self fetch:nil];
497 }
498
499 @end