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 {
/// @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.
/// @return Resources directory.
///
/// Mainly for user interface elements such as graphics and strings
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
/// @return Shared support directory
///
@ -81,18 +53,6 @@ std::string GetBundleSharedFrameworksDirectory();
/// bundle is considered read-only.)
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();
} // namespace util
} // namespace agi

View file

@ -25,8 +25,7 @@ static std::string EmptyIfNil(NSString *string) {
return string ? [string UTF8String] : "";
}
namespace agi {
namespace osx {
namespace agi { namespace osx {
AppNapDisabler::AppNapDisabler(std::string reason) : handle(nullptr) {
if (reason.empty()) reason = "Loading";
auto processInfo = [NSProcessInfo processInfo];
@ -42,63 +41,26 @@ AppNapDisabler::~AppNapDisabler() {
[processInfo endActivity:(id)handle];
[(id)handle release];
}
}
namespace util {
std::string GetBundlePath() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] bundlePath]);
}
}
std::string GetBundleResourcesDirectory() {
@autoreleasepool {
return EmptyIfNil([[[NSBundle mainBundle] resourceURL] path]);
}
}
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() {
@autoreleasepool {
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() {
@autoreleasepool {
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();
}
}
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;
}
#ifndef __WXMAC__
void RestartAegisub() {
config::opt->Flush();
#if defined(__WXMSW__)
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
wxExecute(wxStandardPaths::Get().GetExecutablePath());
#endif
}
#endif
bool ForwardMouseWheelEvent(wxWindow *source, wxMouseEvent &evt) {
wxWindow *target = wxFindWindowAtPoint(wxGetMousePosition());

View file

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

View file

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