Skip to content

Commit 1d12480

Browse files
committed
Update macOS app to use the same InterSpecServer functions as other targets (i.e., DesktopAppConfig, start_server, etc).
macOS users can now use the InterSpec_app_settings.json file in InterSpecs user data directory to set the various options.
1 parent a905a83 commit 1d12480

File tree

5 files changed

+112
-111
lines changed

5 files changed

+112
-111
lines changed

data/config/example_InterSpec_app_settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
"AllowTokenFreeSessions_Documentation": "Normally external sessions (i.e. 'View' -> 'Use in external browser') get assigned a one-time-use token that is required to load InterSpec into the browser. Without a valid token, you cant load a session in the browser. If you allow external sessions without tokens, then the token wont be needed - and any application that can access your localhost network can create a session and potentually access your data. It is not recomended to to enable this setting.",
1616

1717
"OpenDevTools": false,
18-
"OpenDevTools_Documentation": "Enables right-clicking on an element to open the WebView Dev Tools to allow debugging JavaScript errors you may run into (please report to InterSpec@sandia.gov if you find any)"
18+
"OpenDevTools_Documentation": "Enables right-clicking on an element to open the WebView Dev Tools to allow debugging JavaScript errors you may run into (please report to InterSpec@sandia.gov if you find any). On macOS you will still need to select 'Edit' -> 'Enable Web Inspector'."
1919
}

src/InterSpecApp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ void InterSpecApp::setupDomEnvironment()
301301
#endif
302302

303303
#if( BUILD_AS_OSX_APP && !PERFORM_DEVELOPER_CHECKS )
304-
root()->setAttributeValue( "oncontextmenu", "return false;" );
304+
domRoot()->setAttributeValue( "oncontextmenu", "return false;" );
305305
#endif
306306

307307
// Define some javascript to artificially trigger a resize event; this is a hack used a few

src/InterSpecServer.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,15 @@ int start_server( const char *process_name,
518518
return -10;
519519
}
520520

521+
// In case the Wt XML config file is relative to the base directory that contains "data"
522+
// but that isnt our CWD.
523+
string wt_config_file = xml_config_path;
524+
if( !SpecUtils::is_file(wt_config_file) )
525+
{
526+
const string trial = SpecUtils::append_path( relbasedir, wt_config_file );
527+
if( SpecUtils::is_file(trial) )
528+
wt_config_file = trial;
529+
}
521530

522531
//ToDo: should look into using '--approot' Wt Argument.
523532

