99a500d3994fc1a99e2b8d3f0bfbbe67b59d23ea
[WebKit-https.git] / Tools / MiniBrowser / mac / AppDelegate.m
1 /*
2  * Copyright (C) 2010-2016 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 "ExtensionManagerWindowController.h"
29 #import "SettingsController.h"
30 #import "WK1BrowserWindowController.h"
31 #import "WK2BrowserWindowController.h"
32 #import <WebKit/WKPreferencesPrivate.h>
33 #import <WebKit/WKProcessPoolPrivate.h>
34 #import <WebKit/WKUserContentControllerPrivate.h>
35 #import <WebKit/WKWebViewConfigurationPrivate.h>
36 #import <WebKit/WKWebsiteDataStorePrivate.h>
37 #import <WebKit/WebKit.h>
38 #import <WebKit/_WKProcessPoolConfiguration.h>
39 #import <WebKit/_WKUserContentExtensionStore.h>
40
41 #if WK_API_ENABLED
42 #import <WebKit/_WKExperimentalFeature.h>
43 #import <WebKit/_WKInternalDebugFeature.h>
44 #endif
45
46 enum {
47     WebKit1NewWindowTag = 1,
48     WebKit2NewWindowTag = 2,
49     WebKit1NewEditorTag = 3,
50     WebKit2NewEditorTag = 4
51 };
52
53 @interface NSApplication (TouchBar)
54 @property (getter=isAutomaticCustomizeTouchBarMenuItemEnabled) BOOL automaticCustomizeTouchBarMenuItemEnabled;
55 @end
56
57 @implementation BrowserAppDelegate
58
59 - (id)init
60 {
61     self = [super init];
62     if (self) {
63         _browserWindowControllers = [[NSMutableSet alloc] init];
64 #if WK_API_ENABLED
65         _extensionManagerWindowController = [[ExtensionManagerWindowController alloc] init];
66 #endif
67     }
68
69     return self;
70 }
71
72 - (void)awakeFromNib
73 {
74     NSMenuItem *item = [[NSMenuItem alloc] init];
75     [item setSubmenu:[[SettingsController shared] menu]];
76
77 #if WK_API_ENABLED
78     if ([[SettingsController shared] usesGameControllerFramework])
79         [WKProcessPool _forceGameControllerFramework];
80 #endif
81
82     [[NSApp mainMenu] insertItem:[item autorelease] atIndex:[[NSApp mainMenu] indexOfItemWithTitle:@"Debug"]];
83
84     if ([NSApp respondsToSelector:@selector(setAutomaticCustomizeTouchBarMenuItemEnabled:)])
85         [NSApp setAutomaticCustomizeTouchBarMenuItemEnabled:YES];
86 }
87
88 #if WK_API_ENABLED
89 static WKWebViewConfiguration *defaultConfiguration()
90 {
91     static WKWebViewConfiguration *configuration;
92
93     if (!configuration) {
94         configuration = [[WKWebViewConfiguration alloc] init];
95         configuration.preferences._fullScreenEnabled = YES;
96         configuration.preferences._developerExtrasEnabled = YES;
97         configuration.preferences._mediaDevicesEnabled = YES;
98         configuration.preferences._mockCaptureDevicesEnabled = YES;
99
100         _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
101         processConfiguration.diskCacheSpeculativeValidationEnabled = ![SettingsController shared].networkCacheSpeculativeRevalidationDisabled;
102         if ([SettingsController shared].perWindowWebProcessesDisabled)
103             processConfiguration.maximumProcessCount = 1;
104         if ([SettingsController shared].processSwapOnNavigationEnabled)
105             processConfiguration.processSwapsOnNavigation = true;
106         if ([SettingsController shared].processSwapOnWindowOpenWithOpenerEnabled)
107             processConfiguration.processSwapsOnWindowOpenWithOpener = true;
108         
109         configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease];
110
111 #if WK_API_ENABLED
112         NSArray<_WKExperimentalFeature *> *experimentalFeatures = [WKPreferences _experimentalFeatures];
113         for (_WKExperimentalFeature *feature in experimentalFeatures) {
114             BOOL enabled;
115             if ([[NSUserDefaults standardUserDefaults] objectForKey:feature.key])
116                 enabled = [[NSUserDefaults standardUserDefaults] boolForKey:feature.key];
117             else
118                 enabled = [feature defaultValue];
119             [configuration.preferences _setEnabled:enabled forExperimentalFeature:feature];
120         }
121
122         NSArray<_WKInternalDebugFeature *> *internalDebugFeatures = [WKPreferences _internalDebugFeatures];
123         for (_WKInternalDebugFeature *feature in internalDebugFeatures) {
124             BOOL enabled;
125             if ([[NSUserDefaults standardUserDefaults] objectForKey:feature.key])
126                 enabled = [[NSUserDefaults standardUserDefaults] boolForKey:feature.key];
127             else
128                 enabled = [feature defaultValue];
129             [configuration.preferences _setEnabled:enabled forInternalDebugFeature:feature];
130         }
131 #endif
132     }
133
134     configuration.suppressesIncrementalRendering = [SettingsController shared].incrementalRenderingSuppressed;
135     configuration.websiteDataStore._resourceLoadStatisticsEnabled = [SettingsController shared].resourceLoadStatisticsEnabled;
136     return configuration;
137 }
138
139 WKPreferences *defaultPreferences()
140 {
141     return defaultConfiguration().preferences;
142 }
143
144 #endif
145
146 - (BrowserWindowController *)createBrowserWindowController:(id)sender
147 {
148     BrowserWindowController *controller = nil;
149     BOOL useWebKit2 = NO;
150     BOOL makeEditable = NO;
151
152     if (![sender respondsToSelector:@selector(tag)]) {
153         useWebKit2 = [SettingsController shared].useWebKit2ByDefault;
154         makeEditable = [SettingsController shared].createEditorByDefault;
155     } else {
156         useWebKit2 = [sender tag] == WebKit2NewWindowTag || [sender tag] == WebKit2NewEditorTag;
157         makeEditable = [sender tag] == WebKit1NewEditorTag || [sender tag] == WebKit2NewEditorTag;
158     }
159
160     if (!useWebKit2)
161         controller = [[WK1BrowserWindowController alloc] initWithWindowNibName:@"BrowserWindow"];
162 #if WK_API_ENABLED
163     else
164         controller = [[WK2BrowserWindowController alloc] initWithConfiguration:defaultConfiguration()];
165 #endif
166
167     if (makeEditable)
168         controller.editable = YES;
169
170     if (!controller)
171         return nil;
172
173     [_browserWindowControllers addObject:controller];
174
175     return controller;
176 }
177
178 - (IBAction)newWindow:(id)sender
179 {
180     BrowserWindowController *controller = [self createBrowserWindowController:sender];
181     if (!controller)
182         return;
183
184     [[controller window] makeKeyAndOrderFront:sender];
185     [controller loadURLString:[SettingsController shared].defaultURL];
186 }
187
188 - (IBAction)newPrivateWindow:(id)sender
189 {
190 #if WK_API_ENABLED
191     WKWebViewConfiguration *privateConfiguraton = [defaultConfiguration() copy];
192     privateConfiguraton.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
193
194     BrowserWindowController *controller = [[WK2BrowserWindowController alloc] initWithConfiguration:privateConfiguraton];
195     [privateConfiguraton release];
196
197     [[controller window] makeKeyAndOrderFront:sender];
198     [_browserWindowControllers addObject:controller];
199
200     [controller loadURLString:[SettingsController shared].defaultURL];
201 #endif
202 }
203
204 - (IBAction)newEditorWindow:(id)sender
205 {
206     BrowserWindowController *controller = [self createBrowserWindowController:sender];
207     if (!controller)
208         return;
209
210     [[controller window] makeKeyAndOrderFront:sender];
211     [controller loadHTMLString:@"<html><body></body></html>"];
212 }
213
214 - (void)browserWindowWillClose:(NSWindow *)window
215 {
216     [_browserWindowControllers removeObject:window.windowController];
217 }
218
219 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
220 {
221     WebHistory *webHistory = [[WebHistory alloc] init];
222     [WebHistory setOptionalSharedHistory:webHistory];
223     [webHistory release];
224
225     [self _updateNewWindowKeyEquivalents];
226
227     if ([SettingsController shared].createEditorByDefault)
228         [self newEditorWindow:self];
229     else
230         [self newWindow:self];
231 }
232
233 - (BrowserWindowController *)frontmostBrowserWindowController
234 {
235     for (NSWindow* window in [NSApp windows]) {
236         id delegate = [window delegate];
237
238         if (![delegate isKindOfClass:[BrowserWindowController class]])
239             continue;
240
241         BrowserWindowController *controller = (BrowserWindowController *)delegate;
242         assert([_browserWindowControllers containsObject:controller]);
243         return controller;
244     }
245
246     return nil;
247 }
248
249 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
250 {
251     BrowserWindowController *controller = [self createBrowserWindowController:nil];
252     if (!controller)
253         return NO;
254
255     [controller.window makeKeyAndOrderFront:self];
256     [controller loadURLString:[NSURL fileURLWithPath:filename].absoluteString];
257     return YES;
258 }
259
260 - (IBAction)openDocument:(id)sender
261 {
262     BrowserWindowController *browserWindowController = [self frontmostBrowserWindowController];
263
264     if (browserWindowController) {
265         NSOpenPanel *openPanel = [[NSOpenPanel openPanel] retain];
266         [openPanel beginSheetModalForWindow:browserWindowController.window completionHandler:^(NSInteger result) {
267             if (result != NSModalResponseOK)
268                 return;
269
270             NSURL *url = [openPanel.URLs objectAtIndex:0];
271             [browserWindowController loadURLString:[url absoluteString]];
272         }];
273         return;
274     }
275
276     NSOpenPanel *openPanel = [NSOpenPanel openPanel];
277     [openPanel beginWithCompletionHandler:^(NSInteger result) {
278         if (result != NSModalResponseOK)
279             return;
280
281         BrowserWindowController *controller = [self createBrowserWindowController:nil];
282         [controller.window makeKeyAndOrderFront:self];
283
284         NSURL *url = [openPanel.URLs objectAtIndex:0];
285         [controller loadURLString:[url absoluteString]];
286     }];
287 }
288
289 - (void)didChangeSettings
290 {
291     [self _updateNewWindowKeyEquivalents];
292
293     // Let all of the BrowserWindowControllers know that a setting changed, so they can attempt to dynamically update.
294     for (BrowserWindowController *browserWindowController in _browserWindowControllers)
295         [browserWindowController didChangeSettings];
296 }
297
298 - (void)_updateNewWindowKeyEquivalents
299 {
300     NSEventModifierFlags webKit1Flags = [SettingsController shared].useWebKit2ByDefault ? NSEventModifierFlagOption : 0;
301     NSEventModifierFlags webKit2Flags = [SettingsController shared].useWebKit2ByDefault ? 0 : NSEventModifierFlagOption;
302
303     NSString *normalWindowEquivalent = [SettingsController shared].createEditorByDefault ? @"N" : @"n";
304     NSString *editorEquivalent = [SettingsController shared].createEditorByDefault ? @"n" : @"N";
305
306     _newWebKit1WindowItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | webKit1Flags;
307     _newWebKit2WindowItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | webKit2Flags;
308     _newWebKit1EditorItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | webKit1Flags;
309     _newWebKit2EditorItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | webKit2Flags;
310
311     _newWebKit1WindowItem.keyEquivalent = normalWindowEquivalent;
312     _newWebKit2WindowItem.keyEquivalent = normalWindowEquivalent;
313     _newWebKit1EditorItem.keyEquivalent = editorEquivalent;
314     _newWebKit2EditorItem.keyEquivalent = editorEquivalent;
315 }
316
317 - (IBAction)showExtensionsManager:(id)sender
318 {
319 #if WK_API_ENABLED
320     [_extensionManagerWindowController showWindow:sender];
321 #endif
322 }
323
324 #if WK_API_ENABLED
325 - (WKUserContentController *)userContentContoller
326 {
327     return defaultConfiguration().userContentController;
328 }
329
330 - (IBAction)fetchDefaultStoreWebsiteData:(id)sender
331 {
332     [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray *websiteDataRecords) {
333         NSLog(@"did fetch default store website data %@.", websiteDataRecords);
334     }];
335 }
336
337 - (IBAction)fetchAndClearDefaultStoreWebsiteData:(id)sender
338 {
339     [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray *websiteDataRecords) {
340         [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] forDataRecords:websiteDataRecords completionHandler:^{
341             [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray *websiteDataRecords) {
342                 NSLog(@"did clear default store website data, after clearing data is %@.", websiteDataRecords);
343             }];
344         }];
345     }];
346 }
347
348 - (IBAction)clearDefaultStoreWebsiteData:(id)sender
349 {
350     [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^{
351         NSLog(@"Did clear default store website data.");
352     }];
353 }
354
355 #endif
356
357 @end