1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
from Foundation import *
from AppKit import *
import os, sys
import objc
import MacOS
from pygame.pkgdata import getResource
from pygame.base import get_sdl_version
__all__ = ['init']
# Need to do this if not running with a nib
def setupAppleMenu(app):
appleMenuController = NSAppleMenuController.alloc().init()
appleMenuController.retain()
appleMenu = NSMenu.alloc().initWithTitle_('')
appleMenuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('', None, '')
appleMenuItem.setSubmenu_(appleMenu)
app.mainMenu().addItem_(appleMenuItem)
appleMenuController.controlMenu_(appleMenu)
app.mainMenu().removeItem_(appleMenuItem)
# Need to do this if not running with a nib
def setupWindowMenu(app):
windowMenu = NSMenu.alloc().initWithTitle_('Window')
windowMenu.retain()
menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Minimize', 'performMiniaturize:', 'm')
windowMenu.addItem_(menuItem)
windowMenuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Window', None, '')
windowMenuItem.setSubmenu_(windowMenu)
app.mainMenu().addItem_(windowMenuItem)
app.setWindowsMenu_(windowMenu)
# Used to cleanly terminate
class PyGameAppDelegate(NSObject):
def applicationShouldTerminate_(self, app):
import pygame.event
pygame.event.post(pygame.event.Event(pygame.QUIT))
return NSTerminateLater
def windowUpdateNotification_(self, notification):
win = notification.object()
if get_sdl_version() < (1, 2, 8) and isinstance(win, objc.lookUpClass('SDL_QuartzWindow')):
# Seems to be a retain count bug in SDL.. workaround!
win.retain()
NSNotificationCenter.defaultCenter().removeObserver_name_object_(
self, NSWindowDidUpdateNotification, None)
self.release()
def setIcon(app):
try:
defaultIcon = getResource('pygame_icon.tiff').read()
except IOError:
return
data = NSData.dataWithBytes_length_(defaultIcon, len(defaultIcon))
if data is None:
return
img = NSImage.alloc().initWithData_(data)
if img is None:
return
app.setApplicationIconImage_(img)
def install():
app = NSApplication.sharedApplication()
setIcon(app)
appDelegate = PyGameAppDelegate.alloc().init()
app.setDelegate_(appDelegate)
appDelegate.retain()
NSNotificationCenter.defaultCenter().addObserver_selector_name_object_(
appDelegate,
'windowUpdateNotification:',
NSWindowDidUpdateNotification,
None)
if not app.mainMenu():
mainMenu = NSMenu.alloc().init()
app.setMainMenu_(mainMenu)
setupAppleMenu(app)
setupWindowMenu(app)
app.finishLaunching()
app.updateWindows()
app.activateIgnoringOtherApps_(True)
def S(*args):
return ''.join(args)
OSErr = objc._C_SHT
OUTPSN = 'o^{ProcessSerialNumber=LL}'
INPSN = 'n^{ProcessSerialNumber=LL}'
FUNCTIONS=[
# These two are public API
( u'GetCurrentProcess', S(OSErr, OUTPSN) ),
( u'SetFrontProcess', S(OSErr, INPSN) ),
# This is undocumented SPI
( u'CPSSetProcessName', S(OSErr, INPSN, objc._C_CHARPTR) ),
( u'CPSEnableForegroundOperation', S(OSErr, INPSN) ),
]
def WMEnable(name=None):
if name is None:
name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
if isinstance(name, unicode):
name = name.encode('utf-8')
if not hasattr(objc, 'loadBundleFunctions'):
return False
bndl = NSBundle.bundleWithPath_(objc.pathForFramework('/System/Library/Frameworks/ApplicationServices.framework'))
if bndl is None:
print >>sys.stderr, 'ApplicationServices missing'
return False
d = {}
app = NSApplication.sharedApplication()
objc.loadBundleFunctions(bndl, d, FUNCTIONS)
for (fn, sig) in FUNCTIONS:
if fn not in d:
print >>sys.stderr, 'Missing', fn
return False
err, psn = d['GetCurrentProcess']()
if err:
print >>sys.stderr, 'GetCurrentProcess', (err, psn)
return False
err = d['CPSSetProcessName'](psn, name)
if err:
print >>sys.stderr, 'CPSSetProcessName', (err, psn)
return False
err = d['CPSEnableForegroundOperation'](psn)
if err:
print >>sys.stderr, 'CPSEnableForegroundOperation', (err, psn)
return False
err = d['SetFrontProcess'](psn)
if err:
print >>sys.stderr, 'SetFrontProcess', (err, psn)
return False
return True
def init():
if not (MacOS.WMAvailable() or WMEnable()):
raise ImportError, "Can not access the window manager. Use py2app or execute with the pythonw script."
if not NSApp():
# running outside of a bundle
install()
# running inside a bundle, change dir
if (os.getcwd() == '/') and len(sys.argv) > 1:
os.chdir(os.path.dirname(sys.argv[0]))
return True
|