def send_OS_X_notify(title, content, img_path): '''发送Mac桌面通知''' def swizzle(cls, SEL, 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) def swizzled_bundleIdentifier(self, original): # Use iTunes icon for notification return 'com.apple.itunes' swizzle(objc.lookUpClass('NSBundle'), b'bundleIdentifier', swizzled_bundleIdentifier) notification = NSUserNotification.alloc().init() notification.setInformativeText_('') notification.setTitle_(title.decode('utf-8')) notification.setSubtitle_(content.decode('utf-8')) notification.setInformativeText_('') notification.setUserInfo_({}) if img_path is not None: image = NSImage.alloc().initWithContentsOfFile_(img_path) # notification.setContentImage_(image) notification.set_identityImage_(image) notification.setDeliveryDate_( NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter().\ scheduleNotification_(notification)
def _pyobjc_notify(message, title=None, subtitle=None, appIcon=None, contentImage=None, open_URL=None, delay=0, sound=False): swizzle(objc.lookUpClass('NSBundle'), b'bundleIdentifier', swizzled_bundleIdentifier) notification = NSUserNotification.alloc().init() notification.setInformativeText_(message) if title: notification.setTitle_(title) if subtitle: notification.setSubtitle_(subtitle) if appIcon: url = NSURL.alloc().initWithString_(appIcon) image = NSImage.alloc().initWithContentsOfURL_(url) notification.set_identityImage_(image) if contentImage: url = NSURL.alloc().initWithString_(contentImage) image = NSImage.alloc().initWithContentsOfURL_(url) notification.setContentImage_(image) if sound: notification.setSoundName_( "NSUserNotificationDefaultSoundName") notification.setDeliveryDate_( NSDate.dateWithTimeInterval_sinceDate_(delay, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_( notification)
def notification(title, subtitle, message, data=None, sound=True, image=None): """Send a notification to Notification Center (Mac OS X 10.8+). If running on a version of Mac OS X that does not support notifications, a ``RuntimeError`` will be raised. Apple says, "The userInfo content must be of reasonable serialized size (less than 1k) or an exception will be thrown." So don't do that! :param title: text in a larger font. :param subtitle: text in a smaller font below the `title`. :param message: text representing the body of the notification below the `subtitle`. :param data: will be passed to the application's "notification center" (see :func:`rumps.notifications`) when this notification is clicked. :param sound: whether the notification should make a noise when it arrives. """ if not _NOTIFICATIONS: raise RuntimeError('Mac OS X 10.8+ is required to send notifications') if data is not None and not isinstance(data, Mapping): raise TypeError('notification data must be a mapping') _require_string_or_none(title, subtitle, message) notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(message) notification.setUserInfo_({} if data is None else data) if sound: notification.setSoundName_("NSUserNotificationDefaultSoundName") if image != None: notification.setContentImage_(image) notification.setDeliveryDate_(NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}): """ Python method to show a desktop notification on Mountain Lion. Where: title: Title of notification subtitle: Subtitle of notification info_text: Informative text of notification delay: Delay (in seconds) before showing the notification sound: Play the default notification sound userInfo: a dictionary that can be used to handle clicks in your app's applicationDidFinishLaunching:aNotification method """ from Foundation import NSDate from objc import lookUpClass NSUserNotification = lookUpClass('NSUserNotification') NSUserNotificationCenter = lookUpClass('NSUserNotificationCenter') notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(info_text) notification.setUserInfo_(userInfo) if sound: notification.setSoundName_("NSUserNotificationDefaultSoundName") notification.setDeliveryDate_(NSDate.dateWithTimeInterval_sinceDate_(delay, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
def format_time(timestamp=None): """Return timestamp as an ISO 8601 formatted string, in the current timezone. If timestamp isn't given the current time is used.""" if timestamp is None: return str(NSDate.new()) return str(NSDate.dateWithTimeIntervalSince1970_(timestamp))
def notification(title, subtitle, message, data=None, sound=True): """Send a notification to Notification Center (OS X 10.8+). If running on a version of macOS that does not support notifications, a ``RuntimeError`` will be raised. Apple says, "The userInfo content must be of reasonable serialized size (less than 1k) or an exception will be thrown." So don't do that! :param title: text in a larger font. :param subtitle: text in a smaller font below the `title`. :param message: text representing the body of the notification below the `subtitle`. :param data: will be passed to the application's "notification center" (see :func:`rumps.notifications`) when this notification is clicked. :param sound: whether the notification should make a noise when it arrives. """ if not _NOTIFICATIONS: raise RuntimeError('OS X 10.8+ is required to send notifications') if data is not None and not isinstance(data, Mapping): raise TypeError('notification data must be a mapping') _require_string_or_none(title, subtitle, message) notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(message) notification.setUserInfo_({} if data is None else data) if sound: notification.setSoundName_("NSUserNotificationDefaultSoundName") notification.setDeliveryDate_( NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date())) notification_center = _default_user_notification_center() notification_center.scheduleNotification_(notification)
def appleSoftwareUpdatesAvailable(forcecheck=False, suppresscheck=False): '''Checks for available Apple Software Updates, trying not to hit the SUS more than needed''' if suppresscheck: # typically because we're doing a logout install; if # there are no waiting Apple Updates we shouldn't # trigger a check for them. pass elif forcecheck: # typically because user initiated the check from # Managed Software Update.app unused_retcode = checkForSoftwareUpdates(forcecheck=True) else: # have we checked recently? Don't want to check with # Apple Software Update server too frequently now = NSDate.new() nextSUcheck = now lastSUcheckString = munkicommon.pref('LastAppleSoftwareUpdateCheck') if lastSUcheckString: try: lastSUcheck = NSDate.dateWithString_(lastSUcheckString) interval = 24 * 60 * 60 nextSUcheck = lastSUcheck.dateByAddingTimeInterval_(interval) except (ValueError, TypeError): pass if now.timeIntervalSinceDate_(nextSUcheck) >= 0: unused_retcode = checkForSoftwareUpdates(forcecheck=True) else: unused_retcode = checkForSoftwareUpdates(forcecheck=False) if writeAppleUpdatesFile(): displayAppleUpdateInfo() return True else: return False
def send_OS_X_notify(title, content, img_path): '''发送Mac桌面通知''' def swizzle(cls, SEL, 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) def swizzled_bundleIdentifier(self, original): # Use iTunes icon for notification return 'com.apple.itunes' swizzle(objc.lookUpClass('NSBundle'), b'bundleIdentifier', swizzled_bundleIdentifier) notification = NSUserNotification.alloc().init() notification.setInformativeText_('') notification.setTitle_(title.decode('utf-8')) notification.setSubtitle_(content.decode('utf-8')) notification.setInformativeText_('') notification.setUserInfo_({}) if img_path is not None: image = NSImage.alloc().initWithContentsOfFile_(img_path) # notification.setContentImage_(image) notification.set_identityImage_(image) notification.setDeliveryDate_( NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date()) ) NSUserNotificationCenter.defaultUserNotificationCenter().\ scheduleNotification_(notification)
def _pyobjc_notify(message, title=None, subtitle=None, appIcon=None, contentImage=None, open_URL=None, delay=0, sound=False): swizzle(objc.lookUpClass('NSBundle'), b'bundleIdentifier', swizzled_bundleIdentifier) notification = NSUserNotification.alloc().init() notification.setInformativeText_(message) if title: notification.setTitle_(title) if subtitle: notification.setSubtitle_(subtitle) if appIcon: url = NSURL.alloc().initWithString_(appIcon) image = NSImage.alloc().initWithContentsOfURL_(url) notification.set_identityImage_(image) if contentImage: url = NSURL.alloc().initWithString_(contentImage) image = NSImage.alloc().initWithContentsOfURL_(url) notification.setContentImage_(image) if sound: notification.setSoundName_( "NSUserNotificationDefaultSoundName") notification.setDeliveryDate_( NSDate.dateWithTimeInterval_sinceDate_( delay, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter( ).scheduleNotification_(notification)
def software_updates_available( self, force_check=False, suppress_check=False): """Checks for available Apple Software Updates, trying not to hit the SUS more than needed. Args: force_check: Boolean. If True, forces a softwareupdate run. suppress_check: Boolean. If True, skips a softwareupdate run. Returns: Integer. Count of available Apple updates. """ success = True if suppress_check: # don't check at all -- # typically because we are doing a logout install # just return any AppleUpdates info we already have if not os.path.exists(self.apple_updates_plist): return 0 try: plist = FoundationPlist.readPlist(self.apple_updates_plist) except FoundationPlist.FoundationPlistException: plist = {} return len(plist.get('AppleUpdates', [])) if force_check: # typically because user initiated the check from # Managed Software Update.app success = self.check_for_software_updates(force_check=True) else: # have we checked recently? Don't want to check with # Apple Software Update server too frequently now = NSDate.new() next_su_check = now last_su_check_string = prefs.pref( 'LastAppleSoftwareUpdateCheck') if last_su_check_string: try: last_su_check = NSDate.dateWithString_( last_su_check_string) # dateWithString_ returns None if invalid date string. if not last_su_check: raise ValueError interval = 24 * 60 * 60 # only force check every 24 hours. next_su_check = last_su_check.dateByAddingTimeInterval_( interval) except (ValueError, TypeError): pass if now.timeIntervalSinceDate_(next_su_check) >= 0: success = self.check_for_software_updates(force_check=True) else: success = self.check_for_software_updates(force_check=False) display.display_debug1( 'CheckForSoftwareUpdates result: %s' % success) if success: count = self.write_appleupdates_file() else: self.clear_apple_update_info() return 0 return count
def format_time(timestamp=None): """Return timestamp as an ISO 8601 formatted string, in the current timezone. If timestamp isn't given the current time is used.""" if timestamp is None: return str(NSDate.new()) else: return str(NSDate.dateWithTimeIntervalSince1970_(timestamp))
def software_updates_available(self, force_check=False, suppress_check=False): """Checks for available Apple Software Updates, trying not to hit the SUS more than needed. Args: force_check: Boolean. If True, forces a softwareupdate run. suppress_check: Boolean. If True, skips a softwareupdate run. Returns: Integer. Count of available Apple updates. """ if suppress_check: # don't check at all -- # typically because we are doing a logout install # just return any AppleUpdates info we already have return self.cached_update_count() if force_check: # typically because user initiated the check from # Managed Software Update.app updatecount = self.check_for_software_updates(force_check=True) else: # have we checked recently? Don't want to check with # Apple Software Update server too frequently now = NSDate.new() next_su_check = now last_su_check_string = prefs.pref('LastAppleSoftwareUpdateCheck') if last_su_check_string: try: last_su_check = NSDate.dateWithString_( last_su_check_string) # dateWithString_ returns None if invalid date string. if not last_su_check: raise ValueError interval = 24 * 60 * 60 # only force check every 24 hours. next_su_check = last_su_check.dateByAddingTimeInterval_( interval) except (ValueError, TypeError): pass if now.timeIntervalSinceDate_(next_su_check) >= 0: updatecount = self.check_for_software_updates(force_check=True) else: updatecount = self.check_for_software_updates( force_check=False) display.display_debug1('CheckForSoftwareUpdates result: %s' % updatecount) if updatecount == -1: # some (transient?) communications error with the su server; return # cached AppleInfo return self.cached_update_count() elif updatecount == 0: self.clear_apple_update_info() else: _ = self.write_appleupdates_file() return updatecount
def softwareupdated_installhistory(start_date=None, end_date=None): '''Returns softwareupdated items from InstallHistory.plist that are within the given date range. (dates must be NSDates)''' start_date = start_date or NSDate.distantPast() end_date = end_date or NSDate.distantFuture() try: installhistory = FoundationPlist.readPlist(INSTALLHISTORY_PLIST) except FoundationPlist.FoundationPlistException: return [] return [item for item in installhistory if item.get('processName') == 'softwareupdated' and item['date'] >= start_date and item['date'] <= end_date]
def notify(title, subtitle, msg_text, sound=False): # Function to generate OS X notification. NSUserNotification = lookUpClass("NSUserNotification") NSUserNotificationCenter = lookUpClass("NSUserNotificationCenter") notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(msg_text) if sound: notification.setSoundName_("NSUserNotificationDefaultSoundName") notification.setDeliveryDate_(NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
def thereAreUpdatesToBeForcedSoon(hours=72): '''Return True if any updates need to be installed within the next X hours, false otherwise''' installinfo = getInstallInfo() if installinfo: now = NSDate.date() now_xhours = NSDate.dateWithTimeIntervalSinceNow_(hours * 3600) for item in installinfo.get('managed_installs', []): force_install_after_date = item.get('force_install_after_date') if force_install_after_date: force_install_after_date = discardTimeZoneFromDate( force_install_after_date) if now_xhours >= force_install_after_date: return True return False
def notify(title, subtitle, text, bundleid=None, url=None): if bundleid: # fake our bundleid set_fake_bundleid(bundleid) # create a new user notification notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(text) if url: userInfo = NSDictionary.dictionaryWithDictionary_({ 'action': u'open_url', 'value': unicode(url) }) notification.setUserInfo_(userInfo) notification.setHasActionButton_(True) notification.setActionButtonTitle_('Details') # get the default User Notification Center nc = NSUserNotificationCenter.defaultUserNotificationCenter() # create a delegate object that implements our delegate methods my_delegate = NotificationCenterDelegate.alloc().init() nc.setDelegate_(my_delegate) nc.removeAllDeliveredNotifications() # deliver the notification nc.deliverNotification_(notification) # keep running until the notification is activated while (my_delegate.keepRunning): NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(0.1))
def runConsoleEventLoop(argv=None, installInterrupt=False, mode=NSDefaultRunLoopMode, maxTimeout=3.0): if argv is None: argv = sys.argv if installInterrupt: installMachInterrupt() runLoop = NSRunLoop.currentRunLoop() stopper = PyObjCAppHelperRunLoopStopper.alloc().init() PyObjCAppHelperRunLoopStopper.addRunLoopStopper_toRunLoop_( stopper, runLoop) try: while stopper.shouldRun(): nextfire = runLoop.limitDateForMode_(mode) if not stopper.shouldRun(): break soon = NSDate.dateWithTimeIntervalSinceNow_(maxTimeout) if nextfire is not None: nextfire = soon.earlierDate_(nextfire) if not runLoop.runMode_beforeDate_(mode, nextfire): stopper.stop() finally: PyObjCAppHelperRunLoopStopper.removeRunLoopStopperFromRunLoop_(runLoop)
def gotIsComposing(self, window, state, refresh, last_active): self.enableIsComposing = True flag = state == "active" if flag: if refresh is None: refresh = 120 if last_active is not None and ( last_active - ISOTimestamp.now() > datetime.timedelta(seconds=refresh)): # message is old, discard it return if self.remoteTypingTimer: # if we don't get any indications in the request refresh, then we assume remote to be idle self.remoteTypingTimer.setFireDate_( NSDate.dateWithTimeIntervalSinceNow_(refresh)) else: self.remoteTypingTimer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_( refresh, self, "remoteBecameIdle:", window, False) else: if self.remoteTypingTimer: self.remoteTypingTimer.invalidate() self.remoteTypingTimer = None window.noteView_isComposing_(self, flag)
def run(config): """ starts self-control with custom parameters, depending on the weekday and the config """ check_if_running(config["username"]) try: schedule = next(s for s in config["block-schedules"] if is_schedule_active(s)) except StopIteration: syslog.syslog(syslog.LOG_ALERT, "No schedule is active at the moment. Shutting down.") exit(0) duration = get_duration_minutes(schedule["end-hour"], schedule["end-minute"]) set_selfcontrol_setting("BlockDuration", duration, config["username"]) set_selfcontrol_setting("BlockAsWhitelist", 1 if schedule.get("block-as-whitelist", False) else 0, config["username"]) if schedule.get("host-blacklist", None) is not None: set_selfcontrol_setting("HostBlacklist", schedule["host-blacklist"], config["username"]) elif config.get("host-blacklist", None) is not None: set_selfcontrol_setting("HostBlacklist", config["host-blacklist"], config["username"]) # In legacy mode manually set the BlockStartedDate, this should not be required anymore in future versions # of SelfControl. if config.get("legacy-mode", True): set_selfcontrol_setting("BlockStartedDate", NSDate.date(), config["username"]) # Start SelfControl subprocess.call(["{path}/Contents/MacOS/org.eyebeam.SelfControl".format(path=config["selfcontrol-path"]), str(getpwnam(config["username"]).pw_uid), "--install"]) syslog.syslog(syslog.LOG_ALERT, "SelfControl started for {min} minute(s).".format(min=duration))
def get_apps(): # credit to the Munki project for borrowing code, thanks Munki! apps_dict = {} query = NSMetadataQuery.alloc().init() query.setPredicate_( NSPredicate.predicateWithFormat_( "(kMDItemContentType = 'com.apple.application-bundle')")) query.setSearchScopes_(['/Applications']) query.startQuery() start_time = 0 max_time = 20 while query.isGathering() and start_time <= max_time: start_time += 0.3 NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(0.3)) query.stopQuery() # check if the app returns a None value for this query, some apps may have embedded Applescripts # that will return a None value and will be set to blank for app in query.results(): name = app.valueForAttribute_('kMDItemDisplayName') if name: version = app.valueForAttribute_('kMDItemVersion') or '' apps_dict[name] = version return apps_dict
def predicate_info_object(): '''Returns our info object used for predicate comparisons''' info_object = {} machine = getMachineFacts() info_object.update(machine) info_object.update(get_conditions()) # use our start time for "current" date (if we have it) # and add the timezone offset to it so we can compare # UTC dates as though they were local dates. info_object['date'] = add_tzoffset_to_date( NSDate.dateWithString_( reports.report.get('StartTime', reports.format_time()))) # split os version into components for easier predicate comparison os_vers = machine['os_vers'] os_vers = os_vers + '.0.0' info_object['os_vers_major'] = int(os_vers.split('.')[0]) info_object['os_vers_minor'] = int(os_vers.split('.')[1]) info_object['os_vers_patch'] = int(os_vers.split('.')[2]) # get last build number component for easier predicate comparison build = machine['os_build_number'] info_object['os_build_last_component'] = pkgutils.MunkiLooseVersion( build).version[-1] if 'Book' in machine.get('machine_model', ''): info_object['machine_type'] = 'laptop' else: info_object['machine_type'] = 'desktop' return info_object
def _nestedRunLoopReaderUntilEOLchars_(self, eolchars): """ This makes the baby jesus cry. I want co-routines. """ app = NSApplication.sharedApplication() window = self.textView.window() self.setCharacterIndexForInput_(self.lengthOfTextView()) # change the color.. eh self.textView.setTypingAttributes_( {NSFontAttributeName: self.font(), NSForegroundColorAttributeName: self.codeColor()} ) while True: event = app.nextEventMatchingMask_untilDate_inMode_dequeue_( NSUIntegerMax, NSDate.distantFuture(), NSDefaultRunLoopMode, True ) if (event.type() == NSKeyDown) and (event.window() == window): eol = event.characters() if eol in eolchars: break app.sendEvent_(event) cl = self.currentLine() if eol == "\r": self.writeCode_("\n") return cl + eol
def notification(title, subtitle, message, data=None, sound=True): """ Notification sender. Apple says, "The userInfo content must be of reasonable serialized size (less than 1k) or an exception will be thrown." So don't do that! """ if data is not None and not isinstance(data, Mapping): raise TypeError('notification data must be a mapping') notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(message) notification.setUserInfo_({} if data is None else data) if sound: notification.setSoundName_("NSUserNotificationDefaultSoundName") notification.setDeliveryDate_(NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date())) NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
def rightMouseDown_(self, event): point = self.window().convertScreenToBase_(NSEvent.mouseLocation()) event = NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_( NSRightMouseUp, point, 0, NSDate.timeIntervalSinceReferenceDate(), self.window().windowNumber(), self.window().graphicsContext(), 0, 1, 0) videoDevicesMenu = NSMenu.alloc().init() lastItem = videoDevicesMenu.addItemWithTitle_action_keyEquivalent_(NSLocalizedString("Select Video Camera", "Menu item"), "", "") lastItem.setEnabled_(False) videoDevicesMenu.addItem_(NSMenuItem.separatorItem()) i = 0 for item in Engine().video_devices: if item not in (None, 'system_default'): i += 1 lastItem = videoDevicesMenu.addItemWithTitle_action_keyEquivalent_(item, "changeVideoDevice:", "") lastItem.setRepresentedObject_(item) if SIPApplication.video_device.real_name == item: lastItem.setState_(NSOnState) if i > 1: videoDevicesMenu.addItem_(NSMenuItem.separatorItem()) settings = SIPSimpleSettings() lastItem = videoDevicesMenu.addItemWithTitle_action_keyEquivalent_(NSLocalizedString("Auto Rotate Cameras", "Menu item"), "toggleAutoRotate:", "") lastItem.setState_(NSOnState if settings.video.auto_rotate_cameras else NSOffState) NSMenu.popUpContextMenu_withEvent_forView_(videoDevicesMenu, event, self.window().contentView())
def addPayloadFromPlistContents(self, plist_dict, domain, manage, is_byhost=False): """Add one plist dict contents to the profile's payloads. domain is the preferences domain (ie. com.apple.finder), manage is one of 'Once', 'Often' or 'Always', and is_byhost is a boolean representing whether the preference is to be used as a ByHost. """ payload_dict = {} # Frequency to apply settings, or 'state' if manage == 'Always': state = 'Forced' else: state = 'Set-Once' if is_byhost: domain += '.ByHost' # Yet another nested dict for the actual contents payload_dict[domain] = {} payload_dict[domain][state] = [] payload_dict[domain][state].append({}) payload_dict[domain][state][0]['mcx_preference_settings'] = plist_dict # Add a datestamp if we're managing 'Once' if manage == 'Once': now = NSDate.new() payload_dict[domain][state][0]['mcx_data_timestamp'] = now self._addPayload(payload_dict)
def get_apps(tag, removal): """use spotlight to find apps by custom tag""" # main dictionary removals = {} # set NSMetaDatQuery predicate by your custom tag with value of true predicate = "%s = 'true'" % tag # build and execute the spotlight query query = NSMetadataQuery.alloc().init() query.setPredicate_(NSPredicate.predicateWithFormat_(predicate)) query.setSearchScopes_(['/Applications']) query.startQuery() start_time = 0 max_time = 20 while query.isGathering() and start_time <= max_time: start_time += 0.3 NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(0.3)) query.stopQuery() # iterate through the results to grab spotlight attributes for item in query.results(): app = item.valueForAttribute_('kMDItemFSName') path = item.valueForAttribute_('kMDItemPath') customtag = item.valueForAttribute_(removal) if customtag: # build nested dictionary of tagged apps and attribute values removals[app] = {} removals[app]['path'] = path removals[app]['method'] = customtag return removals
def find_apps_in_dirs(dirlist): """Do spotlight search for type applications within the list of directories provided. Returns a list of paths to applications these appear to always be some form of unicode string. """ applist = [] query = NSMetadataQuery.alloc().init() query.setPredicate_( NSPredicate.predicateWithFormat_('(kMDItemKind = "Application")')) query.setSearchScopes_(dirlist) query.startQuery() # Spotlight isGathering phase - this is the initial search. After the # isGathering phase Spotlight keeps running returning live results from # filesystem changes, we are not interested in that phase. # Run for 0.3 seconds then check if isGathering has completed. runtime = 0 maxruntime = 20 while query.isGathering() and runtime <= maxruntime: runtime += 0.3 NSRunLoop.currentRunLoop( ).runUntilDate_(NSDate.dateWithTimeIntervalSinceNow_(0.3)) query.stopQuery() if runtime >= maxruntime: display.display_warning( 'Spotlight search for applications terminated due to excessive ' 'time. Possible causes: Spotlight indexing is turned off for a ' 'volume; Spotlight is reindexing a volume.') for item in query.results(): pathname = item.valueForAttribute_('kMDItemPath') if pathname and not is_excluded_filesystem(pathname): applist.append(pathname) return applist
async def _handle_nsrunloop(self): while not self.ns_run_loop_done: time_interval = NSDate.alloc().initWithTimeIntervalSinceNow_( self.ns_run_loop_interval) self.nsrunloop.runMode_beforeDate_(NSDefaultRunLoopMode, time_interval) await asyncio.sleep(0)
def find_apps_in_dirs(dirlist): """Do spotlight search for type applications within the list of directories provided. Returns a list of paths to applications these appear to always be some form of unicode string. """ applist = [] query = NSMetadataQuery.alloc().init() query.setPredicate_( NSPredicate.predicateWithFormat_('(kMDItemKind = "Application")')) query.setSearchScopes_(dirlist) query.startQuery() # Spotlight isGathering phase - this is the initial search. After the # isGathering phase Spotlight keeps running returning live results from # filesystem changes, we are not interested in that phase. # Run for 0.3 seconds then check if isGathering has completed. runtime = 0 maxruntime = 20 while query.isGathering() and runtime <= maxruntime: runtime += 0.3 NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(0.3)) query.stopQuery() if runtime >= maxruntime: display.display_warning( 'Spotlight search for applications terminated due to excessive ' 'time. Possible causes: Spotlight indexing is turned off for a ' 'volume; Spotlight is reindexing a volume.') for item in query.results(): pathname = item.valueForAttribute_('kMDItemPath') if pathname and not is_excluded_filesystem(pathname): applist.append(pathname) return applist
def _create_date(self, form_item, val, form_view): gregorian = NSCalendar.alloc().initWithCalendarIdentifier_(NSGregorianCalendar) control_label = NSTextField.createLabelWithText_font_(form_item.label, self._system_font) control = NSDatePicker.alloc().initWithFrame_(NSZeroRect) control.setCalendar_(gregorian) control.setDatePickerElements_(NSYearMonthDatePickerElementFlag) control.setDrawsBackground_(YES) control.setDateValue_(NSDate.date()) control.setMinDate_(NSDate.date()) control.setMaxDate_(NSDate.dateWithString_('2029-12-31 23:59:59 +0600')) control.sizeToFit() control.setAction_(self.datePickerAction_) self._form_y_offset -= NSHeight(control.frame()) control.setFrameOrigin_(NSPoint(self._center_point, self._form_y_offset)) control_label.placeRelativeToControl_(control) return (control, control_label)
def run(config): """ starts self-control with custom parameters, depending on the weekday and the config """ if check_if_running(config["username"]): syslog.syslog(syslog.LOG_ALERT, "SelfControl is already running, ignore current execution of Auto-SelfControl.") exit(2) try: schedule = next(s for s in config["block-schedules"] if is_schedule_active(s)) except StopIteration: syslog.syslog(syslog.LOG_ALERT, "No schedule is active at the moment. Shutting down.") exit(0) duration = get_duration_minutes(schedule["end-hour"], schedule["end-minute"]) set_selfcontrol_setting("BlockDuration", duration, config["username"]) set_selfcontrol_setting("BlockAsWhitelist", 1 if schedule.get("block-as-whitelist", False) else 0, config["username"]) if schedule.get("host-blacklist", None) is not None: set_selfcontrol_setting("HostBlacklist", schedule["host-blacklist"], config["username"]) elif config.get("host-blacklist", None) is not None: set_selfcontrol_setting("HostBlacklist", config["host-blacklist"], config["username"]) # In legacy mode manually set the BlockStartedDate, this should not be required anymore in future versions # of SelfControl. if config.get("legacy-mode", True): set_selfcontrol_setting("BlockStartedDate", NSDate.date(), config["username"]) # Start SelfControl subprocess.check_output(["{path}/Contents/MacOS/org.eyebeam.SelfControl".format(path=config["selfcontrol-path"]), str(getpwnam(config["username"]).pw_uid), "--install"]) syslog.syslog(syslog.LOG_ALERT, "SelfControl started for {min} minute(s).".format(min=duration))
def notify(title, subtitle, text, bundleid=None): if bundleid: # fake our bundleid set_fake_bundleid(bundleid) # create a new user notification notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(subtitle) notification.setInformativeText_(text) # get the default User Notification Center nc = NSUserNotificationCenter.defaultUserNotificationCenter() # create a delegate object that implements our delegate methods my_delegate = NotificationCenterDelegate.alloc().init() nc.setDelegate_(my_delegate) # deliver the notification nc.deliverNotification_(notification) # keep running until the notification is activated while (my_delegate.keepRunning): NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(0.1))
def findDomains(serviceName, seconds=5.0): runloop = NSRunLoop.currentRunLoop() browser = NSNetServiceBrowser.new() pbd = PrintingBrowserDelegate.new() browser.setDelegate_(pbd) browser.searchForServicesOfType_inDomain_(serviceName, "") untilWhen = NSDate.dateWithTimeIntervalSinceNow_(seconds) runloop.runUntilDate_(untilWhen)
def start(self): if not self._status: self._nsdate = NSDate.date() self._nstimer = NSTimer.alloc().initWithFireDate_interval_target_selector_userInfo_repeats_( self._nsdate, self._interval, self, 'callback:', None, True) NSRunLoop.currentRunLoop().addTimer_forMode_(self._nstimer, NSDefaultRunLoopMode) _TIMERS.add(self) self._status = True
def send_OS_X_notify(title, content, img_path): '''发送Mac桌面通知''' try: from Foundation import ( NSDate, NSUserNotification, NSUserNotificationCenter) from AppKit import NSImage import objc except ImportError: logger.info('failed to init OSX notify!') return def swizzle(cls, SEL, func): old_IMP = getattr(cls, SEL, None) if old_IMP is None: 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.encode(), new_IMP) def swizzled_bundleIdentifier(self, original): # Use iTunes icon for notification return 'com.apple.itunes' swizzle(objc.lookUpClass('NSBundle'), 'bundleIdentifier', swizzled_bundleIdentifier) notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setSubtitle_(content) notification.setInformativeText_('') notification.setUserInfo_({}) if img_path is not None: image = NSImage.alloc().initWithContentsOfFile_(img_path) # notification.setContentImage_(image) notification.set_identityImage_(image) notification.setDeliveryDate_( NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date()) ) NSUserNotificationCenter.defaultUserNotificationCenter().\ scheduleNotification_(notification) logger.info('send notify success!')
def __init__(self, callback, interval): self.set_callback(callback) self._nsdate = NSDate.date() self._nstimer = NSTimer.alloc( ).initWithFireDate_interval_target_selector_userInfo_repeats_( self._nsdate, interval, self, 'callback:', None, True) NSRunLoop.currentRunLoop().addTimer_forMode_(self._nstimer, NSDefaultRunLoopMode)
def waituntil(conditionfunc, timeout=None): """ Waits until conditionfunc() returns true, or <timeout> seconds have passed. (If timeout=None, this waits indefinitely until conditionfunc() returns true.) Returns false if the process timed out, otherwise returns true. Note!! You must call interruptwait() when you know that conditionfunc() should be checked (e.g. if you are waiting for data and you know some data has arrived) so that this can check conditionfunc(); otherwise it will just continue to wait. (This allows the function to wait for an event that is sent by interruptwait() instead of polling conditionfunc().) This allows the caller to wait while the main event loop processes its events. This must be done for certain situations, e.g. to receive socket data or to accept client connections on a server socket, since IOBluetooth requires the presence of an event loop to run these operations. This function doesn't need to be called if there is something else that is already processing the main event loop, e.g. if called from within a Cocoa application. """ app = NSApplication.sharedApplication() starttime = time.time() if timeout is None: timeout = NSDate.distantFuture().timeIntervalSinceNow() if not isinstance(timeout, (int, float)): raise TypeError("timeout must be int or float, was %s" % \ type(timeout)) endtime = starttime + timeout while True: currtime = time.time() if currtime >= endtime: return False # use WAIT_MAX_TIMEOUT, don't wait forever in case of KeyboardInterrupt e = app.nextEventMatchingMask_untilDate_inMode_dequeue_( NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_( min(endtime - currtime, WAIT_MAX_TIMEOUT)), NSDefaultRunLoopMode, True) if e is not None: if (e.type() == NSApplicationDefined and e.subtype() == LIGHTBLUE_NOTIFY_ID): if conditionfunc(): return True else: app.postEvent_atStart_(e, True)
def alert(self, title, subtitle, message, delay=0, sound=False, userInfo={}): self.notification.setTitle_(title) self.notification.setSubtitle_(subtitle) self.notification.setInformativeText_(message) self.notification.setDeliveryDate_(NSDate.dateWithTimeInterval_sinceDate_(delay, NSDate.date())) # self.notification.setUserInfo_(userInfo) if sound: self.notification.setSoundName_("NSUserNotificationDefaultSoundName") NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(self.notification)
def isDone(self): '''Check if the connection request is complete. As a side effect, allow the delegates to work by letting the run loop run for a bit''' if self.done: return self.done # let the delegates do their thing NSRunLoop.currentRunLoop().runUntilDate_( NSDate.dateWithTimeIntervalSinceNow_(.1)) return self.done
def looponce(): app = NSApplication.sharedApplication() # to push the run loops I seem to have to do this twice # use NSEventTrackingRunLoopMode or NSDefaultRunLoopMode? for i in range(2): event = app.nextEventMatchingMask_untilDate_inMode_dequeue_( NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_(0.02), NSDefaultRunLoopMode, False)
def make_pkginfo_metadata(): '''Records information about the environment in which the pkginfo was created so we have a bit of an audit trail. Returns a dictionary.''' metadata = {} metadata['created_by'] = NSUserName() metadata['creation_date'] = NSDate.new() metadata['munki_version'] = info.get_version() metadata['os_version'] = osutils.getOsVersion(only_major_minor=False) return metadata
def GET(url): """Return the contents of a url (from cache if possible)""" opener = urllib2.build_opener(CacheHandler("/tmp/plod")) response = opener.open(url) last_mod = _date_parser.dateFromString_(response.headers.get('Last-Modified')) if not last_mod: last_mod = NSDate.date() return response, last_mod.timeIntervalSince1970()
def increment(self, value=1): """ Increment the progress bar by **value**. *Only available in determinate progress bars.* """ self._nsObject.incrementBy_(value) self._nsObject.display() if osVersionCurrent >= osVersion10_11: NSRunLoop.mainRunLoop().runUntilDate_(NSDate.dateWithTimeIntervalSinceNow_(0.0001))
def set(self, value): """ Set the value of the progress bar to **value**. *Only available in determinate progress bars.* """ self._nsObject.setDoubleValue_(value) self._nsObject.display() if osVersionCurrent >= osVersion10_11: NSRunLoop.mainRunLoop().runUntilDate_(NSDate.dateWithTimeIntervalSinceNow_(0.0001))
def waituntil(conditionfunc, timeout=None): """ Waits until conditionfunc() returns true, or <timeout> seconds have passed. (If timeout=None, this waits indefinitely until conditionfunc() returns true.) Returns false if the process timed out, otherwise returns true. Note!! You must call interruptwait() when you know that conditionfunc() should be checked (e.g. if you are waiting for data and you know some data has arrived) so that this can check conditionfunc(); otherwise it will just continue to wait. (This allows the function to wait for an event that is sent by interruptwait() instead of polling conditionfunc().) This allows the caller to wait while the main event loop processes its events. This must be done for certain situations, e.g. to receive socket data or to accept client connections on a server socket, since IOBluetooth requires the presence of an event loop to run these operations. This function doesn't need to be called if there is something else that is already processing the main event loop, e.g. if called from within a Cocoa application. """ app = NSApplication.sharedApplication() starttime = time.time() if timeout is None: timeout = NSDate.distantFuture().timeIntervalSinceNow() if not isinstance(timeout, (int, float)): raise TypeError("timeout must be int or float, was %s" % \ type(timeout)) endtime = starttime + timeout while True: currtime = time.time() if currtime >= endtime: return False # use WAIT_MAX_TIMEOUT, don't wait forever in case of KeyboardInterrupt e = app.nextEventMatchingMask_untilDate_inMode_dequeue_(NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_(min(endtime - currtime, WAIT_MAX_TIMEOUT)), NSDefaultRunLoopMode, True) if e is not None: if (e.type() == NSApplicationDefined and e.subtype() == LIGHTBLUE_NOTIFY_ID): if conditionfunc(): return True else: app.postEvent_atStart_(e, True)
def check_for_software_updates(self, force_check=True): """Check if Apple Software Updates are available, if needed or forced. Args: force_check: Boolean. If True, forces a check, otherwise only checks if the last check is deemed outdated. Returns: Boolean. True if there are updates, False otherwise. """ before_hash = munkihash.getsha256hash( self.applesync.apple_download_catalog_path) msg = 'Checking Apple Software Update catalog...' display.display_status_major(msg) try: self.applesync.cache_apple_catalog() except sync.CatalogNotFoundError: return False except (sync.ReplicationError, fetch.Error) as err: display.display_warning( 'Could not download Apple SUS catalog:') display.display_warning('\t%s', unicode(err)) return False if not force_check and not self._force_check_necessary(before_hash): display.display_info( 'Skipping Apple Software Update check ' 'because sucatalog is unchanged, installed Apple packages are ' 'unchanged and we recently did a full check.') # return True if we have cached updates; False otherwise return bool(self.software_update_info()) if self.download_available_updates(): # Success; ready to install. prefs.set_pref('LastAppleSoftwareUpdateCheck', NSDate.date()) product_ids = self.available_update_product_ids() if not product_ids: # No updates found self.applesync.clean_up_cache() return False try: self.applesync.cache_update_metadata(product_ids) except sync.ReplicationError as err: display.display_warning( 'Could not replicate software update metadata:') display.display_warning('\t%s', unicode(err)) return False return True else: # Download error, allow check again soon. display.display_error( 'Could not download all available Apple updates.') prefs.set_pref('LastAppleSoftwareUpdateCheck', None) return False
def thereAreUpdatesToBeForcedSoon(hours=72): '''Return True if any updates need to be installed within the next X hours, false otherwise''' installinfo = getInstallInfo().get('managed_installs', []) installinfo.extend(getAppleUpdates().get('AppleUpdates', [])) if installinfo: now = NSDate.date() now_xhours = NSDate.dateWithTimeIntervalSinceNow_(hours * 3600) for item in installinfo: force_install_after_date = item.get('force_install_after_date') if force_install_after_date: try: force_install_after_date = discardTimeZoneFromDate( force_install_after_date) if now_xhours >= force_install_after_date: return True except BadDateError: # some issue with the stored date pass return False
def looponce(): app = NSApplication.sharedApplication() # It is very likely that this code will run in a separate python thread. # An autoreleasepool won't be created automatically for us, so do so "manually" to avoid leaking. # http://www.opensource.apple.com/source/pyobjc/pyobjc-14/pyobjc/stable/pyobjc-core/Doc/api-notes-macosx.txt pool = NSAutoreleasePool.alloc().init() # to push the run loops I seem to have to do this twice # use NSEventTrackingRunLoopMode or NSDefaultRunLoopMode? for i in range(2): event = app.nextEventMatchingMask_untilDate_inMode_dequeue_( NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_(0.02), NSDefaultRunLoopMode, False) del pool