#include #include #include #include #include #include #include #include #include #include #import #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #pragma GCC diagnostic ignored "-Wshadow" #include #pragma GCC diagnostic pop #include namespace po = boost::program_options; @interface URLHandler : NSObject @property (nonatomic) mbgl::Map *map; - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; @end @implementation URLHandler - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { (void)replyEvent; NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; NSURL *url = [NSURL URLWithString:urlString]; NSMutableDictionary *params = [[NSMutableDictionary alloc] init]; for (NSString *param in [[url query] componentsSeparatedByString:@"&"]) { NSArray *parts = [param componentsSeparatedByString:@"="]; if([parts count] < 2) continue; [params setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]]; } mbgl::LatLng latLng = mbgl::LatLng(0, 0); double zoom = 0, bearing = 0; bool hasCenter = false, hasZoom = false, hasBearing = false; NSString *centerString = [params objectForKey:@"center"]; if (centerString) { NSArray *latLngValues = [centerString componentsSeparatedByString:@","]; if ([latLngValues count] == 2) { latLng.latitude = [latLngValues[0] doubleValue]; latLng.longitude = [latLngValues[1] doubleValue]; hasCenter = true; } } NSString *zoomString = [params objectForKey:@"zoom"]; if (zoomString) { zoom = [zoomString doubleValue]; hasZoom = true; } NSString *bearingString = [params objectForKey:@"bearing"]; if (bearingString) { bearing = [bearingString doubleValue]; hasBearing = true; } if ([self map]) { if (hasCenter && hasZoom) { [self map]->setLatLngZoom(latLng, zoom); } else if (hasCenter) { [self map]->setLatLng(latLng); } else if (hasZoom) { [self map]->setZoom(zoom); } if (hasBearing) { [self map]->setBearing(bearing); } } } @end // Returns the path to the default cache database on this system. const std::string &defaultCacheDatabase() { static const std::string path = []() -> std::string { NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES); if ([paths count] == 0) { // Disable the cache if we don't have a location to write. return ""; } NSString *p = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mapbox GL"]; if (![[NSFileManager defaultManager] createDirectoryAtPath:p withIntermediateDirectories:YES attributes:nil error:nil]) { // Disable the cache if we couldn't create the directory. return ""; } return [[p stringByAppendingPathComponent:@"cache.db"] UTF8String]; }(); return path; } int main(int argc, char* argv[]) { bool fullscreen = false; bool benchmark = false; std::string style; po::options_description desc("Allowed options"); desc.add_options() ("fullscreen,f", po::bool_switch(&fullscreen)->default_value(fullscreen), "Fullscreen mode") ("style,s", po::value(&style)->value_name("json"), "Map stylesheet") ("benchmark,b", po::bool_switch(&benchmark)->default_value(benchmark), "Benchmark mode") ; try { auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); po::variables_map vm; po::store(parsed, vm); po::notify(vm); } catch(std::exception& e) { std::cout << "Error: " << e.what() << std::endl << desc; exit(1); } if (benchmark) { mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); } GLFWView view(fullscreen, benchmark); mbgl::SQLiteCache cache(defaultCacheDatabase()); mbgl::DefaultFileSource fileSource(&cache); // Set access token if present NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; if (!accessToken) mbgl::Log::Warning(mbgl::Event::Setup, "No access token set. Mapbox vector tiles won't work."); if (accessToken) fileSource.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]); mbgl::Map map(view, fileSource); URLHandler *handler = [[URLHandler alloc] init]; [handler setMap:&map]; NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager]; [appleEventManager setEventHandler:handler andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; // Notify map object when network reachability status changes. MGLReachability* reachability = [MGLReachability reachabilityForInternetConnection]; reachability.reachableBlock = ^(MGLReachability *) { mbgl::NetworkStatus::Reachable(); }; [reachability startNotifier]; // Load settings mbgl::Settings_NSUserDefaults settings; map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom); map.setBearing(settings.bearing); map.setDebug(settings.debug); view.setChangeStyleCallback([&map, &view] () { static uint8_t currentStyleIndex; if (++currentStyleIndex == mbgl::util::default_styles::numOrderedStyles) { currentStyleIndex = 0; } mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[currentStyleIndex]; map.setStyleURL(newStyle.url); view.setWindowTitle(newStyle.name); mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name); }); // Load style if (style.empty()) { mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[0]; style = newStyle.url; view.setWindowTitle(newStyle.name); } map.setStyleURL(style); view.run(); [reachability stopNotifier]; // Save settings mbgl::LatLng latLng = map.getLatLng(); settings.latitude = latLng.latitude; settings.longitude = latLng.longitude; settings.zoom = map.getZoom(); settings.bearing = map.getBearing(); settings.debug = map.getDebug(); settings.save(); return 0; }