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 "AppDelegate.h" 27 28#import "BrowserWindowController.h" 29#import "BrowserStatisticsWindowController.h" 30 31#import <WebKit2/WKContextPrivate.h> 32#import <WebKit2/WKStringCF.h> 33#import <WebKit2/WKURLCF.h> 34 35static NSString *defaultURL = @"http://www.webkit.org/"; 36 37@implementation BrowserAppDelegate 38 39void didRecieveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void *clientInfo) 40{ 41 CFStringRef cfMessageName = WKStringCopyCFString(0, messageName); 42 43 WKTypeID typeID = WKGetTypeID(messageBody); 44 if (typeID == WKStringGetTypeID()) { 45 CFStringRef cfMessageBody = WKStringCopyCFString(0, (WKStringRef)messageBody); 46 LOG(@"ContextInjectedBundleClient - didRecieveMessage - MessageName: %@ MessageBody %@", cfMessageName, cfMessageBody); 47 CFRelease(cfMessageBody); 48 } else { 49 LOG(@"ContextInjectedBundleClient - didRecieveMessage - MessageName: %@ (MessageBody Unhandeled)\n", cfMessageName); 50 } 51 52 CFRelease(cfMessageName); 53 54 WKStringRef newMessageName = WKStringCreateWithCFString(CFSTR("Response")); 55 WKStringRef newMessageBody = WKStringCreateWithCFString(CFSTR("Roger that!")); 56 57 WKContextPostMessageToInjectedBundle(context, newMessageName, newMessageBody); 58 59 WKRelease(newMessageName); 60 WKRelease(newMessageBody); 61} 62 63// MARK: History Client Callbacks 64 65static void didNavigateWithNavigationData(WKContextRef context, WKPageRef page, WKNavigationDataRef navigationData, WKFrameRef frame, const void *clientInfo) 66{ 67 WKStringRef wkTitle = WKNavigationDataCopyTitle(navigationData); 68 CFStringRef title = WKStringCopyCFString(0, wkTitle); 69 WKRelease(wkTitle); 70 71 WKURLRef wkURL = WKNavigationDataCopyURL(navigationData); 72 CFURLRef url = WKURLCopyCFURL(0, wkURL); 73 WKRelease(wkURL); 74 75 LOG(@"HistoryClient - didNavigateWithNavigationData - title: %@ - url: %@", title, url); 76 CFRelease(title); 77 CFRelease(url); 78} 79 80static void didPerformClientRedirect(WKContextRef context, WKPageRef page, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void *clientInfo) 81{ 82 CFURLRef cfSourceURL = WKURLCopyCFURL(0, sourceURL); 83 CFURLRef cfDestinationURL = WKURLCopyCFURL(0, destinationURL); 84 LOG(@"HistoryClient - didPerformClientRedirect - sourceURL: %@ - destinationURL: %@", cfSourceURL, cfDestinationURL); 85 CFRelease(cfSourceURL); 86 CFRelease(cfDestinationURL); 87} 88 89static void didPerformServerRedirect(WKContextRef context, WKPageRef page, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void *clientInfo) 90{ 91 CFURLRef cfSourceURL = WKURLCopyCFURL(0, sourceURL); 92 CFURLRef cfDestinationURL = WKURLCopyCFURL(0, destinationURL); 93 LOG(@"HistoryClient - didPerformServerRedirect - sourceURL: %@ - destinationURL: %@", cfSourceURL, cfDestinationURL); 94 CFRelease(cfSourceURL); 95 CFRelease(cfDestinationURL); 96} 97 98static void didUpdateHistoryTitle(WKContextRef context, WKPageRef page, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void *clientInfo) 99{ 100 CFStringRef cfTitle = WKStringCopyCFString(0, title); 101 CFURLRef cfURL = WKURLCopyCFURL(0, URL); 102 LOG(@"HistoryClient - didUpdateHistoryTitle - title: %@ - URL: %@", cfTitle, cfURL); 103 CFRelease(cfTitle); 104 CFRelease(cfURL); 105} 106 107static void populateVisitedLinks(WKContextRef context, const void *clientInfo) 108{ 109 LOG(@"HistoryClient - populateVisitedLinks"); 110} 111 112- (id)init 113{ 114 self = [super init]; 115 if (self) { 116 if ([NSEvent modifierFlags] & NSShiftKeyMask) 117 _currentProcessModel = kProcessModelSharedSecondaryThread; 118 else 119 _currentProcessModel = kProcessModelSharedSecondaryProcess; 120 121 WKContextHistoryClient historyClient = { 122 0, 123 self, 124 didNavigateWithNavigationData, 125 didPerformClientRedirect, 126 didPerformServerRedirect, 127 didUpdateHistoryTitle, 128 populateVisitedLinks 129 }; 130 131 _threadContext = WKContextGetSharedThreadContext(); 132 WKContextSetHistoryClient(_threadContext, &historyClient); 133 WKContextSetCacheModel(_threadContext, kWKCacheModelPrimaryWebBrowser); 134 135 CFStringRef bundlePathCF = (CFStringRef)[[NSBundle mainBundle] pathForAuxiliaryExecutable:@"WebBundle.bundle"]; 136 WKStringRef bundlePath = WKStringCreateWithCFString(bundlePathCF); 137 138 _processContext = WKContextCreateWithInjectedBundlePath(bundlePath); 139 140 WKContextInjectedBundleClient bundleClient = { 141 0, /* version */ 142 0, /* clientInfo */ 143 didRecieveMessageFromInjectedBundle, 144 0 145 }; 146 WKContextSetInjectedBundleClient(_processContext, &bundleClient); 147 WKContextSetHistoryClient(_processContext, &historyClient); 148 WKContextSetCacheModel(_processContext, kWKCacheModelPrimaryWebBrowser); 149 150 WKRelease(bundlePath); 151 } 152 153 return self; 154} 155 156- (IBAction)newWindow:(id)sender 157{ 158 BrowserWindowController *controller = [[BrowserWindowController alloc] initWithContext:[self getCurrentContext]]; 159 [[controller window] makeKeyAndOrderFront:sender]; 160 161 [controller loadURLString:defaultURL]; 162} 163 164- (WKContextRef)getCurrentContext 165{ 166 return (_currentProcessModel == kProcessModelSharedSecondaryThread) ? _threadContext : _processContext; 167} 168 169- (BOOL)validateMenuItem:(NSMenuItem *)menuItem 170{ 171 if ([menuItem action] == @selector(setSharedProcessProcessModel:)) 172 [menuItem setState:_currentProcessModel == kProcessModelSharedSecondaryProcess ? NSOnState : NSOffState]; 173 else if ([menuItem action] == @selector(setSharedThreadProcessModel:)) 174 [menuItem setState:_currentProcessModel == kProcessModelSharedSecondaryThread ? NSOnState : NSOffState]; 175 return YES; 176} 177 178- (void)_setProcessModel:(ProcessModel)processModel 179{ 180 if (processModel == _currentProcessModel) 181 return; 182 183 _currentProcessModel = processModel; 184} 185 186- (IBAction)setSharedProcessProcessModel:(id)sender 187{ 188 [self _setProcessModel:kProcessModelSharedSecondaryProcess]; 189} 190 191- (IBAction)setSharedThreadProcessModel:(id)sender 192{ 193 [self _setProcessModel:kProcessModelSharedSecondaryThread]; 194} 195 196- (IBAction)showStatisticsWindow:(id)sender 197{ 198 static BrowserStatisticsWindowController* windowController; 199 if (!windowController) 200 windowController = [[BrowserStatisticsWindowController alloc] initWithThreadedWKContextRef:_threadContext 201 processWKContextRef:_processContext]; 202 203 [[windowController window] makeKeyAndOrderFront:self]; 204} 205 206- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 207{ 208 [self newWindow:self]; 209} 210 211- (void)applicationWillTerminate:(NSNotification *)notification 212{ 213 NSArray* windows = [NSApp windows]; 214 for (NSWindow* window in windows) { 215 id delegate = [window delegate]; 216 if ([delegate isKindOfClass:[BrowserWindowController class]]) { 217 BrowserWindowController *controller = (BrowserWindowController *)delegate; 218 [controller applicationTerminating]; 219 } 220 } 221 222 WKRelease(_processContext); 223 _processContext = 0; 224} 225 226- (BrowserWindowController *)frontmostBrowserWindowController 227{ 228 NSArray* windows = [NSApp windows]; 229 for (NSWindow* window in windows) { 230 id delegate = [window delegate]; 231 if ([delegate isKindOfClass:[BrowserWindowController class]]) 232 return (BrowserWindowController *)delegate; 233 } 234 235 return 0; 236} 237 238- (IBAction)openDocument:(id)sender 239{ 240 NSOpenPanel *openPanel = [[NSOpenPanel openPanel] retain]; 241 [openPanel beginForDirectory:nil 242 file:nil 243 types:nil 244 modelessDelegate:self 245 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) 246 contextInfo:0]; 247} 248 249- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo 250{ 251 [sheet autorelease]; 252 if (returnCode != NSOKButton || ![[sheet filenames] count]) 253 return; 254 255 NSString* filePath = [[sheet filenames] objectAtIndex:0]; 256 257 BrowserWindowController *controller = [self frontmostBrowserWindowController]; 258 if (!controller) { 259 controller = [[BrowserWindowController alloc] initWithContext:[self getCurrentContext]]; 260 [[controller window] makeKeyAndOrderFront:self]; 261 } 262 263 [controller loadURLString:[[NSURL fileURLWithPath:filePath] absoluteString]]; 264} 265 266@end 267