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