Fix restarting the application after changing the UI language on OS X

This commit is contained in:
Thomas Goyne 2014-06-13 09:33:41 -07:00
parent ebb13d96ec
commit 7780fadfc6
6 changed files with 40 additions and 121 deletions

View file

@ -40,40 +40,12 @@ namespace agi {
}; };
} }
namespace util { namespace util {
/// @brief Get the full name of bundle.
/// @return Full name of bundle.
/// Get the full name of the bundle itself.
///
/// @warning May return "" if the current executable is not inside a bundle.
std::string GetBundlePath();
/// @brief Get the esources directory. /// @brief Get the esources directory.
/// @return Resources directory. /// @return Resources directory.
/// ///
/// Mainly for user interface elements such as graphics and strings /// Mainly for user interface elements such as graphics and strings
std::string GetBundleResourcesDirectory(); std::string GetBundleResourcesDirectory();
/// @brief Get the built-in plugins directory.
/// @return Built-in plugins directory.
///
/// This is generaly only used by native Carbon and Cocoa applications. It is
/// not for general shared libraries.
std::string GetBundleBuiltInPlugInsDirectory();
/// @brief Get the private Frameworks directory.
/// @return Private Framework directory.
///
/// These are suitable locations for shared libraries.
std::string GetBundlePrivateFrameworksDirectory();
/// @brief Get the shared Frameworks directory.
/// @return Shared Framework directory.
///
/// @see GetBundlePrivateFrameworksDirectory()
/// @note Does anyone know the difference between private and shared frameworks
/// inside a bundle?
std::string GetBundleSharedFrameworksDirectory();
/// @brief Get the shared support directory /// @brief Get the shared support directory
/// @return Shared support directory /// @return Shared support directory
/// ///
@ -81,18 +53,6 @@ std::string GetBundleSharedFrameworksDirectory();
/// bundle is considered read-only.) /// bundle is considered read-only.)
std::string GetBundleSharedSupportDirectory(); std::string GetBundleSharedSupportDirectory();
/// @brief Get the main executable path.
/// @return Main executable path.
///
/// The binary run when the user launches the bundle from Finder.
std::string GetBundleExecutablePath();
/// @brief Get the auxillary executable path.
/// @return Auxillary executable path.
///
/// Pass the basename of the executable to get the path.
std::string GetBundleAuxillaryExecutablePath(std::string const& executableName);
std::string GetApplicationSupportDirectory(); std::string GetApplicationSupportDirectory();
} // namespace util } // namespace util
} // namespace agi } // namespace agi

View file

@ -25,8 +25,7 @@ static std::string EmptyIfNil(NSString *string) {
return string ? [string UTF8String] : ""; return string ? [string UTF8String] : "";
} }
namespace agi { namespace agi { namespace osx {
namespace osx {
AppNapDisabler::AppNapDisabler(std::string reason) : handle(nullptr) { AppNapDisabler::AppNapDisabler(std::string reason) : handle(nullptr) {
if (reason.empty()) reason = "Loading"; if (reason.empty()) reason = "Loading";
auto processInfo = [NSProcessInfo processInfo]; auto processInfo = [NSProcessInfo processInfo];
@ -42,14 +41,9 @@ AppNapDisabler::~AppNapDisabler() {
[processInfo endActivity:(id)handle]; [processInfo endActivity:(id)handle];
[(id)handle release]; [(id)handle release];
} }
}
namespace util {
std::string GetBundlePath() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] bundlePath]);
}
} }
namespace util {
std::string GetBundleResourcesDirectory() { std::string GetBundleResourcesDirectory() {
@autoreleasepool { @autoreleasepool {
@ -57,48 +51,16 @@ std::string GetBundleResourcesDirectory() {
} }
} }
std::string GetBundleExecutablePath() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] executablePath]);
}
}
std::string GetBundleBuiltInPlugInsDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] builtInPlugInsPath]);
}
}
std::string GetBundlePrivateFrameworksDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] privateFrameworksPath]);
}
}
std::string GetBundleSharedFrameworksDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] sharedFrameworksPath]);
}
}
std::string GetBundleSharedSupportDirectory() { std::string GetBundleSharedSupportDirectory() {
@autoreleasepool { @autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] sharedSupportPath]); return EmptyIfNil([[NSBundle mainBundle] sharedSupportPath]);
} }
} }
std::string GetBundleAuxillaryExecutablePath(std::string const& executableName) {
@autoreleasepool {
NSString *name = [NSString stringWithUTF8String:executableName.c_str()];
return EmptyIfNil([[NSBundle mainBundle]pathForAuxiliaryExecutable:name]);
}
}
std::string GetApplicationSupportDirectory() { std::string GetApplicationSupportDirectory() {
@autoreleasepool { @autoreleasepool {
return EmptyIfNil([NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject]); return EmptyIfNil([NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject]);
} }
} }
} } }
}

View file

@ -59,3 +59,10 @@ void SetPlaceholderText(wxWindow *window, wxString const& placeholder) {
cell.placeholderString = wxCFStringRef(placeholder).AsNSString(); cell.placeholderString = wxCFStringRef(placeholder).AsNSString();
} }
} }
void RestartAegisub() {
auto helperPath = [NSBundle.mainBundle pathForAuxiliaryExecutable:@"restart-helper"];
if (helperPath)
[NSTask launchedTaskWithLaunchPath:helperPath
arguments:@[NSBundle.mainBundle.executablePath]];
}

