mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-21 07:58:04 +03:00
a3c48df25b
All our native code now gets built into Atom.framework. Atom.app and Atom Helper.app both link against this framework. All resources other than a couple of main-bundle-only ones (e.g., atom.icns) go into Atom.framework. Note that this means that there's no compile- or link-time separation between main process code and helper process code. We could introduce a compile-time separation by building main process and helper process code into separate static libraries with mutually exclusive include paths, if we want. Atom.framework exports a single symbol: AtomMain(). Atom.app and Atom Helper.app contain a single source file: main.cpp. main() just calls AtomMain(). All frameworks are placed in Atom.app/Contents/Frameworks. We now link against all frameworks using @rpath-based install names, which allows Atom.app and Atom Helper.app to find them automatically based on their own LD_RUNPATH_SEARCH_PATH settings. We use install_name_tool at build time on each of our three binaries (Atom.app, Atom Helper.app, Atom.framework) to set the install names. By reducing duplication of code and resources between Atom.app and Atom Helper.app (and the EH/NP copies of Atom Helper.app), this reduces the size of the total installed Atom.app bundle from 145MB to 82MB. By compiling .coffee and .cson files only once, clean build time drops from 114 seconds to 79 seconds on my MacBook Pro.
143 lines
4.9 KiB
Plaintext
143 lines
4.9 KiB
Plaintext
#import "atom_main.h"
|
|
#import "atom_cef_app.h"
|
|
#import "include/cef_application_mac.h"
|
|
#import "native/atom_application.h"
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
|
|
void sendPathToMainProcessAndExit(int fd, NSString *socketPath, NSDictionary *arguments);
|
|
void handleBeingOpenedAgain(int argc, char* argv[]);
|
|
void listenForPathToOpen(int fd, NSString *socketPath);
|
|
void activateOpenApp();
|
|
BOOL isAppAlreadyOpen();
|
|
|
|
int AtomMain(int argc, char* argv[]) {
|
|
{
|
|
// See if we're being run as a secondary process.
|
|
|
|
CefMainArgs main_args(argc, argv);
|
|
CefRefPtr<CefApp> app(new AtomCefApp);
|
|
int exitCode = CefExecuteProcess(main_args, app);
|
|
if (exitCode >= 0)
|
|
return exitCode;
|
|
}
|
|
|
|
// We're the main process.
|
|
|
|
@autoreleasepool {
|
|
handleBeingOpenedAgain(argc, argv);
|
|
|
|
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
|
AtomApplication *application = [AtomApplication applicationWithArguments:argv count:argc];
|
|
|
|
NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
|
|
NSNib *mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:[NSBundle bundleWithIdentifier:@"com.github.atom.framework"]];
|
|
[mainNib instantiateNibWithOwner:application topLevelObjects:nil];
|
|
|
|
CefRunMessageLoop();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void handleBeingOpenedAgain(int argc, char* argv[]) {
|
|
NSString *socketPath = [NSString stringWithFormat:@"/tmp/atom-%d.sock", getuid()];
|
|
|
|
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
|
|
if (isAppAlreadyOpen()) {
|
|
NSDictionary *arguments = [AtomApplication parseArguments:argv count:argc];
|
|
sendPathToMainProcessAndExit(fd, socketPath, arguments);
|
|
}
|
|
else {
|
|
listenForPathToOpen(fd, socketPath);
|
|
}
|
|
}
|
|
|
|
void sendPathToMainProcessAndExit(int fd, NSString *socketPath, NSDictionary *arguments) {
|
|
struct sockaddr_un send_addr;
|
|
send_addr.sun_family = AF_UNIX;
|
|
strcpy(send_addr.sun_path, [socketPath UTF8String]);
|
|
|
|
NSString *path = [arguments objectForKey:@"path"];
|
|
if (path) {
|
|
NSMutableString *packedString = [NSMutableString stringWithString:path];
|
|
if ([arguments objectForKey:@"wait"]) {
|
|
[packedString appendFormat:@"\n%@", [arguments objectForKey:@"pid"]];
|
|
}
|
|
|
|
const char *buf = [packedString UTF8String];
|
|
if (sendto(fd, buf, [packedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding], 0, (sockaddr *)&send_addr, sizeof(send_addr)) < 0) {
|
|
perror("Error: Failed to sending path to main Atom process");
|
|
exit(1);
|
|
}
|
|
} else {
|
|
activateOpenApp();
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
void listenForPathToOpen(int fd, NSString *socketPath) {
|
|
struct sockaddr_un addr;
|
|
addr.sun_family = AF_UNIX;
|
|
strcpy(addr.sun_path, [socketPath UTF8String]);
|
|
|
|
unlink([socketPath UTF8String]);
|
|
if (bind(fd, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
|
perror("ERROR: Binding to socket");
|
|
}
|
|
else {
|
|
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
|
dispatch_async(queue, ^{
|
|
char buf[MAXPATHLEN + 16]; // Add 16 to hold the pid string
|
|
struct sockaddr_un listen_addr;
|
|
listen_addr.sun_family = AF_UNIX;
|
|
strcpy(listen_addr.sun_path, [socketPath UTF8String]);
|
|
socklen_t listen_addr_length;
|
|
|
|
while(true) {
|
|
memset(buf, 0, sizeof(buf));
|
|
if (recvfrom(fd, &buf, sizeof(buf), 0, (sockaddr *)&listen_addr, &listen_addr_length) < 0) {
|
|
perror("ERROR: Receiving from socket");
|
|
}
|
|
else {
|
|
NSArray *components = [[NSString stringWithUTF8String:buf] componentsSeparatedByString:@"\n"];
|
|
NSString *path = [components objectAtIndex:0];
|
|
NSNumber *pid = nil;
|
|
if (components.count > 1) pid = [NSNumber numberWithInt:[[components objectAtIndex:1] intValue]];
|
|
dispatch_queue_t mainQueue = dispatch_get_main_queue();
|
|
dispatch_async(mainQueue, ^{
|
|
[[AtomApplication sharedApplication] open:path pidToKillWhenWindowCloses:pid];
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
void activateOpenApp() {
|
|
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
|
BOOL hasSameBundleId = [app.bundleIdentifier isEqualToString:[[NSBundle mainBundle] bundleIdentifier]];
|
|
BOOL hasSameProcessesId = app.processIdentifier == [[NSProcessInfo processInfo] processIdentifier];
|
|
if (hasSameBundleId && !hasSameProcessesId) {
|
|
[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL isAppAlreadyOpen() {
|
|
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
|
BOOL hasSameBundleId = [app.bundleIdentifier isEqualToString:[[NSBundle mainBundle] bundleIdentifier]];
|
|
BOOL hasSameProcessesId = app.processIdentifier == [[NSProcessInfo processInfo] processIdentifier];
|
|
if (hasSameBundleId && !hasSameProcessesId) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|