Begin Notification Center support: notifier helper app; docktileplugin, support for NSUserNotificationCenterDelegate methods

This commit is contained in:
Greg Neagle
2015-04-15 10:44:37 -07:00
parent 9d6de2e696
commit 42e2cf17f1
19 changed files with 1719 additions and 25 deletions
@@ -0,0 +1,30 @@
/*
File: DockTilePlugIn.h
Copyright 2015 Greg Neagle.
Liberally adapted from Apple sample code:
https://developer.apple.com/library/mac/samplecode/DockTile/Listings/DockTilePlugIn_DockTilePlugIn_h.html
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Cocoa/Cocoa.h>
@interface DockTilePlugIn : NSObject <NSDockTilePlugIn> {
id updateObserver;
}
@property(retain) id updateObserver;
@end
@@ -0,0 +1,62 @@
/*
File: DockTilePlugIn.m
Copyright 2015 Greg Neagle.
Liberally adapted from Apple sample code:
https://developer.apple.com/library/mac/samplecode/DockTile/Listings/DockTilePlugIn_DockTilePlugIn_h.html
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "DockTilePlugIn.h"
@implementation DockTilePlugIn
@synthesize updateObserver;
static void updateCount(NSDockTile *tile) {
CFPreferencesAppSynchronize(CFSTR("ManagedInstalls"));
NSInteger count = CFPreferencesGetAppIntegerValue(CFSTR("PendingUpdateCount"), CFSTR("ManagedInstalls"), NULL);
if (count) {
[tile setBadgeLabel:[NSString stringWithFormat:@"%ld", (long)count]];
} else {
[tile setBadgeLabel: nil];
}
}
- (void)setDockTile:(NSDockTile *)dockTile {
if (dockTile) {
// Attach an observer that will update the count in the dock tile whenever it changes
self.updateObserver = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.googlecode.munki.managedsoftwareupdate.dock.updateschanged" object:nil queue:nil usingBlock:^(NSNotification *notification) {
updateCount(dockTile); // Note that this block captures (and retains) dockTile for use later. Also note that it does not capture self, which means -dealloc may be called even while the notification is active. Although it's not clear this needs to be supported, this does eliminate a potential source of leaks.
}];
updateCount(dockTile); // Make sure count is updated as soon as we are invoked
} else {
// Strictly speaking this may not be necessary (since the plug-in may be terminated when it's removed from the dock),
/// but it's good practice
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self.updateObserver];
self.updateObserver = nil;
}
}
- (void)dealloc {
if (self.updateObserver) {
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self.updateObserver];
self.updateObserver = nil;
}
[super dealloc];
}
@end
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.googlecode.munki.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 The Munki Project. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>DockTile</string>
</dict>
</plist>
@@ -33,9 +33,35 @@
C0B9E8B219AB8E5500DB7247 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C09004FC16CDD84E00BE34CE /* InfoPlist.strings */; };
C0B9E8B619AF7E9E00DB7247 /* Managed Software Center 10_6.icns in Resources */ = {isa = PBXBuildFile; fileRef = C0B9E8B519AF7E9E00DB7247 /* Managed Software Center 10_6.icns */; };
C0E098BC1857A3C80045DEEB /* msclib.py in Resources */ = {isa = PBXBuildFile; fileRef = C0E098BB1857A3C80045DEEB /* msclib.py */; };
C0EF96BA1ADDB9B2002C02FF /* DockTilePlugIn.m in Sources */ = {isa = PBXBuildFile; fileRef = C0EF96B91ADDB9B2002C02FF /* DockTilePlugIn.m */; };
C0EF96BD1ADDBD88002C02FF /* MSCDockTilePlugin.docktileplugin in Copy Files */ = {isa = PBXBuildFile; fileRef = C0EF96B11ADDB90B002C02FF /* MSCDockTilePlugin.docktileplugin */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
C0F1586E187D256200052F9A /* MyStuffTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = C0F1586D187D256200052F9A /* MyStuffTemplate.png */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
C0EF96C11ADDCBAD002C02FF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C09004E416CDD84E00BE34CE /* Project object */;
proxyType = 1;
remoteGlobalIDString = C0EF96B01ADDB90B002C02FF;
remoteInfo = MSCDockTilePlugin;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
C0EF96BC1ADDBD77002C02FF /* Copy Files */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
C0EF96BD1ADDBD88002C02FF /* MSCDockTilePlugin.docktileplugin in Copy Files */,
);
name = "Copy Files";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
650B29A319B69FC800A5E946 /* MSCToolbar.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSCToolbar.py; sourceTree = "<group>"; };
C00A4C56185FCEC9004EB3B7 /* FoundationPlist.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = FoundationPlist.py; sourceTree = "<group>"; };
@@ -113,6 +139,10 @@
C0B9E8AF19AA55DC00DB7247 /* en_GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en_GB; path = en_GB.lproj/MainMenu.strings; sourceTree = "<group>"; };
C0B9E8B519AF7E9E00DB7247 /* Managed Software Center 10_6.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = "Managed Software Center 10_6.icns"; sourceTree = "<group>"; };
C0E098BB1857A3C80045DEEB /* msclib.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = msclib.py; sourceTree = "<group>"; };
C0EF96B11ADDB90B002C02FF /* MSCDockTilePlugin.docktileplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MSCDockTilePlugin.docktileplugin; sourceTree = BUILT_PRODUCTS_DIR; };
C0EF96B41ADDB90B002C02FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C0EF96B81ADDB9B2002C02FF /* DockTilePlugIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DockTilePlugIn.h; sourceTree = "<group>"; };
C0EF96B91ADDB9B2002C02FF /* DockTilePlugIn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DockTilePlugIn.m; sourceTree = "<group>"; };
C0F1586D187D256200052F9A /* MyStuffTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MyStuffTemplate.png; sourceTree = "<group>"; };
E62967521993D4A400ADCB43 /* en_GB */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en_GB; path = en_GB.lproj/MainMenu.xib; sourceTree = "<group>"; };
E62967541993D4AF00ADCB43 /* en_GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en_GB; path = en_GB.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -135,6 +165,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C0EF96AE1ADDB90B002C02FF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -142,6 +179,7 @@
isa = PBXGroup;
children = (
C09004F916CDD84E00BE34CE /* Managed Software Center */,
C0EF96B21ADDB90B002C02FF /* MSCDockTilePlugin */,
C09004F016CDD84E00BE34CE /* Frameworks */,
C09004EE16CDD84E00BE34CE /* Products */,
C035274D18A9C582004A5AE4 /* libpython2.6.dylib */,
@@ -152,6 +190,7 @@
isa = PBXGroup;
children = (
C09004ED16CDD84E00BE34CE /* Managed Software Center.app */,
C0EF96B11ADDB90B002C02FF /* MSCDockTilePlugin.docktileplugin */,
);
name = Products;
sourceTree = "<group>";
@@ -226,6 +265,24 @@
name = Resources;
sourceTree = "<group>";
};
C0EF96B21ADDB90B002C02FF /* MSCDockTilePlugin */ = {
isa = PBXGroup;
children = (
C0EF96B81ADDB9B2002C02FF /* DockTilePlugIn.h */,
C0EF96B91ADDB9B2002C02FF /* DockTilePlugIn.m */,
C0EF96B31ADDB90B002C02FF /* Supporting Files */,
);
path = MSCDockTilePlugin;
sourceTree = "<group>";
};
C0EF96B31ADDB90B002C02FF /* Supporting Files */ = {
isa = PBXGroup;
children = (
C0EF96B41ADDB90B002C02FF /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -238,16 +295,35 @@
C09004EA16CDD84E00BE34CE /* Frameworks */,
C09004EB16CDD84E00BE34CE /* Resources */,
C09CE1DA18BEA59E00B9724A /* Embed version info */,
C0EF96BC1ADDBD77002C02FF /* Copy Files */,
);
buildRules = (
);
dependencies = (
C0EF96C21ADDCBAD002C02FF /* PBXTargetDependency */,
);
name = "Managed Software Center";
productName = SomeDumbTest;
productReference = C09004ED16CDD84E00BE34CE /* Managed Software Center.app */;
productType = "com.apple.product-type.application";
};
C0EF96B01ADDB90B002C02FF /* MSCDockTilePlugin */ = {
isa = PBXNativeTarget;
buildConfigurationList = C0EF96B51ADDB90B002C02FF /* Build configuration list for PBXNativeTarget "MSCDockTilePlugin" */;
buildPhases = (
C0EF96C01ADDC0AF002C02FF /* Resources */,
C0EF96AD1ADDB90B002C02FF /* Sources */,
C0EF96AE1ADDB90B002C02FF /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = MSCDockTilePlugin;
productName = MSCDockTilePlugin;
productReference = C0EF96B11ADDB90B002C02FF /* MSCDockTilePlugin.docktileplugin */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -257,6 +333,11 @@
CLASSPREFIX = MSC;
LastUpgradeCheck = 0510;
ORGANIZATIONNAME = "The Munki Project";
TargetAttributes = {
C0EF96B01ADDB90B002C02FF = {
CreatedOnToolsVersion = 6.3;
};
};
};
buildConfigurationList = C09004E716CDD84E00BE34CE /* Build configuration list for PBXProject "Managed Software Center" */;
compatibilityVersion = "Xcode 3.2";
@@ -315,6 +396,7 @@
projectRoot = "";
targets = (
C09004EC16CDD84E00BE34CE /* Managed Software Center */,
C0EF96B01ADDB90B002C02FF /* MSCDockTilePlugin */,
);
};
/* End PBXProject section */
@@ -325,32 +407,39 @@
buildActionMask = 2147483647;
files = (
C0B9E8B219AB8E5500DB7247 /* InfoPlist.strings in Resources */,
C0B37443187089F300B6204E /* toolbarUpdatesTemplate.pdf in Resources */,
C0E098BC1857A3C80045DEEB /* msclib.py in Resources */,
C0AAA21E18BAD8710012663F /* msclog.py in Resources */,
C094B6CF188F7C7700E06897 /* MSCStatusController.py in Resources */,
C079D9C118BD435200BAD62E /* AlertController.py in Resources */,
C0B3744718708A0300B6204E /* WebResources in Resources */,
C090050616CDD84E00BE34CE /* main.py in Resources */,
C0B37442187089F300B6204E /* toolbarCategoriesTemplate.pdf in Resources */,
C0F1586E187D256200052F9A /* MyStuffTemplate.png in Resources */,
C090050816CDD84E00BE34CE /* MSCAppDelegate.py in Resources */,
C05C3CEF188391F200095E65 /* munki.py in Resources */,
650B29A419B69FC800A5E946 /* MSCToolbar.py in Resources */,
C0B9E8B619AF7E9E00DB7247 /* Managed Software Center 10_6.icns in Resources */,
C0AAA22018BC67F90012663F /* mschtml.py in Resources */,
C02C98891911B81D00425167 /* Localizable.strings in Resources */,
C090050B16CDD84E00BE34CE /* MainMenu.xib in Resources */,
C0A71B76188A47C700A6EE82 /* MSCMainWindowController.py in Resources */,
C090050616CDD84E00BE34CE /* main.py in Resources */,
C0E098BC1857A3C80045DEEB /* msclib.py in Resources */,
C0AAA21E18BAD8710012663F /* msclog.py in Resources */,
C0AAA22018BC67F90012663F /* mschtml.py in Resources */,
C05C3CEF188391F200095E65 /* munki.py in Resources */,
C079D9C118BD435200BAD62E /* AlertController.py in Resources */,
C00A4C57185FCEC9004EB3B7 /* FoundationPlist.py in Resources */,
C0AE8658186D2DF900C87AE7 /* Managed Software Center.icns in Resources */,
C0B3743F187089F300B6204E /* AllItemsTemplate.png in Resources */,
C0AAA21C18B801400012663F /* MunkiItems.py in Resources */,
C090050816CDD84E00BE34CE /* MSCAppDelegate.py in Resources */,
C0AE865A186D32AF00C87AE7 /* MSCBadgedTemplateImage.py in Resources */,
C0A71B76188A47C700A6EE82 /* MSCMainWindowController.py in Resources */,
C094B6CF188F7C7700E06897 /* MSCStatusController.py in Resources */,
650B29A419B69FC800A5E946 /* MSCToolbar.py in Resources */,
C0AAA21C18B801400012663F /* MunkiItems.py in Resources */,
C0B9E8B619AF7E9E00DB7247 /* Managed Software Center 10_6.icns in Resources */,
C0AE8658186D2DF900C87AE7 /* Managed Software Center.icns in Resources */,
C0B37443187089F300B6204E /* toolbarUpdatesTemplate.pdf in Resources */,
C0B37442187089F300B6204E /* toolbarCategoriesTemplate.pdf in Resources */,
C0F1586E187D256200052F9A /* MyStuffTemplate.png in Resources */,
C0B3743F187089F300B6204E /* AllItemsTemplate.png in Resources */,
C0B3744718708A0300B6204E /* WebResources in Resources */,
C0B3744618708A0300B6204E /* templates in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C0EF96C01ADDC0AF002C02FF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -393,8 +482,24 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C0EF96AD1ADDB90B002C02FF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C0EF96BA1ADDB9B2002C02FF /* DockTilePlugIn.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
C0EF96C21ADDCBAD002C02FF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C0EF96B01ADDB90B002C02FF /* MSCDockTilePlugin */;
targetProxy = C0EF96C11ADDCBAD002C02FF /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
C02C98871911B81D00425167 /* Localizable.strings */ = {
isa = PBXVariantGroup;
@@ -579,6 +684,88 @@
};
name = Release;
};
C0EF96B61ADDB90B002C02FF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
INFOPLIST_FILE = MSCDockTilePlugin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
MACOSX_DEPLOYMENT_TARGET = 10.6;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"-framework",
Foundation,
"-framework",
AppKit,
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx10.8;
SKIP_INSTALL = NO;
WRAPPER_EXTENSION = docktileplugin;
};
name = Debug;
};
C0EF96B71ADDB90B002C02FF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
INFOPLIST_FILE = MSCDockTilePlugin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
MACOSX_DEPLOYMENT_TARGET = 10.6;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = (
"-framework",
Foundation,
"-framework",
AppKit,
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx10.8;
SKIP_INSTALL = NO;
WRAPPER_EXTENSION = docktileplugin;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -600,6 +787,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C0EF96B51ADDB90B002C02FF /* Build configuration list for PBXNativeTarget "MSCDockTilePlugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C0EF96B61ADDB90B002C02FF /* Debug */,
C0EF96B71ADDB90B002C02FF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C09004E416CDD84E00BE34CE /* Project object */;
@@ -45,6 +45,15 @@ class MSCAppDelegate(NSObject):
def applicationDidFinishLaunching_(self, sender):
'''NSApplication delegate method called at launch'''
userNotification = sender.userInfo().get('NSApplicationLaunchUserNotificationKey')
# we get this notification at launch because it's too early to have declared ourself
# a NSUserNotificationCenterDelegate
if userNotification:
NSLog("Launched via Notification interaction")
self.userNotificationCenter_didActivateNotification_(
NSUserNotificationCenter.defaultUserNotificationCenter(), userNotification)
# Prevent automatic relaunching at login on Lion+
if NSApp.respondsToSelector_('disableRelaunchOnLogin'):
NSApp.disableRelaunchOnLogin()
@@ -60,6 +69,11 @@ class MSCAppDelegate(NSObject):
myImage = NSImage.imageNamed_("Managed Software Center 10_6")
NSApp.setApplicationIconImage_(myImage)
# if we are running under Mountain Lion or later set ourselves as a delegate
# for NSUserNotificationCenter notifications
if os.uname()[2].split('.')[0] > '11':
NSUserNotificationCenter.defaultUserNotificationCenter().setDelegate_(self)
# setup client logging
msclog.setup_logging()
@@ -102,11 +116,8 @@ class MSCAppDelegate(NSObject):
struct.unpack(">i", "GURL")[0],
struct.unpack(">i", "GURL")[0])
def openURL_withReplyEvent_(self, event, replyEvent):
'''Handle openURL messages'''
keyDirectObject = struct.unpack(">i", "----")[0]
url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().decode('utf8')
msclog.log("MSU", "Called by external URL: %s", url)
def openMunkiURL(self, url):
'''Display page associated with munki:// url'''
parsed_url = urlparse(url)
if parsed_url.scheme != 'munki':
msclog.debug_log("URL %s has unsupported scheme" % url)
@@ -120,3 +131,27 @@ class MSCAppDelegate(NSObject):
self.mainWindowController.load_page(filename)
else:
msclog.debug_log("%s doesn't have a valid extension. Prevented from opening" % url)
def openURL_withReplyEvent_(self, event, replyEvent):
'''Handle openURL messages'''
keyDirectObject = struct.unpack(">i", "----")[0]
url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().decode('utf8')
msclog.log("MSU", "Called by external URL: %s", url)
self.openMunkiURL(url)
def userNotificationCenter_didActivateNotification_(self, center, notification):
'''User clicked on a Notification Center alert'''
user_info = notification.userInfo()
if user_info.get('action') == 'open_url':
url = user_info.get('value')
msclog.log("MSU", "Got user notification to open %s" % url)
self.openMunkiURL(url)
center.removeDeliveredNotification_(notification)
else:
msclog.log("MSU", "Got user notification with unrecognized userInfo")
def userNotificationCenter_shouldPresentNotification_(self, center, notification):
return True
def userNotificationCenter_didDeliverNotification_(self, center, notification):
pass
@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSUserNotificationAlertStyle</key>
<string>alert</string>
<key>NSDockTilePlugIn</key>
<string>MSCDockTilePlugin.docktileplugin</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>LSHasLocalizedDisplayName</key>
@@ -21,7 +25,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.0</string>
<string>4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -31,7 +35,7 @@
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2014 The Munki Project https://github.com/munki/munki</string>
<string>Copyright © 2015 The Munki Project https://github.com/munki/munki</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
@@ -0,0 +1,359 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
C0022FD61AD9BCED007DCEC3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0022FD51AD9BCED007DCEC3 /* Cocoa.framework */; };
C0022FDF1AD9BCED007DCEC3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0022FDE1AD9BCED007DCEC3 /* main.m */; };
C0022FE21AD9BCED007DCEC3 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = C0022FE01AD9BCED007DCEC3 /* Credits.rtf */; };
C0022FE51AD9BCED007DCEC3 /* libpython2.6.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C0022FE41AD9BCED007DCEC3 /* libpython2.6.dylib */; };
C0022FE71AD9BCED007DCEC3 /* main.py in Resources */ = {isa = PBXBuildFile; fileRef = C0022FE61AD9BCED007DCEC3 /* main.py */; };
C0022FE91AD9BCED007DCEC3 /* AppDelegate.py in Resources */ = {isa = PBXBuildFile; fileRef = C0022FE81AD9BCED007DCEC3 /* AppDelegate.py */; };
C0022FEC1AD9BCED007DCEC3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C0022FEA1AD9BCED007DCEC3 /* MainMenu.xib */; };
C0022FEE1AD9BCED007DCEC3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0022FED1AD9BCED007DCEC3 /* Images.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
C0022FD21AD9BCED007DCEC3 /* notifier.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = notifier.app; sourceTree = BUILT_PRODUCTS_DIR; };
C0022FD51AD9BCED007DCEC3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
C0022FD81AD9BCED007DCEC3 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
C0022FD91AD9BCED007DCEC3 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
C0022FDA1AD9BCED007DCEC3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
C0022FDD1AD9BCED007DCEC3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C0022FDE1AD9BCED007DCEC3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
C0022FE11AD9BCED007DCEC3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
C0022FE41AD9BCED007DCEC3 /* libpython2.6.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpython2.6.dylib; path = /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/config/libpython2.6.dylib; sourceTree = "<absolute>"; };
C0022FE61AD9BCED007DCEC3 /* main.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = main.py; sourceTree = "<group>"; };
C0022FE81AD9BCED007DCEC3 /* AppDelegate.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = AppDelegate.py; sourceTree = "<group>"; };
C0022FEB1AD9BCED007DCEC3 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
C0022FED1AD9BCED007DCEC3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C0022FCF1AD9BCED007DCEC3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C0022FD61AD9BCED007DCEC3 /* Cocoa.framework in Frameworks */,
C0022FE51AD9BCED007DCEC3 /* libpython2.6.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C0022FC91AD9BCED007DCEC3 = {
isa = PBXGroup;
children = (
C0022FDB1AD9BCED007DCEC3 /* notifier */,
C0022FD41AD9BCED007DCEC3 /* Frameworks */,
C0022FD31AD9BCED007DCEC3 /* Products */,
);
sourceTree = "<group>";
};
C0022FD31AD9BCED007DCEC3 /* Products */ = {
isa = PBXGroup;
children = (
C0022FD21AD9BCED007DCEC3 /* notifier.app */,
);
name = Products;
sourceTree = "<group>";
};
C0022FD41AD9BCED007DCEC3 /* Frameworks */ = {
isa = PBXGroup;
children = (
C0022FD51AD9BCED007DCEC3 /* Cocoa.framework */,
C0022FD71AD9BCED007DCEC3 /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
C0022FD71AD9BCED007DCEC3 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
C0022FD81AD9BCED007DCEC3 /* AppKit.framework */,
C0022FD91AD9BCED007DCEC3 /* CoreData.framework */,
C0022FDA1AD9BCED007DCEC3 /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
C0022FDB1AD9BCED007DCEC3 /* notifier */ = {
isa = PBXGroup;
children = (
C0022FE61AD9BCED007DCEC3 /* main.py */,
C0022FE81AD9BCED007DCEC3 /* AppDelegate.py */,
C0022FEA1AD9BCED007DCEC3 /* MainMenu.xib */,
C0022FED1AD9BCED007DCEC3 /* Images.xcassets */,
C0022FE31AD9BCED007DCEC3 /* SharedLibraries */,
C0022FDC1AD9BCED007DCEC3 /* Supporting Files */,
);
path = notifier;
sourceTree = "<group>";
};
C0022FDC1AD9BCED007DCEC3 /* Supporting Files */ = {
isa = PBXGroup;
children = (
C0022FDD1AD9BCED007DCEC3 /* Info.plist */,
C0022FDE1AD9BCED007DCEC3 /* main.m */,
C0022FE01AD9BCED007DCEC3 /* Credits.rtf */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
C0022FE31AD9BCED007DCEC3 /* SharedLibraries */ = {
isa = PBXGroup;
children = (
C0022FE41AD9BCED007DCEC3 /* libpython2.6.dylib */,
);
name = SharedLibraries;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
C0022FD11AD9BCED007DCEC3 /* notifier */ = {
isa = PBXNativeTarget;
buildConfigurationList = C0022FF11AD9BCED007DCEC3 /* Build configuration list for PBXNativeTarget "notifier" */;
buildPhases = (
C0022FCE1AD9BCED007DCEC3 /* Sources */,
C0022FCF1AD9BCED007DCEC3 /* Frameworks */,
C0022FD01AD9BCED007DCEC3 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = notifier;
productName = notifier;
productReference = C0022FD21AD9BCED007DCEC3 /* notifier.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C0022FCA1AD9BCED007DCEC3 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0620;
ORGANIZATIONNAME = "The Munki Project";
TargetAttributes = {
C0022FD11AD9BCED007DCEC3 = {
CreatedOnToolsVersion = 6.2;
};
};
};
buildConfigurationList = C0022FCD1AD9BCED007DCEC3 /* Build configuration list for PBXProject "notifier" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = C0022FC91AD9BCED007DCEC3;
productRefGroup = C0022FD31AD9BCED007DCEC3 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
C0022FD11AD9BCED007DCEC3 /* notifier */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
C0022FD01AD9BCED007DCEC3 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C0022FE21AD9BCED007DCEC3 /* Credits.rtf in Resources */,
C0022FEE1AD9BCED007DCEC3 /* Images.xcassets in Resources */,
C0022FE91AD9BCED007DCEC3 /* AppDelegate.py in Resources */,
C0022FE71AD9BCED007DCEC3 /* main.py in Resources */,
C0022FEC1AD9BCED007DCEC3 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C0022FCE1AD9BCED007DCEC3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C0022FDF1AD9BCED007DCEC3 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
C0022FE01AD9BCED007DCEC3 /* Credits.rtf */ = {
isa = PBXVariantGroup;
children = (
C0022FE11AD9BCED007DCEC3 /* en */,
);
name = Credits.rtf;
sourceTree = "<group>";
};
C0022FEA1AD9BCED007DCEC3 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
C0022FEB1AD9BCED007DCEC3 /* en */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
C0022FEF1AD9BCED007DCEC3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/System/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6,
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.6/lib/python2.6/config",
);
MACOSX_DEPLOYMENT_TARGET = 10.6;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx10.9;
};
name = Debug;
};
C0022FF01AD9BCED007DCEC3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/System/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6,
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.6/lib/python2.6/config",
);
MACOSX_DEPLOYMENT_TARGET = 10.6;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx10.9;
};
name = Release;
};
C0022FF21AD9BCED007DCEC3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = notifier/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.6/lib/python2.6/config",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
C0022FF31AD9BCED007DCEC3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = notifier/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.6/lib/python2.6/config",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C0022FCD1AD9BCED007DCEC3 /* Build configuration list for PBXProject "notifier" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C0022FEF1AD9BCED007DCEC3 /* Debug */,
C0022FF01AD9BCED007DCEC3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C0022FF11AD9BCED007DCEC3 /* Build configuration list for PBXNativeTarget "notifier" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C0022FF21AD9BCED007DCEC3 /* Debug */,
C0022FF31AD9BCED007DCEC3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C0022FCA1AD9BCED007DCEC3 /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:notifier.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>E088A8E1-4185-4AB3-AE66-1B742E32B2A2</string>
<key>IDESourceControlProjectName</key>
<string>project</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>A31FD838B66508AF3FC9DA0BE09B237ED93F27DB</key>
<string>https://github.com/munki/munki.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>code/apps/notifier/notifier.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>A31FD838B66508AF3FC9DA0BE09B237ED93F27DB</key>
<string>../../../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>https://github.com/munki/munki.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>A31FD838B66508AF3FC9DA0BE09B237ED93F27DB</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>A31FD838B66508AF3FC9DA0BE09B237ED93F27DB</string>
<key>IDESourceControlWCCName</key>
<string>munki</string>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0620"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C0022FD11AD9BCED007DCEC3"
BuildableName = "notifier.app"
BlueprintName = "notifier"
ReferencedContainer = "container:notifier.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C0022FD11AD9BCED007DCEC3"
BuildableName = "notifier.app"
BlueprintName = "notifier"
ReferencedContainer = "container:notifier.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C0022FD11AD9BCED007DCEC3"
BuildableName = "notifier.app"
BlueprintName = "notifier"
ReferencedContainer = "container:notifier.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C0022FD11AD9BCED007DCEC3"
BuildableName = "notifier.app"
BlueprintName = "notifier"
ReferencedContainer = "container:notifier.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>notifier.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>C0022FD11AD9BCED007DCEC3</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
+135
View File
@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
#
# AppDelegate.py
# notifier
#
# Created by Greg Neagle on 4/11/15.
# Copyright (c) 2015 The Munki Project. All rights reserved.
#
from Foundation import *
from AppKit import *
import objc
MSCbundleIdentifier = u'com.googlecode.munki.ManagedSoftwareCenter'
NotificationCenterUIBundleID = u'com.apple.notificationcenterui'
class AppDelegate(NSObject):
def applicationDidFinishLaunching_(self, notification):
userNotification = notification.userInfo().get('NSApplicationLaunchUserNotificationKey')
if userNotification:
NSLog('Launched due to NSUserNotification')
self.userActivatedNotification_(userNotification)
NSApp.terminate_(self)
else:
runningProcesses = NSWorkspace.sharedWorkspace().runningApplications().valueForKey_(
'bundleIdentifier')
if NotificationCenterUIBundleID not in runningProcesses:
NSLog('[!] Unable to post a notification for the current user (%@), as it has no '
'running NotificationCenter instance.', NSUserName())
NSApp.terminate_(self)
self.notify('Updates available', '', 'Software updates are ready to install.',
'munki://updates')
def notify(self, title, subtitle, text, url):
'''Send our notification'''
nc = NSUserNotificationCenter.defaultUserNotificationCenter()
for userNotification in nc.deliveredNotifications():
# remove any previously posted update notifications
if userNotification.userInfo().get('type') == 'updates':
nc.removeDeliveredNotification_(userNotification)
notification = NSUserNotification.alloc().init()
notification.setTitle_(title)
notification.setSubtitle_(subtitle)
notification.setInformativeText_(text)
notification.setSoundName_('NSUserNotificationDefaultSoundName')
notification.setUserInfo_({'action': 'open_url', 'url': url, 'type': 'updates'})
notification.setHasActionButton_(True)
notification.setActionButtonTitle_('Details')
# private (undocumented) functionality
notification.setValue_forKey_(True, '_showsButtons')
nc.setDelegate_(self)
nc.scheduleNotification_(notification)
def userNotificationCenter_didActivateNotification_(self, center, notification):
'''User clicked on our notification'''
NSLog('Got userNotificationCenter:didActivateNotification:')
self.userActivatedNotification_(notification)
def userNotificationCenter_shouldPresentNotification_(self, center, notification):
'''Delegate method called when Notification Center has decided it doesn't
need to present the notification -- returning True overrides that decision'''
NSLog('Got userNotificationCenter:shouldPresentNotification:')
return True
def userNotificationCenter_didDeliverNotification_(self, center, notification):
'''Notification was delivered and we can exit'''
NSLog('Got userNotificationCenter:didDeliverNotification:')
NSApp.terminate_(self)
def userActivatedNotification_(self, notification):
'''React to user clicking on notification by launching MSC.app and showing Updates page'''
NSUserNotificationCenter.defaultUserNotificationCenter().removeDeliveredNotification_(
notification)
user_info = notification.userInfo()
if user_info.get('action') == 'open_url':
url = user_info.get('url')
NSWorkspace.sharedWorkspace(
).openURLs_withAppBundleIdentifier_options_additionalEventParamDescriptor_launchIdentifiers_(
[NSURL.URLWithString_(url)], MSCbundleIdentifier, 0, None, None)
def swizzle(*args):
"""
Decorator to override an ObjC selector's implementation with a
custom implementation ("method swizzling").
Use like this:
@swizzle(NSOriginalClass, 'selectorName')
def swizzled_selectorName(self, original):
--> `self` points to the instance
--> `original` is the original implementation
Originally from http://klep.name/programming/python/
(The link was dead on 2013-05-22 but the Google Cache version works:
http://goo.gl/ABGvJ)
"""
cls, SEL = args
def decorator(func):
old_IMP = cls.instanceMethodForSelector_(SEL)
def wrapper(self, *args, **kwargs):
return func(self, old_IMP, *args, **kwargs)
new_IMP = objc.selector(wrapper, selector=old_IMP.selector,
signature=old_IMP.signature)
objc.classAddMethod(cls, SEL, new_IMP)
return wrapper
return decorator
@swizzle(NSBundle, 'bundleIdentifier')
def swizzled_bundleIdentifier(self, original):
"""Swizzle [NSBundle bundleIdentifier] to make NSUserNotifications
work.
To post NSUserNotifications OS X requires the binary to be packaged
as an application bundle. To circumvent this restriction, we modify
`bundleIdentifier` to return a fake bundle identifier.
Original idea for this approach by Norio Numura:
https://github.com/norio-nomura/usernotification
"""
if self == NSBundle.mainBundle():
# return our fake bundle identifier
return MSCbundleIdentifier
else:
# call original function
return original(self)
@@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.googlecode.munki.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 The Munki Project. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
@@ -0,0 +1,29 @@
{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw9840\paperh8400
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
\f0\b\fs24 \cf0 Engineering:
\b0 \
Some people\
\
\b Human Interface Design:
\b0 \
Some other people\
\
\b Testing:
\b0 \
Hopefully not nobody\
\
\b Documentation:
\b0 \
Whoever\
\
\b With special thanks to:
\b0 \
Mom\
}
@@ -0,0 +1,504 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">13F1077</string>
<string key="IBDocument.InterfaceBuilderVersion">6751</string>
<string key="IBDocument.AppKitVersion">1265.21</string>
<string key="IBDocument.HIToolboxVersion">698.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">6751</string>
</object>
<array key="IBDocument.IntegratedClassDependencies">
<string>NSCustomObject</string>
<string>NSMenu</string>
<string>NSMenuItem</string>
</array>
<array key="IBDocument.PluginDependencies">
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</array>
<dictionary class="NSMutableDictionary" key="IBDocument.Metadata"/>
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
<object class="NSCustomObject" id="1021">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSCustomObject" id="1014">
<string key="NSClassName">FirstResponder</string>
</object>
<object class="NSCustomObject" id="1050">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSMenu" id="649796088">
<string key="NSTitle">AMainMenu</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="NSMenuItem" id="694149608">
<reference key="NSMenu" ref="649796088"/>
<string key="NSTitle">notifier</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<object class="NSCustomResource" key="NSOnImage" id="715147791">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSMenuCheckmark</string>
</object>
<object class="NSCustomResource" key="NSMixedImage" id="897496305">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSMenuMixedState</string>
</object>
<string key="NSAction">submenuAction:</string>
<reference key="NSTarget" ref="110575045"/>
<object class="NSMenu" key="NSSubmenu" id="110575045">
<string key="NSTitle">notifier</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="NSMenuItem" id="238522557">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">About notifier</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="304266470">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="1046388886">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Services</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
<string key="NSAction">submenuAction:</string>
<reference key="NSTarget" ref="752062318"/>
<object class="NSMenu" key="NSSubmenu" id="752062318">
<string key="NSTitle">Services</string>
<array class="NSMutableArray" key="NSMenuItems"/>
<string key="NSName">_NSServicesMenu</string>
</object>
</object>
<object class="NSMenuItem" id="646227648">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="755159360">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Hide notifier</string>
<string key="NSKeyEquiv">h</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="342932134">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Hide Others</string>
<string key="NSKeyEquiv">h</string>
<int key="NSKeyEquivModMask">1572864</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="908899353">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Show All</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="1056857174">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
<object class="NSMenuItem" id="632727374">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">Quit notifier</string>
<string key="NSKeyEquiv">q</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
</array>
<string key="NSName">_NSAppleMenu</string>
</object>
</object>
<object class="NSMenuItem" id="391199113">
<reference key="NSMenu" ref="649796088"/>
<string key="NSTitle">Help</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
<string key="NSAction">submenuAction:</string>
<reference key="NSTarget" ref="374024848"/>
<object class="NSMenu" key="NSSubmenu" id="374024848">
<string key="NSTitle">Help</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="NSMenuItem" id="238773614">
<reference key="NSMenu" ref="374024848"/>
<string key="NSTitle">notifier Help</string>
<string key="NSKeyEquiv">?</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="715147791"/>
<reference key="NSMixedImage" ref="897496305"/>
</object>
</array>
</object>
</object>
</array>
<string key="NSName">_NSMainMenu</string>
</object>
<object class="NSCustomObject" id="610635028">
<string key="NSClassName">AppDelegate</string>
</object>
<object class="NSCustomObject" id="15635064">
<string key="NSClassName">NSFontManager</string>
</object>
</array>
<object class="IBObjectContainer" key="IBDocument.Objects">
<array key="connectionRecords">
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="1050"/>
<reference key="destination" ref="610635028"/>
</object>
<int key="connectionID">374</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">orderFrontStandardAboutPanel:</string>
<reference key="source" ref="1021"/>
<reference key="destination" ref="238522557"/>
</object>
<int key="connectionID">142</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">showHelp:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="238773614"/>
</object>
<int key="connectionID">360</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">hide:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="755159360"/>
</object>
<int key="connectionID">367</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">hideOtherApplications:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="342932134"/>
</object>
<int key="connectionID">368</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">terminate:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="632727374"/>
</object>
<int key="connectionID">369</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">unhideAllApplications:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="908899353"/>
</object>
<int key="connectionID">370</int>
</object>
</array>
<object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects">
<object class="IBObjectRecord">
<int key="objectID">0</int>
<array key="object" id="0"/>
<reference key="children" ref="1048"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="1021"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="1014"/>
<reference key="parent" ref="0"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="1050"/>
<reference key="parent" ref="0"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">29</int>
<reference key="object" ref="649796088"/>
<array class="NSMutableArray" key="children">
<reference ref="694149608"/>
<reference ref="391199113"/>
</array>
<reference key="parent" ref="0"/>
<string key="objectName">MainMenu</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">56</int>
<reference key="object" ref="694149608"/>
<array class="NSMutableArray" key="children">
<reference ref="110575045"/>
</array>
<reference key="parent" ref="649796088"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">103</int>
<reference key="object" ref="391199113"/>
<array class="NSMutableArray" key="children">
<reference ref="374024848"/>
</array>
<reference key="parent" ref="649796088"/>
<string key="objectName">1</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">106</int>
<reference key="object" ref="374024848"/>
<array class="NSMutableArray" key="children">
<reference ref="238773614"/>
</array>
<reference key="parent" ref="391199113"/>
<string key="objectName">2</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">111</int>
<reference key="object" ref="238773614"/>
<reference key="parent" ref="374024848"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">57</int>
<reference key="object" ref="110575045"/>
<array class="NSMutableArray" key="children">
<reference ref="238522557"/>
<reference ref="755159360"/>
<reference ref="908899353"/>
<reference ref="632727374"/>
<reference ref="646227648"/>
<reference ref="304266470"/>
<reference ref="1046388886"/>
<reference ref="1056857174"/>
<reference ref="342932134"/>
</array>
<reference key="parent" ref="694149608"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">58</int>
<reference key="object" ref="238522557"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">134</int>
<reference key="object" ref="755159360"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">150</int>
<reference key="object" ref="908899353"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">136</int>
<reference key="object" ref="632727374"/>
<reference key="parent" ref="110575045"/>
<string key="objectName">1111</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">144</int>
<reference key="object" ref="646227648"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">236</int>
<reference key="object" ref="304266470"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">131</int>
<reference key="object" ref="1046388886"/>
<array class="NSMutableArray" key="children">
<reference ref="752062318"/>
</array>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">149</int>
<reference key="object" ref="1056857174"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">145</int>
<reference key="object" ref="342932134"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">130</int>
<reference key="object" ref="752062318"/>
<reference key="parent" ref="1046388886"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">373</int>
<reference key="object" ref="610635028"/>
<reference key="parent" ref="0"/>
<string key="objectName">AppDelegate</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">420</int>
<reference key="object" ref="15635064"/>
<reference key="parent" ref="0"/>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="103.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="106.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="111.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="130.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="131.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="134.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="144.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="145.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="149.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="150.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="236.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="373.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="420.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="58.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">448</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
<string key="className">AppDelegate</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../notifier/AppDelegate.py</string>
</object>
</object>
</array>
<array class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
<object class="IBPartialClassDescription">
<string key="className">NSApplication</string>
<string key="superclassName">NSResponder</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSFontManager</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSMenu</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSMenuItem</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSResponder</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSView</string>
<string key="superclassName">NSResponder</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBFrameworkSource</string>
<string key="minorKey">AppKit.framework/Headers/NSView.h</string>
</object>
</object>
</array>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<bool key="IBDocument.previouslyAttemptedUpgradeToXcode5">NO</bool>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
<integer value="1050" key="NS.object.0"/>
</object>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
<integer value="4600" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
<string key="NSMenuCheckmark">{11, 11}</string>
<string key="NSMenuMixedState">{10, 3}</string>
</dictionary>
</data>
</archive>
+41
View File
@@ -0,0 +1,41 @@
#import <Cocoa/Cocoa.h>
#import <Python.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *resourcePath = [mainBundle resourcePath];
NSArray *pythonPathArray = [NSArray arrayWithObjects: resourcePath, [resourcePath stringByAppendingPathComponent:@"PyObjC"], nil];
setenv("PYTHONPATH", [[pythonPathArray componentsJoinedByString:@":"] UTF8String], 1);
NSArray *possibleMainExtensions = [NSArray arrayWithObjects: @"py", @"pyc", @"pyo", nil];
NSString *mainFilePath = nil;
for (NSString *possibleMainExtension in possibleMainExtensions) {
mainFilePath = [mainBundle pathForResource: @"main" ofType: possibleMainExtension];
if ( mainFilePath != nil ) break;
}
if ( !mainFilePath ) {
[NSException raise: NSInternalInconsistencyException format: @"%s:%d main() Failed to find the Main.{py,pyc,pyo} file in the application wrapper's Resources directory.", __FILE__, __LINE__];
}
Py_SetProgramName("/usr/bin/python");
Py_Initialize();
PySys_SetArgv(argc, (char **)argv);
const char *mainFilePathPtr = [mainFilePath UTF8String];
FILE *mainFile = fopen(mainFilePathPtr, "r");
int result = PyRun_SimpleFile(mainFile, (char *)[[mainFilePath lastPathComponent] UTF8String]);
if ( result != 0 ) {
[NSException raise: NSInternalInconsistencyException
format: @"%s:%d main() PyRun_SimpleFile failed with file '%@'. See console for errors.", __FILE__, __LINE__, mainFilePath];
}
return result;
}
}
+21
View File
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
#
# main.py
# notifier
#
# Created by Greg Neagle on 4/11/15.
# Copyright (c) 2015 The Munki Project. All rights reserved.
#
# import modules required by application
import objc
import Foundation
import AppKit
from PyObjCTools import AppHelper
# import modules containing classes required to start application and load MainMenu.nib
import AppDelegate
# pass control to AppKit
AppHelper.runEventLoop()