mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
using bundles (and LSUIElement=1) to better manage OSX dock icons
This commit is contained in:
parent
270d79658e
commit
884c389bad
@ -39,7 +39,8 @@ class Packager:
|
||||
newName = None, deleteTemp = False,
|
||||
explicit = False, compress = None, extract = None,
|
||||
text = None, unprocessed = None,
|
||||
executable = None, platformSpecific = None):
|
||||
executable = None, dependencyDir = None,
|
||||
platformSpecific = None):
|
||||
assert isinstance(filename, Filename)
|
||||
self.filename = Filename(filename)
|
||||
self.newName = newName
|
||||
@ -50,6 +51,7 @@ class Packager:
|
||||
self.text = text
|
||||
self.unprocessed = unprocessed
|
||||
self.executable = executable
|
||||
self.dependencyDir = dependencyDir
|
||||
self.platformSpecific = platformSpecific
|
||||
|
||||
if not self.newName:
|
||||
@ -73,6 +75,11 @@ class Packager:
|
||||
if self.executable is None:
|
||||
self.executable = (ext in packager.executableExtensions)
|
||||
|
||||
if self.executable and self.dependencyDir is None:
|
||||
# By default, install executable dependencies in the
|
||||
# same directory with the executable itself.
|
||||
self.dependencyDir = Filename(self.newName).getDirname()
|
||||
|
||||
if self.extract is None:
|
||||
self.extract = self.executable or (ext in packager.extractExtensions)
|
||||
if self.platformSpecific is None:
|
||||
@ -779,7 +786,9 @@ class Packager:
|
||||
for filename in filenames:
|
||||
filename = Filename.fromOsSpecific(filename)
|
||||
filename.resolveFilename(path)
|
||||
self.addFile(filename, newName = filename.getBasename(),
|
||||
|
||||
newName = Filename(file.dependencyDir, filename.getBasename())
|
||||
self.addFile(filename, newName = newName.cStr(),
|
||||
explicit = False, executable = True)
|
||||
|
||||
def __parseDependenciesWindows(self, tempFile):
|
||||
@ -851,13 +860,19 @@ class Packager:
|
||||
""" Copies the given library file to a temporary directory,
|
||||
and alters the dependencies so that it doesn't contain absolute
|
||||
framework dependencies. """
|
||||
|
||||
# Copy the file to a temporary location because we don't want
|
||||
# to modify the original (there's a big chance that we break it)
|
||||
assert file.filename.exists(), "File doesn't exist: %s" % ffilename
|
||||
tmpfile = Filename.fromOsSpecific("/tmp/p3d_" + hashlib.md5(file.filename.toOsSpecific()).hexdigest())
|
||||
if not tmpfile.exists():
|
||||
|
||||
if not file.deleteTemp:
|
||||
# Copy the file to a temporary location because we
|
||||
# don't want to modify the original (there's a big
|
||||
# chance that we break it).
|
||||
|
||||
# Copy it every time, because the source file might
|
||||
# have changed since last time we ran.
|
||||
assert file.filename.exists(), "File doesn't exist: %s" % ffilename
|
||||
tmpfile = Filename.temporary('', "p3d_" + file.filename.getBasename())
|
||||
file.filename.copyTo(tmpfile)
|
||||
file.filename = tmpfile
|
||||
file.deleteTemp = True
|
||||
|
||||
# Alter the dependencies to have a relative path rather than absolute
|
||||
for filename in framework_deps:
|
||||
@ -865,7 +880,6 @@ class Packager:
|
||||
os.system('install_name_tool -id "%s" "%s"' % (os.path.basename(filename), tmpfile.toOsSpecific()))
|
||||
else:
|
||||
os.system('install_name_tool -change "%s" "%s" "%s"' % (filename, os.path.basename(filename), tmpfile.toOsSpecific()))
|
||||
self.sourceFilenames[file.filename].filename = tmpfile
|
||||
|
||||
def __addImplicitDependenciesOSX(self):
|
||||
""" Walks through the list of files, looking for dylib's
|
||||
@ -915,7 +929,7 @@ class Packager:
|
||||
if len(framework_deps) > 0:
|
||||
# Fixes dependencies like @executable_path/../Library/Frameworks/Cg.framework/Cg
|
||||
self.__alterFrameworkDependencies(file, framework_deps)
|
||||
|
||||
|
||||
for filename in filenames:
|
||||
if '.framework/' in filename:
|
||||
# It references a framework, and besides the fact
|
||||
@ -926,7 +940,9 @@ class Packager:
|
||||
# It's just a normal library - find it on the path.
|
||||
filename = Filename.fromOsSpecific(filename)
|
||||
filename.resolveFilename(path)
|
||||
self.addFile(filename, newName = filename.getBasename(),
|
||||
|
||||
newName = Filename(file.dependencyDir, filename.getBasename())
|
||||
self.addFile(filename, newName = newName.cStr(),
|
||||
explicit = False, executable = True)
|
||||
|
||||
def __parseDependenciesOSX(self, tempFile):
|
||||
@ -998,7 +1014,9 @@ class Packager:
|
||||
for filename in filenames:
|
||||
filename = Filename.fromOsSpecific(filename)
|
||||
filename.resolveFilename(path)
|
||||
self.addFile(filename, newName = filename.getBasename(),
|
||||
|
||||
newName = Filename(file.dependencyDir, filename.getBasename())
|
||||
self.addFile(filename, newName = newName.cStr(),
|
||||
explicit = False, executable = True)
|
||||
|
||||
def __parseDependenciesPosix(self, tempFile):
|
||||
@ -2517,6 +2535,22 @@ class Packager:
|
||||
# an associated dynamic library. Note that the .exe and .dll
|
||||
# extensions are automatically replaced with the appropriate
|
||||
# platform-specific extensions.
|
||||
|
||||
if self.platform.startswith('osx'):
|
||||
# On Mac, we package up a P3DPython.app bundle. This
|
||||
# includes specifications in the plist file to avoid
|
||||
# creating a dock icon and stuff.
|
||||
|
||||
# Find p3dpython.plist in the direct source tree.
|
||||
import direct
|
||||
plist = Filename(direct.__path__[0], 'plugin/p3dpython.plist')
|
||||
self.do_makeBundle('P3DPython.app', plist, executable = 'p3dpython',
|
||||
dependencyDir = '')
|
||||
|
||||
else:
|
||||
# Anywhere else, we just ship the executable file p3dcert.exe.
|
||||
self.do_file('p3dcert.exe')
|
||||
|
||||
self.do_file('p3dpython.exe')
|
||||
if PandaSystem.getPlatform().startswith('win'):
|
||||
self.do_file('p3dpythonw.exe')
|
||||
@ -2574,6 +2608,27 @@ class Packager:
|
||||
freezer.reset()
|
||||
package.mainModule = None
|
||||
|
||||
def do_makeBundle(self, bundleName, plist, executable = None,
|
||||
resources = None, dependencyDir = None):
|
||||
""" Constructs a minimal OSX "bundle" consisting of an
|
||||
executable and a plist file, with optional resource files
|
||||
(such as icons), and adds it to the package under the given
|
||||
name. """
|
||||
|
||||
contents = bundleName + '/Contents'
|
||||
|
||||
self.addFiles([plist], newName = contents + '/Info.plist',
|
||||
extract = True)
|
||||
if executable:
|
||||
basename = Filename(executable).getBasename()
|
||||
self.addFiles([executable], newName = contents + '/MacOS/' + basename,
|
||||
extract = True, executable = True, dependencyDir = dependencyDir)
|
||||
if resources:
|
||||
self.addFiles(resources, newDir = contents + '/Resources',
|
||||
extract = True, dependencyDir = dependencyDir)
|
||||
|
||||
|
||||
|
||||
def do_file(self, *args, **kw):
|
||||
""" Adds the indicated file or files to the current package.
|
||||
See addFiles(). """
|
||||
@ -2582,7 +2637,7 @@ class Packager:
|
||||
|
||||
def addFiles(self, filenames, text = None, newName = None,
|
||||
newDir = None, extract = None, executable = None,
|
||||
deleteTemp = False, literal = False):
|
||||
deleteTemp = False, literal = False, dependencyDir = None):
|
||||
|
||||
""" Adds the indicated arbitrary files to the current package.
|
||||
|
||||
@ -2705,7 +2760,8 @@ class Packager:
|
||||
self.currentPackage.addFile(
|
||||
filename, newName = name, extract = extract,
|
||||
explicit = explicit, executable = executable,
|
||||
text = text, deleteTemp = deleteTemp)
|
||||
text = text, deleteTemp = deleteTemp,
|
||||
dependencyDir = dependencyDir)
|
||||
|
||||
def do_exclude(self, filename):
|
||||
""" Marks the indicated filename as not to be included. The
|
||||
|
@ -69,4 +69,16 @@ class p3dcert(package):
|
||||
# user to accept or deny unknown applications, is its own package.
|
||||
config(display_name = "Authorization Dialog")
|
||||
|
||||
file('p3dcert.exe')
|
||||
if platform.startswith('osx'):
|
||||
# On Mac, we package up a P3DCert.app bundle. This includes
|
||||
# specifications in the plist file to avoid creating a dock
|
||||
# icon and stuff.
|
||||
|
||||
# Find p3dcert.plist in the direct source tree.
|
||||
import direct
|
||||
plist = Filename(direct.__path__[0], 'plugin/p3dcert.plist')
|
||||
makeBundle('P3DCert.app', plist, executable = 'p3dcert')
|
||||
|
||||
else:
|
||||
# Anywhere else, we just ship the executable file p3dcert.exe.
|
||||
file('p3dcert.exe')
|
||||
|
@ -155,6 +155,10 @@ start_p3dcert() {
|
||||
#ifdef _WIN32
|
||||
_p3dcert_exe += ".exe";
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
// On OSX, run from the packaged bundle.
|
||||
_p3dcert_exe = root_dir + "/P3DCert.app/Contents/MacOS/p3dcert";
|
||||
#endif
|
||||
|
||||
// Populate the new process' environment.
|
||||
_env = string();
|
||||
|
@ -17,11 +17,6 @@
|
||||
#include "wx/filename.h"
|
||||
|
||||
#include "ca_bundle_data_src.c"
|
||||
|
||||
#ifdef __WXMAC__
|
||||
#include <Carbon/Carbon.h>
|
||||
extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
|
||||
#endif
|
||||
|
||||
static const wxString
|
||||
self_signed_cert_text =
|
||||
@ -96,19 +91,11 @@ OnInit() {
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
#ifdef __WXMAC__
|
||||
// Enable the dialog to go to the foreground on Mac, even without
|
||||
// having to wrap it up in a bundle.
|
||||
ProcessSerialNumber psn;
|
||||
|
||||
GetCurrentProcess(&psn);
|
||||
CPSEnableForegroundOperation(&psn);
|
||||
SetFrontProcess(&psn);
|
||||
#endif
|
||||
|
||||
AuthDialog *dialog = new AuthDialog(_cert_filename, _cert_dir);
|
||||
SetTopWindow(dialog);
|
||||
dialog->Show(true);
|
||||
dialog->SetFocus();
|
||||
dialog->Raise();
|
||||
|
||||
// Return true to enter the main loop and wait for user input.
|
||||
return true;
|
||||
@ -155,7 +142,11 @@ END_EVENT_TABLE()
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AuthDialog::
|
||||
AuthDialog(const wxString &cert_filename, const wxString &cert_dir) :
|
||||
wxDialog(NULL, wxID_ANY, _T("New Panda3D Application"), wxDefaultPosition),
|
||||
// I hate stay-on-top dialogs, but if we don't set this flag, it
|
||||
// doesn't come to the foreground on OSX, and might be lost behind
|
||||
// the browser window.
|
||||
wxDialog(NULL, wxID_ANY, _T("New Panda3D Application"), wxDefaultPosition,
|
||||
wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP),
|
||||
_cert_dir(cert_dir)
|
||||
{
|
||||
_view_cert_dialog = NULL;
|
||||
|
@ -786,6 +786,10 @@ start_p3dpython(P3DInstance *inst) {
|
||||
_p3dpython_exe = P3D_PLUGIN_P3DPYTHON;
|
||||
if (_p3dpython_exe.empty()) {
|
||||
_p3dpython_exe = _python_root_dir + "/p3dpython";
|
||||
#ifdef __APPLE__
|
||||
// On OSX, run from the packaged bundle.
|
||||
_p3dpython_exe = _python_root_dir + "/P3DPython.app/Contents/MacOS/p3dpython";
|
||||
#endif
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (!inst_mgr->get_console_environment()) {
|
||||
|
34
direct/src/plugin/p3dcert.plist
Normal file
34
direct/src/plugin/p3dcert.plist
Normal file
@ -0,0 +1,34 @@
|
||||
<?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>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>P3DCert</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>p3dcert</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.panda3d.runtime.p3dcert</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>P3DCert</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.9.3</string>
|
||||
<key>LSUIElement</key>
|
||||
<string>1</string>
|
||||
<key>LSHasLocalizedDisplayName</key>
|
||||
<false/>
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<false/>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
34
direct/src/plugin/p3dpython.plist
Normal file
34
direct/src/plugin/p3dpython.plist
Normal file
@ -0,0 +1,34 @@
|
||||
<?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>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>P3DPython</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>p3dpython</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.panda3d.runtime.p3dpython</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>P3DPython</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.9.3</string>
|
||||
<key>LSUIElement</key>
|
||||
<string>1</string>
|
||||
<key>LSHasLocalizedDisplayName</key>
|
||||
<false/>
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<false/>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
@ -32,7 +32,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>panda3d.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.panda3d.runtime</string>
|
||||
<string>org.panda3d.runtime.panda3d_mac</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
@ -11,15 +11,6 @@
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __APPLE__
|
||||
// We have to include this before we include any Panda libraries,
|
||||
// because one of the things we pick up in Panda defines a macro for
|
||||
// TCP_NODELAY and friends, causing heartaches for the header files
|
||||
// picked up here.
|
||||
#include <Carbon/Carbon.h>
|
||||
extern "C" { void CPSEnableForegroundOperation(ProcessSerialNumber* psn); }
|
||||
#endif
|
||||
|
||||
#include "showBase.h"
|
||||
|
||||
@ -68,6 +59,9 @@ get_config_showbase() {
|
||||
// At the moment, this is a no-op except on Mac.
|
||||
void
|
||||
init_app_for_gui() {
|
||||
// Actually, this may not be necessary after all. Let's assume the
|
||||
// user will always be running from a bundle or from pythonw.
|
||||
/*
|
||||
static bool initted_for_gui = false;
|
||||
if (!initted_for_gui) {
|
||||
initted_for_gui = true;
|
||||
@ -79,6 +73,7 @@ init_app_for_gui() {
|
||||
SetFrontProcess(&psn);
|
||||
#endif // IS_OSX
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// klunky interface since we cant pass array from python->C++ to use verify_window_sizes directly
|
||||
|
@ -1077,7 +1077,17 @@ os_open_window(WindowProperties &req_properties) {
|
||||
GlobalInits = true;
|
||||
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
|
||||
// Determine if we're running from a bundle.
|
||||
CFDictionaryRef dref =
|
||||
ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask);
|
||||
// If the dictionary doesn't have "BundlePath", then we're not
|
||||
// running from a bundle, and we need to call TransformProcessType
|
||||
// to make the process a "foreground" application, with its own
|
||||
// icon in the dock and such.
|
||||
if (!CFDictionaryContainsKey(dref, CFSTR("BundlePath"))) {
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
}
|
||||
SetFrontProcess(&psn);
|
||||
}
|
||||
|
||||
|
@ -880,8 +880,18 @@ bool TinyOsxGraphicsWindow::OSOpenWindow(WindowProperties &req_properties)
|
||||
GlobalInits = true;
|
||||
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
SetFrontProcess(&psn);
|
||||
|
||||
// Determine if we're running from a bundle.
|
||||
CFDictionaryRef dref =
|
||||
ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask);
|
||||
// If the dictionary doesn't have "BundlePath", then we're not
|
||||
// running from a bundle, and we need to call TransformProcessType
|
||||
// to make the process a "foreground" application, with its own
|
||||
// icon in the dock and such.
|
||||
if (!CFDictionaryContainsKey(dref, CFSTR("BundlePath"))) {
|
||||
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
}
|
||||
SetFrontProcess(&psn);
|
||||
}
|
||||
|
||||
if (req_properties.has_fullscreen() && req_properties.get_fullscreen())
|
||||
|
Loading…
x
Reference in New Issue
Block a user