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 35 static NSString *defaultURL = @"http://www.webkit.org/"; 36 37 @implementation BrowserAppDelegate 38 39 void 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 65 static 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 80 static 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 89 static 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 98 static 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 107 static 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