@@ -532,7 +541,7 @@ int start_server( const char *process_name,
532541

533542
try
534543
{
535-
InterSpecServer::startWebServer( process_name, relbasedir, xml_config_path, server_port );
544+
InterSpecServer::startWebServer( process_name, relbasedir, wt_config_file, server_port );
536545
}catch( std::exception &e )
537546
{
538547
std::cerr << "\n\nCaught exception trying to start InterSpec server:\n\t"

target/osx/AppDelegate.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,13 @@
3333
@property (strong, nonatomic) NSString *fileNeedsOpening;
3434
@property (strong, nonatomic) NSString *UrlServingOn;
3535
@property (strong, nonatomic) NSString *UrlUniqueId;
36-
@property (strong, nonatomic) NSString *PreferenceDbPath;
3736

3837
@property (assign) IBOutlet NSWindow *window;
3938

4039
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
4140
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
4241
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
4342

44-
-(void)setDbDirectory;
45-
4643
-(void) terminated: (NSNotification *)notification;
4744
-(void) application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls;
4845
-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender;
@@ -52,6 +49,7 @@
5249
-(void)application:(NSApplication *)app willEncodeRestorableState:(NSCoder *)coder;
5350
-(void)applicationWillTerminate:(NSNotification *)notification;
5451

52+
-(void)enableWebInspector;
5553

5654
-(NSString *)generateSessionToken;
5755
@end

target/osx/AppDelegate.mm

Lines changed: 99 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include <thread>
3232
#include <chrono>
3333
#include <stdlib.h>
34-
#include <boost/filesystem.hpp> //toso: get rid of using boost in this file
3534

3635
//We gotta fix some wierd errors...
3736
#ifdef check
@@ -211,67 +210,16 @@ - (void) terminated: (NSNotification *)notification
211210
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
212211
{
213212
NSLog(@"applicationWillFinishLaunching");
214-
_PreferenceDbPath = nil;
215213
_fileNeedsOpening = nil;
216214
_isServing = NO;
217215
_UrlServingOn = @"";
218216
_UrlUniqueId = nil;
219217
}
220218

221219

222-
- (void)setDbDirectory
223-
{
224-
NSLog( @"setDbDirectory" );
225-
if( _PreferenceDbPath )
226-
return;
227-
228-
NSLog( @"will get path" );
229-
boost::filesystem::path datadir = [[[self applicationFilesDirectory] path] UTF8String];
230-
231-
if( !boost::filesystem::exists( datadir ) )
232-
{
233-
try
234-
{
235-
boost::filesystem::create_directories( datadir );
236-
NSLog( @"Created directory directory %s", datadir.c_str() );
237-
}catch(...){}
238-
}
239-
240-
if( boost::filesystem::exists( datadir ) )
241-
{
242-
InterSpec::setWritableDataDirectory( datadir.string<std::string>() );
243-
244-
const std::vector<std::string> serial_db = SpecUtils::ls_files_in_directory( datadir.string<std::string>(), "serial_to_model.csv" );
245-
if( !serial_db.empty() )
246-
SerialToDetectorModel::set_detector_model_input_csv( serial_db[0] );
247-
248-
249-
250-
datadir /= "InterSpecUserData.db";
251-
252-
try
253-
{
254-
DataBaseUtils::setPreferenceDatabaseFile( datadir.string<std::string>() );
255-
}catch( std::exception &e )
256-
{
257-
NSLog( @"Error: %s", e.what() );
258-
}
259-
260-
_PreferenceDbPath = [NSString stringWithFormat:@"%s", datadir.c_str()];
261-
NSLog( @"Datadir=%s", datadir.c_str() );
262-
}else
263-
NSLog( @"Failed to creade directory %s", datadir.c_str() );
264-
}//- (void)setDbDirectory:(void);
265-
266-
267220
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
268221
{
269-
NSLog(@"Finished Launching");
270-
271-
272-
Wt::WString::setDefaultEncoding( Wt::UTF8 );
273-
274-
InterSpecServer::set_require_tokened_sessions( true );
222+
NSLog(@"In applicationDidFinishLaunching");
275223

276224
/*
277225
//Could maybe get rid of using XIB/NIB by manually creating a window like:
@@ -380,18 +328,61 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
380328
//hiddenPageDOMTimerThrottlingAutoIncreases
381329
//pageVisibilityBasedProcessSuppressionEnabled
382330

331+
332+
const std::string base_dir = [[[NSBundle mainBundle] resourcePath] UTF8String];
333+
const std::string data_dir = [[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: @"data"] UTF8String];
334+
const std::string user_data_dir = [[[self applicationFilesDirectory] path] UTF8String];
383335

336+
bool require_token = true;
384337
#if( PERFORM_DEVELOPER_CHECKS )
385-
[prefs setValue:@YES forKey:@"developerExtrasEnabled"];
386-
387-
//Note: currently I disable right click in InterSpecApp using javascript if
388-
// no PERFORM_DEVELOPER_CHECKS. However, could also do:
389-
//https://stackoverflow.com/questions/28801032/how-can-the-context-menu-in-wkwebview-on-the-mac-be-modified-or-overridden#28981319
390-
//[_InterSpecWebView willOpenMenu:<#(nonnull NSMenu *)#> withEvent:<#(nonnull NSEvent *)#>];
338+
bool allow_dev_tools = true;
339+
#else
340+
bool allow_dev_tools = false;
391341
#endif
342+
unsigned short int server_port = 0;
343+
try
344+
{
345+
const InterSpecServer::DesktopAppConfig app_config
346+
= InterSpecServer::DesktopAppConfig::init( data_dir, user_data_dir );
347+
348+
if( !app_config.m_allow_restore )
349+
doResume = NO;
350+
allow_dev_tools = (allow_dev_tools || app_config.m_open_dev_tools);
351+
server_port = app_config.m_http_port;
352+
require_token = app_config.m_require_token;
353+
}catch( std::exception &e )
354+
{
355+
NSString *error = [NSString stringWithUTF8String:e.what()];
356+
357+
NSAlert *alert = [[NSAlert alloc] init];
358+
[alert setMessageText:@"Error parsing application JSON options!"];
359+
[alert setInformativeText: error ];
360+
[alert addButtonWithTitle:@"Ok"];
361+
[alert setAlertStyle:NSAlertStyleCritical];
362+
[alert runModal];
363+
}//try / catch get confiugurations
392364

393-
//To allow deep integration, could
394-
//[_webConfig setURLSchemeHandler:<#(nullable id<WKURLSchemeHandler>)#> forURLScheme: @"helloworld://"];
365+
InterSpecServer::set_require_tokened_sessions( require_token );
366+
367+
NSString *tempDir = NSTemporaryDirectory();
368+
if( tempDir == nil ) //shouldnt ever fail, right
369+
tempDir = @"/tmp";
370+
static const std::string tmpdr = [tempDir UTF8String]; //static since I'm not sure how long the location pointed to by setenv has to last
371+
372+
setenv( "TMPDIR", tmpdr.c_str(), 1);
373+
setenv( "WT_TMP_DIR", tmpdr.c_str(), 1);
374+
375+
376+
if( allow_dev_tools )
377+
{
378+
[prefs setValue:@YES forKey:@"developerExtrasEnabled"];
379+
380+
//Note: currently I disable right click in InterSpecApp using javascript if
381+
// no PERFORM_DEVELOPER_CHECKS. However, could also do:
382+
//https://stackoverflow.com/questions/28801032/how-can-the-context-menu-in-wkwebview-on-the-mac-be-modified-or-overridden#28981319
383+
//[_InterSpecWebView willOpenMenu:<#(nonnull NSMenu *)#> withEvent:<#(nonnull NSEvent *)#>];
384+
}//if( allow_dev_tools )
385+
395386

396387
//Create WKWebView manually, rather than in XIB to support macOS 10.10 and 10.11...
397388
self.InterSpecWebView = [[WKWebView alloc] initWithFrame: _window.contentView.frame configuration: webConfig];
@@ -411,36 +402,37 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
411402
_InterSpecWebView.allowsBackForwardNavigationGestures = NO; //default is NO anyway
412403

413404

414-
[self setDbDirectory];
415-
DataBaseVersionUpgrade::checkAndUpgradeVersion();
416-
405+
if( allow_dev_tools )
406+
{
407+
[prefs setValue:@YES forKey:@"developerExtrasEnabled"];
408+
409+
NSMenu *menu = [[[NSApp mainMenu] itemAtIndex: 1] submenu]; //Get "Edit" menu
410+
411+
if( menu )
412+
{
413+
NSMenuItem *itemnow = [[NSMenuItem alloc]
414+
initWithTitle:@"Enable Web Inspector"
415+
action:@selector(enableWebInspector)
416+
keyEquivalent:@""];
417+
[itemnow setTarget:self];
418+
[menu addItem:itemnow];
419+
[itemnow setEnabled:YES];
420+
}
421+
422+
//Note: currently the right click in InterSpecApp is disabled using javascript if
423+
// unles PERFORM_DEVELOPER_CHECKS is true. However, could also do:
424+
//https://stackoverflow.com/questions/28801032/how-can-the-context-menu-in-wkwebview-on-the-mac-be-modified-or-overridden#28981319
425+
//[_InterSpecWebView willOpenMenu:<#(nonnull NSMenu *)#> withEvent:<#(nonnull NSEvent *)#>];
426+
}//if( allow_dev_tools )
417427

418-
static const std::string basedir = std::string("--basedir=")
419-
+ [[[NSBundle mainBundle] resourcePath] UTF8String];
420428
static const std::string argv0 = [[[NSBundle mainBundle] executablePath] UTF8String];
429+
const char *xml_config_path = "data/config/wt_config_osx.xml";
421430

422-
NSString *tempDir = NSTemporaryDirectory();
423-
if( tempDir == nil ) //shouldnt ever fail, right
424-
tempDir = @"/tmp";
425-
static const std::string tmpdr = [tempDir UTF8String]; //static since I'm not sure how long the location pointed to by setenv has to last
426-
427-
// TODO: Need to switch to just using `InterSpecServer::start_server`, and just set the temp dir env variable manually here; we can then remove some of the above prep code, like checking DB version and such
428-
429-
const char *argv[] = { argv0.c_str(), "--forceserve", "--nobrowsertab", basedir.c_str(), "-c", "data/config/wt_config_osx.xml", "--tempdir", tmpdr.c_str() };
430-
int argc = sizeof(argv) / sizeof(argv[0]);
431-
432-
InterSpecServer::startServer( argc, (char **)argv, &createApplication );
431+
InterSpecServer::start_server( argv0.c_str(), user_data_dir.c_str(),
432+
base_dir.c_str(), xml_config_path, server_port );
433433

434434
//now we'll wait for the server to start
435-
std::string url;
436-
int running = -1;
437-
int numtries = 0;
438-
while( url.empty() && running<0 && numtries < 110 ) //110 sections of at least 10 ms, is 1.1 seconds
439-
{
440-
url = InterSpecServer::urlBeingServedOn(); //will be empty if not serving
441-
if( url.empty() )
442-
std::this_thread::sleep_for( std::chrono::milliseconds(10) );
443-
}//while( numtries < 11 )
435+
std::string url = InterSpecServer::urlBeingServedOn();
444436

445437
if( url.empty() )
446438
{
@@ -554,25 +546,6 @@ - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
554546
[NSDistributedNotificationCenter.defaultCenter addObserver:self selector:@selector(themeChanged:) name:@"AppleInterfaceThemeChangedNotification" object: nil];
555547
}
556548
}
557-
558-
// Try adding a popover, to eventually display a map
559-
// See https://developer.apple.com/documentation/appkit/nspopover
560-
/*
561-
// Need to implement https://developer.apple.com/documentation/appkit/nsviewcontroller?language=objc
562-
// note need to override -loadView method
563-
NSRect bounds = [[self.window contentView] bounds];
564-
565-
self.myPopover = [[NSPopover alloc] init];
566-
567-
[self.myPopover setContentSize:NSMakeSize(0.85*bounds.size.width, 0.85*bounds.size.height)];
568-
[self.myPopover setBehavior: NSPopoverBehaviorTransient]; //change to NSPopoverBehaviorApplicationDefined
569-
[self.myPopover setAnimates:YES];
570-
[self.myPopover setContentViewController: self.popoverViewController];
571-
572-
[self.myPopover showRelativeToRect: bounds
573-
ofView:[[NSApp mainWindow] contentView]
574-
preferredEdge:NSMinYEdge];
575-
*/
576549
}//applicationDidFinishLaunching:(NSNotification *)aNotification
577550

578551

@@ -1028,6 +1001,27 @@ - (void)userContentController:(WKUserContentController *)userContentController
10281001
}//didReceiveScriptMessage
10291002

10301003

1004+
-(void)enableWebInspector
1005+
{
1006+
NSLog( @"Will show WebInpector" );
1007+
1008+
// For macOS build, the context menu is disabled on wApp->domRoot() using JavaScript, so we need
1009+
// to over-ride this
1010+
NSString *js = @"document.querySelector('.Wt-domRoot').setAttribute('oncontextmenu','return true;');";
1011+
[_InterSpecWebView evaluateJavaScript:js completionHandler:nil];
1012+
1013+
NSAlert *alert = [[NSAlert alloc] init];
1014+
[alert setMessageText:@"Web Inspector Enabled"];
1015+
[alert setInformativeText: @"Right click somewhere other than the spectrum or other chart, "
1016+
"and select 'Inspect Element' from the contect menu" ];
1017+
[alert addButtonWithTitle:@"Ok"];
1018+
[alert setAlertStyle:NSAlertStyleInformational];
1019+
[alert runModal];
1020+
1021+
// TODO: disable, or remove the "Enable Web Inspector" menu item.
1022+
}//enableWebInspector
1023+
1024+
10311025
-(NSString *)generateSessionToken
10321026
{
10331027
#define TOKEN_LEN 14

0 commit comments

Comments
 (0)