How to change the app name in OSX menubar in a pure-Python application bundle?
Asked Answered
F

3

3

I am trying to create a pure-Python application bundle for a wxPython app. I created the .app directory with the files described in Apple docs, with an Info.plist file etc. The only difference between a "normal" app and this bundle is that the entry point (CFBundleExecutable) is a script which starts with the following line:

#!/usr/bin/env python2.5

Everything works fine except that the application name in the OSX menubar is still "Python" although I have set the CFBundleName in Info.plist (I copied the result of py2app, actually). The full Info.plist can be viewed here.

How can I change this? I have read everywhere that the menubar name is only determined by CFBundleName. How is it possible that the Python interpreter can change this in runtime?

Note: I was using py2app before, but the result was too large (>50 MB instead of the current 100KB) and it was not even portable between Leopard and Snow Leopard... so it seems to be much easier to create a pure-Python app bundle "by hand" than transforming the output of py2app.

Fairspoken answered 28/5, 2010 at 20:20 Comment(0)
F
3

The "Build Applet.app" that comes with the Python developer tools is actually a pure-Python app bundle. It does the following:

  • a Python interpreter is placed (or linked) into the MacOS/ directory
  • the executable script (Foo.app/Contents/MacOS/Foo) sets up some environment variables and calls os.execve() to this interpreter.

The executable script looks like this (it is assumed that the entry point of the program is in Resources/main.py):

#!/System/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python
import sys, os
execdir = os.path.dirname(sys.argv[0])
executable = os.path.join(execdir, "Python")
resdir = os.path.join(os.path.dirname(execdir), "Resources")
libdir = os.path.join(os.path.dirname(execdir), "Frameworks")
mainprogram = os.path.join(resdir, "main.py")

sys.argv.insert(1, mainprogram)
pypath = os.getenv("PYTHONPATH", "")
if pypath:
    pypath = ":" + pypath
os.environ["PYTHONPATH"] = resdir + pypath
os.environ["PYTHONEXECUTABLE"] = executable
os.environ["DYLD_LIBRARY_PATH"] = libdir
os.environ["DYLD_FRAMEWORK_PATH"] = libdir
os.execve(executable, sys.argv, os.environ)
Fairspoken answered 1/6, 2010 at 22:27 Comment(1)
Sorry, so what exactly is changed here? I am having the same issue!Ursal
G
3

Change a key called LSHasLocalizedDisplayName in Info.plist to true, as in:

<key>LSHasLocalizedDisplayName</key>
<true/>

and then create a file in the executable bundle

foo.app/Contents/Resources/English.lproj/InfoPlist.strings

which has lines

CFBundleName="name in the menu bar";
CFBundleDisplayName="name in the Finder";
Gipson answered 28/5, 2010 at 23:27 Comment(3)
Thanks for the answer!... But no luck :( I have also tried to add the CFBundleLocalizations key with no success.Fairspoken
I noticed the missing semicolons (it gave a warning), so it was not a problem. Here's the result: tinyurl.com/2wcqe9pFairspoken
For me the "name in the Finder" part worked, but not the "name in the menu bar" part, which is what I care about most. Testing these solutions is especially frustrating because the Mac tends to cache previous versions of your app. Thus "touch Foo.app" is a useful command before each test.Nickerson
F
3

The "Build Applet.app" that comes with the Python developer tools is actually a pure-Python app bundle. It does the following:

  • a Python interpreter is placed (or linked) into the MacOS/ directory
  • the executable script (Foo.app/Contents/MacOS/Foo) sets up some environment variables and calls os.execve() to this interpreter.

The executable script looks like this (it is assumed that the entry point of the program is in Resources/main.py):

#!/System/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python
import sys, os
execdir = os.path.dirname(sys.argv[0])
executable = os.path.join(execdir, "Python")
resdir = os.path.join(os.path.dirname(execdir), "Resources")
libdir = os.path.join(os.path.dirname(execdir), "Frameworks")
mainprogram = os.path.join(resdir, "main.py")

sys.argv.insert(1, mainprogram)
pypath = os.getenv("PYTHONPATH", "")
if pypath:
    pypath = ":" + pypath
os.environ["PYTHONPATH"] = resdir + pypath
os.environ["PYTHONEXECUTABLE"] = executable
os.environ["DYLD_LIBRARY_PATH"] = libdir
os.environ["DYLD_FRAMEWORK_PATH"] = libdir
os.execve(executable, sys.argv, os.environ)
Fairspoken answered 1/6, 2010 at 22:27 Comment(1)
Sorry, so what exactly is changed here? I am having the same issue!Ursal
F
1

Actually, if you create a soft link to the python executable and use that rather than the executable itself (inside your MyApp.app/Contents/MacOs/-script-), everything seems to work properly. I personally use a "#! /bin/sh" script instead and just use the "exec" command. (I you may still have to use wx.App.SetAppName(MyAppName).) For example:

#! /bin/sh

export PYTHONPATH=/Applications/MyApp.app/Contents/Resources/[myPythonCode]
export DYLD_LIBRARY_PATH=/Library/Frameworks/Python.framework/Versions/2.6/lib
exec "/Applications/MyApp.app/Contents/MacOS/[SoftLinkToPythonExe]" "/Applications/MyApp.app/Contents/Resources/myAppMain.py"
Forcible answered 3/11, 2010 at 20:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.