View file

@ -94,23 +94,17 @@ int SmallestPowerOf2(int x) {
return x; return x;
} }
#ifndef __WXMAC__
void RestartAegisub() { void RestartAegisub() {
config::opt->Flush(); config::opt->Flush();
#if defined(__WXMSW__) #if defined(__WXMSW__)
wxExecute("\"" + wxStandardPaths::Get().GetExecutablePath() + "\""); wxExecute("\"" + wxStandardPaths::Get().GetExecutablePath() + "\"");
#elif defined(__WXMAC__)
std::string bundle_path = agi::util::GetBundlePath();
std::string helper_path = agi::util::GetBundleAuxillaryExecutablePath("restart-helper");
if (bundle_path.empty() || helper_path.empty()) return;
wxString exec = fmt_wx("\"%s\" /usr/bin/open -n \"%s\"'", helper_path, bundle_path);
LOG_I("util/restart/exec") << exec.utf8_str();
wxExecute(exec);
#else #else
wxExecute(wxStandardPaths::Get().GetExecutablePath()); wxExecute(wxStandardPaths::Get().GetExecutablePath());
#endif #endif
} }
#endif
bool ForwardMouseWheelEvent(wxWindow *source, wxMouseEvent &evt) { bool ForwardMouseWheelEvent(wxWindow *source, wxMouseEvent &evt) {
wxWindow *target = wxFindWindowAtPoint(wxGetMousePosition()); wxWindow *target = wxFindWindowAtPoint(wxGetMousePosition());

View file

@ -1,8 +1,8 @@
include ../Makefile.inc include ../Makefile.inc
ifeq (yes, $(BUILD_DARWIN)) ifeq (yes, $(BUILD_DARWIN))
osx-bundle-restart-helper: osx-bundle-restart-helper.c osx-bundle-restart-helper: osx-bundle-restart-helper.m
$(BIN_CC) -o osx-bundle-restart-helper osx-bundle-restart-helper.c $(BIN_CC) -o osx-bundle-restart-helper -fmodules osx-bundle-restart-helper.m
CLEANFILES += osx-bundle-restart-helper CLEANFILES += osx-bundle-restart-helper
all: osx-bundle-restart-helper all: osx-bundle-restart-helper
endif endif

View file

@ -33,6 +33,8 @@
#include <sys/event.h> #include <sys/event.h>
#include <sys/time.h> #include <sys/time.h>
@import Foundation;
/* /*
Return codes: Return codes:
1: Error in kqueue() 1: Error in kqueue()
@ -42,57 +44,51 @@ Return codes:
If none of those happen the requested command is execve()'d. If none of those happen the requested command is execve()'d.
*/ */
int main(int argc, char *argv[], char *env[]) int main(int argc, char *argv[], char *env[]) {
{ int queue = kqueue();
int waitpid = getppid(); if (queue == -1) {
int queue, nchange;
struct kevent event[1];
struct kevent change[1];
struct timespec timeout = { 30, 0 };
if ((queue = kqueue()) == -1)
{
perror("Error in: kqueue()"); perror("Error in: kqueue()");
return 1; return 1;
} }
struct kevent event[1];
EV_SET(event, EV_SET(event,
waitpid, getppid(),
EVFILT_PROC, EVFILT_PROC,
EV_ADD|EV_ENABLE|EV_ONESHOT, EV_ADD|EV_ENABLE|EV_ONESHOT,
NOTE_EXIT, NOTE_EXIT,
0, 0); 0, 0);
printf("restart-helper: waiting for pid %d\n", waitpid); printf("restart-helper: waiting for pid %d\n", getppid());
nchange = kevent(queue, change, 1, event, 1, &timeout); struct kevent change[1];
struct timespec timeout = { 30, 0 };
int nchange = kevent(queue, change, 1, event, 1, &timeout);
if (nchange < 0) if (nchange < 0) {
{
perror("restart-helper: Error in kevent()"); perror("restart-helper: Error in kevent()");
return 2; return 2;
} }
else if (nchange == 0) if (nchange == 0) {
{ printf("restart-helper: Timed out waiting for pid %d\n", getppid());
printf("restart-helper: Timed out waiting for pid %d\n", waitpid);
return 3; return 3;
} }
else if (change[0].flags & EV_ERROR) if (change[0].flags & EV_ERROR) {
{
perror("restart-helper: Error in event"); perror("restart-helper: Error in event");
return 2; return 2;
} }
else
{
close(queue);
printf("restart-helper: Executing '%s'\n", argv[1]); close(queue);
if (execve(argv[1], argv+1, env) == -1) printf("restart-helper: Executing '%s'\n", argv[1]);
{
perror("restart-helper: Error in execve()"); @try {
return 4; [NSTask launchedTaskWithLaunchPath:[NSString stringWithUTF8String:argv[1]] arguments:@[]];
}
return 0; /* never reached */
} }
@catch (NSException *e) {
printf("restart-helper: Error launching program: %s\n", e.description.UTF8String);
return 4;
}
return 0;
} }