mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2025-02-23 19:40:58 +00:00
Fix app icon not being displayed when requesting administrator privleges on Mac.
Previously the application was run from outside a bundle and hence did not have an app icon - so OS X displayed the generic 'terminal' icon in the elevation dialog. The app icon in the dock was set at runtime, but disappeared temporarily on shutdown when the overridden app icon was replaced with the default icon. This commit fixes the problem by detecting whether the executable is being run from within a bundle and if not, creating a minimal app bundle in /tmp and re-launching the updater from there.
This commit is contained in:
parent
3fe67e9824
commit
9650a492a9
8 changed files with 185 additions and 13 deletions
|
@ -38,10 +38,20 @@ set (SOURCES
|
|||
|
||||
if (APPLE)
|
||||
set(MAC_DOCK_ICON_CPP_FILE ${CMAKE_CURRENT_BINARY_DIR}/mac_dock_icon.cpp)
|
||||
set(MAC_INFO_PLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/mac_info_plist.cpp)
|
||||
generate_cpp_resource_file(resource_macdockicon
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources
|
||||
mac-dock.png ${MAC_DOCK_ICON_CPP_FILE})
|
||||
set(SOURCES ${SOURCES} StandardDirs.mm UpdateDialogCocoa.mm mac_dock_icon.cpp)
|
||||
mac.icns ${MAC_DOCK_ICON_CPP_FILE})
|
||||
generate_cpp_resource_file(resource_macplist
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources
|
||||
Info.plist ${MAC_INFO_PLIST_FILE})
|
||||
set(HEADERS ${HEADERS} MacBundle.h)
|
||||
set(SOURCES ${SOURCES}
|
||||
MacBundle.cpp
|
||||
StandardDirs.mm
|
||||
UpdateDialogCocoa.mm
|
||||
mac_dock_icon.cpp
|
||||
mac_info_plist.cpp)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
|
|
53
src/MacBundle.cpp
Normal file
53
src/MacBundle.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "MacBundle.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "Log.h"
|
||||
|
||||
MacBundle::MacBundle(const std::string& path, const std::string& appName)
|
||||
: m_appName(appName)
|
||||
{
|
||||
m_path = path + '/' + appName + ".app";
|
||||
}
|
||||
|
||||
std::string MacBundle::bundlePath() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void MacBundle::create(const std::string& infoPlist,
|
||||
const std::string& icon,
|
||||
const std::string& exePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// create the bundle directories
|
||||
FileUtils::mkpath(m_path.c_str());
|
||||
|
||||
std::string contentDir = m_path + "/Contents";
|
||||
std::string resourceDir = contentDir + "/Resources";
|
||||
std::string binDir = contentDir + "/MacOS";
|
||||
|
||||
FileUtils::mkpath(resourceDir.c_str());
|
||||
FileUtils::mkpath(binDir.c_str());
|
||||
|
||||
// create the Contents/Info.plist file
|
||||
FileUtils::writeFile((contentDir + "/Info.plist").c_str(),infoPlist.c_str(),infoPlist.size());
|
||||
|
||||
// save the icon to Contents/Resources/<appname>.icns
|
||||
FileUtils::writeFile((resourceDir + '/' + m_appName + ".icns").c_str(),icon.c_str(),icon.size());
|
||||
|
||||
// copy the app binary to Contents/MacOS/<appname>
|
||||
m_exePath = binDir + '/' + m_appName;
|
||||
FileUtils::copyFile(exePath.c_str(),m_exePath.c_str());
|
||||
}
|
||||
catch (const FileUtils::IOException& exception)
|
||||
{
|
||||
LOG(Error,"Unable to create app bundle. " + std::string(exception.what()));
|
||||
}
|
||||
}
|
||||
|
||||
std::string MacBundle::executablePath() const
|
||||
{
|
||||
return m_exePath;
|
||||
}
|
||||
|
35
src/MacBundle.h
Normal file
35
src/MacBundle.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/** Class for creating minimal Mac app bundles. */
|
||||
class MacBundle
|
||||
{
|
||||
public:
|
||||
/** Create a MacBundle instance representing the bundle
|
||||
* in <path>/<appName>.app
|
||||
*/
|
||||
MacBundle(const std::string& path, const std::string& appName);
|
||||
|
||||
/** Create a simple Mac bundle.
|
||||
*
|
||||
* @param infoPlist The content of the Info.plist file
|
||||
* @param icon The content of the app icon
|
||||
* @param exePath The path of the file to use for the main app in the bundle.
|
||||
*/
|
||||
void create(const std::string& infoPlist,
|
||||
const std::string& icon,
|
||||
const std::string& exePath);
|
||||
|
||||
/** Returns the path of the main executable within the Mac bundle. */
|
||||
std::string executablePath() const;
|
||||
|
||||
/** Returns the path of the bundle */
|
||||
std::string bundlePath() const;
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
std::string m_appName;
|
||||
std::string m_exePath;
|
||||
};
|
||||
|
|
@ -90,9 +90,6 @@ UpdateDialogCocoa::~UpdateDialogCocoa()
|
|||
[d->pool release];
|
||||
}
|
||||
|
||||
extern unsigned char mac_dock_png[];
|
||||
extern unsigned int mac_dock_png_len;
|
||||
|
||||
void UpdateDialogCocoa::enableDockIcon()
|
||||
{
|
||||
// convert the application to a foreground application and in
|
||||
|
@ -103,13 +100,6 @@ void UpdateDialogCocoa::enableDockIcon()
|
|||
ProcessSerialNumber psn;
|
||||
GetCurrentProcess(&psn);
|
||||
TransformProcessType(&psn,kProcessTransformToForegroundApplication);
|
||||
|
||||
// loading the icon for the app has to be done after
|
||||
// changing the process type
|
||||
NSData* iconData = [NSData dataWithBytes:mac_dock_png length:mac_dock_png_len];
|
||||
NSImage* iconImage = [[NSImage alloc] initWithData: iconData];
|
||||
[NSApp setApplicationIconImage:iconImage];
|
||||
[iconImage release];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::init()
|
||||
|
|
48
src/main.cpp
48
src/main.cpp
|
@ -15,6 +15,7 @@
|
|||
#endif
|
||||
|
||||
#if defined(PLATFORM_MAC)
|
||||
#include "MacBundle.h"
|
||||
#include "UpdateDialogCocoa.h"
|
||||
#endif
|
||||
|
||||
|
@ -51,13 +52,58 @@ void runUpdaterThread(void* arg)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_MAC
|
||||
extern unsigned char Info_plist[];
|
||||
extern unsigned int Info_plist_len;
|
||||
|
||||
extern unsigned char mac_icns[];
|
||||
extern unsigned int mac_icns_len;
|
||||
|
||||
bool unpackBundle(int argc, char** argv)
|
||||
{
|
||||
MacBundle bundle(FileUtils::tempPath(),AppInfo::name());
|
||||
std::string currentExePath = ProcessUtils::currentProcessPath();
|
||||
|
||||
if (currentExePath.find(bundle.bundlePath()) != std::string::npos)
|
||||
{
|
||||
// already running from a bundle
|
||||
return false;
|
||||
}
|
||||
LOG(Info,"Creating bundle " + bundle.bundlePath());
|
||||
|
||||
// create a Mac app bundle
|
||||
std::string plistContent(reinterpret_cast<const char*>(Info_plist),Info_plist_len);
|
||||
std::string iconContent(reinterpret_cast<const char*>(mac_icns),mac_icns_len);
|
||||
bundle.create(plistContent,iconContent,ProcessUtils::currentProcessPath());
|
||||
|
||||
std::list<std::string> args;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
args.push_back(argv[i]);
|
||||
}
|
||||
ProcessUtils::runSync(bundle.executablePath(),args);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
#ifdef PLATFORM_MAC
|
||||
void* pool = UpdateDialogCocoa::createAutoreleasePool();
|
||||
#endif
|
||||
|
||||
|
||||
Log::instance()->open(AppInfo::logFilePath());
|
||||
|
||||
#ifdef PLATFORM_MAC
|
||||
// when the updater is run for the first time, create a Mac app bundle
|
||||
// and re-launch the application from the bundle. This permits
|
||||
// setting up bundle properties (such as application icon)
|
||||
if (unpackBundle(argc,argv))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
UpdaterOptions options;
|
||||
options.parse(argc,argv);
|
||||
if (options.showVersion)
|
||||
|
|
38
src/resources/Info.plist
Normal file
38
src/resources/Info.plist
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- Note - The name of the application specified here must match the value
|
||||
returned by AppInfo::name()
|
||||
!-->
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Mendeley Updater</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Mendeley Updater.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.mendeley.MendeleyUpdater</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.5</string>
|
||||
<key>LSMinimumSystemVersionByArchitecture</key>
|
||||
<dict>
|
||||
<key>i386</key>
|
||||
<string>10.5.0</string>
|
||||
<key>x86_64</key>
|
||||
<string>10.5.0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
BIN
src/resources/mac.icns
Normal file
BIN
src/resources/mac.icns
Normal file
Binary file not shown.
Loading…
Reference in a new issue