diff --git a/SABnzbd.py b/SABnzbd.py index 2466af2..d0b2604 100755 --- a/SABnzbd.py +++ b/SABnzbd.py @@ -24,7 +24,6 @@ if sys.hexversion < 0x03050000: import logging import logging.handlers import traceback -import os import getopt import signal import socket @@ -889,10 +888,6 @@ def main(): sabnzbd.DIR_LANGUAGE = real_path(sabnzbd.DIR_PROG, DEF_LANGUAGE) org_dir = os.getcwd() - if getattr(sys, 'frozen', None) == 'macosx_app': - # Correct path if frozen with py2app (OSX) - sabnzbd.MY_FULLNAME = sabnzbd.MY_FULLNAME.replace("/Resources/SABnzbd.py", "/MacOS/SABnzbd") - # Need console logging for SABnzbd.py and SABnzbd-console.exe console_logging = (not hasattr(sys, "frozen")) or (sabnzbd.MY_NAME.lower().find('-console') > 0) console_logging = console_logging and not sabnzbd.DAEMON @@ -1172,10 +1167,6 @@ def main(): if autobrowser is not None: sabnzbd.cfg.autobrowser.set(autobrowser) - if not sabnzbd.WIN_SERVICE and not getattr(sys, 'frozen', None) == 'macosx_app': - signal.signal(signal.SIGINT, sabnzbd.sig_handler) - signal.signal(signal.SIGTERM, sabnzbd.sig_handler) - sabnzbd.initialize(pause, clean_up, evalSched=True, repair=repair) os.chdir(sabnzbd.DIR_PROG) @@ -1396,9 +1387,6 @@ def main(): if not autorestarted: launch_a_browser(browser_url) - if sabnzbd.FOUNDATION: - import sabnzbd.osxmenu - sabnzbd.osxmenu.notify("SAB_Launched", None) notifier.send_notification('SABnzbd', T('SABnzbd %s started') % sabnzbd.__version__, 'startup') # Now's the time to check for a new version check_latest_version() @@ -1478,7 +1466,7 @@ def main(): os.chdir(org_dir) # If OSX frozen restart of app instead of embedded python - if getattr(sys, 'frozen', None) == 'macosx_app': + if getattr(sys, 'frozen', None) and sabnzbd.DARWIN: # [[NSProcessInfo processInfo] processIdentifier]] # logging.info("%s" % (NSProcessInfo.processInfo().processIdentifier())) my_pid = os.getpid() @@ -1505,20 +1493,21 @@ def main(): mail.send('stop') if sabnzbd.WIN32: del_connection_info() - if sabnzbd.FOUNDATION: - sabnzbd.osxmenu.notify("SAB_Shutdown", None) + + # Send our final goodbyes! + notifier.send_notification('SABnzbd', T('SABnzbd shutdown finished'), 'startup') logging.info('Leaving SABnzbd') sys.stderr.flush() sys.stdout.flush() sabnzbd.pid_file() - if getattr(sys, 'frozen', None) == 'macosx_app': + + if getattr(sys, 'frozen', None) and sabnzbd.DARWIN: try: AppHelper.stopEventLoop() except: # Failing AppHelper libary! os._exit(0) else: - notifier.send_notification('SABnzbd', T('SABnzbd shutdown finished'), 'startup') os._exit(0) @@ -1649,37 +1638,43 @@ if __name__ == '__main__': args.append(txt) sabnzbd.CMDLINE = ' '.join(args) + # We can only register these in the main thread + signal.signal(signal.SIGINT, sabnzbd.sig_handler) + signal.signal(signal.SIGTERM, sabnzbd.sig_handler) + if sabnzbd.WIN32: if not HandleCommandLine(allow_service=not hasattr(sys, "frozen")): main() - elif getattr(sys, 'frozen', None) == 'macosx_app': - try: - # OSX binary runner - from threading import Thread - from PyObjCTools import AppHelper - from sabnzbd.osxmenu import SABnzbdDelegate - - class startApp(Thread): - - def __init__(self): - logging.info('[osx] sabApp Starting - starting main thread') - Thread.__init__(self) - - def run(self): - main() - logging.info('[osx] sabApp Stopping - main thread quit ') - AppHelper.stopEventLoop() - - def stop(self): - logging.info('[osx] sabApp Quit - stopping main thread ') - sabnzbd.shutdown_program() - logging.info('[osx] sabApp Quit - main thread stopped') - - sabApp = startApp() - sabApp.start() - AppHelper.runEventLoop() - except: - main() + elif sabnzbd.DARWIN and sabnzbd.FOUNDATION: + + # OSX binary runner + from threading import Thread + from PyObjCTools import AppHelper + from AppKit import NSApplication + from sabnzbd.osxmenu import SABnzbdDelegate + + # Need to run the main application in separate thread because the eventLoop + # has to be in the main thread. The eventLoop is required for the menu. + # This code is made with trial-and-error, please improve! + class startApp(Thread): + def run(self): + logging.info('[osx] sabApp Starting - starting main thread') + main() + logging.info('[osx] sabApp Stopping - main thread quit ') + AppHelper.stopEventLoop() + + + sabApp = startApp() + sabApp.start() + + # Initialize the menu + shared_app = NSApplication.sharedApplication() + sabnzbd_menu = SABnzbdDelegate.alloc().init() + shared_app.setDelegate_(sabnzbd_menu) + # Build the menu + sabnzbd_menu.awakeFromNib() + # Run the main eventloop + AppHelper.runEventLoop() else: main() diff --git a/icons/sabnzbd_osx_clicked.tiff b/icons/sabnzbd_osx_clicked.tiff new file mode 100644 index 0000000..8cbc923 Binary files /dev/null and b/icons/sabnzbd_osx_clicked.tiff differ diff --git a/icons/sabnzbd_osx_idle.tiff b/icons/sabnzbd_osx_idle.tiff new file mode 100644 index 0000000..344b4a2 Binary files /dev/null and b/icons/sabnzbd_osx_idle.tiff differ diff --git a/icons/sabnzbd_osx_pause.tiff b/icons/sabnzbd_osx_pause.tiff new file mode 100644 index 0000000..382ce46 Binary files /dev/null and b/icons/sabnzbd_osx_pause.tiff differ diff --git a/sabnzbd/__init__.py b/sabnzbd/__init__.py index 30c5bc1..502c186 100644 --- a/sabnzbd/__init__.py +++ b/sabnzbd/__init__.py @@ -462,7 +462,7 @@ def trigger_restart(timeout=None): del_connection_info() # Leave the harder restarts to the polling in SABnzbd.py - if sabnzbd.WIN_SERVICE or getattr(sys, "frozen", None) == "macosx_app": + if getattr(sys, "frozen", None): sabnzbd.TRIGGER_RESTART = True else: # Do the restart right now diff --git a/sabnzbd/misc.py b/sabnzbd/misc.py index 9fefa29..d1283ed 100644 --- a/sabnzbd/misc.py +++ b/sabnzbd/misc.py @@ -477,10 +477,9 @@ def exit_sab(value): """ Leave the program after flushing stderr/stdout """ sys.stderr.flush() sys.stdout.flush() - if getattr(sys, "frozen", None) == "macosx_app": + if getattr(sys, "frozen", None) and sabnzbd.DARWIN: sabnzbd.SABSTOP = True from PyObjCTools import AppHelper - AppHelper.stopEventLoop() sys.exit(value) diff --git a/sabnzbd/osxmenu.py b/sabnzbd/osxmenu.py index a77cd43..2913b65 100644 --- a/sabnzbd/osxmenu.py +++ b/sabnzbd/osxmenu.py @@ -30,6 +30,7 @@ import sys import time import logging +import cherrypy import sabnzbd import sabnzbd.cfg @@ -47,7 +48,11 @@ import sabnzbd.downloader import sabnzbd.dirscanner as dirscanner from sabnzbd.bpsmeter import BPSMeter -status_icons = {'idle': '../Resources/sab_idle.tiff', 'pause': '../Resources/sab_pause.tiff', 'clicked': '../Resources/sab_clicked.tiff'} +status_icons = { + 'idle': 'icons/sabnzbd_osx_idle.tiff', + 'pause': 'icons/sabnzbd_osx_pause.tiff', + 'clicked': 'icons/sabnzbd_osx_clicked.tiff' +} start_time = NSDate.date() debug = 0 @@ -77,11 +82,15 @@ class SABnzbdDelegate(NSObject): # logging.info("building menu") status_bar = NSStatusBar.systemStatusBar() self.status_item = status_bar.statusItemWithLength_(NSVariableStatusItemLength) - for i in status_icons.keys(): - self.icons[i] = NSImage.alloc().initByReferencingFile_(status_icons[i]) + for icon in status_icons: + icon_path = status_icons[icon] + if getattr(sys, 'frozen', None): + # Path is modified for the binary + icon_path = os.path.join(os.path.dirname(sys.executable), '..', 'Resources', status_icons[icon]) + self.icons[icon] = NSImage.alloc().initByReferencingFile_(icon_path) if sabnzbd.DARWIN_VERSION > 9: # Support for Yosemite Dark Mode - self.icons[i].setTemplate_(YES) + self.icons[icon].setTemplate_(YES) self.status_item.setImage_(self.icons['idle']) self.status_item.setAlternateImage_(self.icons['clicked']) self.status_item.setHighlightMode_(1) @@ -92,7 +101,7 @@ class SABnzbdDelegate(NSObject): NSLog("[osx] menu 1 building") # Wait for SABnzbd Initialization - # cherrypy.engine.wait(cherrypy.process.wspbus.states.STARTED) + cherrypy.engine.wait(cherrypy.process.wspbus.states.STARTED) # Wait for translated texts to be loaded while not sabnzbd.WEBUI_READY and not sabnzbd.SABSTOP: @@ -704,8 +713,6 @@ class SABnzbdDelegate(NSObject): def openFolderAction_(self, sender): folder2open = sender.representedObject() - if isinstance(folder2open, str): - folder2open = folder2open.encode("utf-8") if debug == 1: NSLog("[osx] %@", folder2open) os.system('open "%s"' % folder2open) @@ -760,21 +767,4 @@ class SABnzbdDelegate(NSObject): self.status_item.setHighlightMode_(NO) self.osx_icon = False sabnzbd.shutdown_program() - try: - notifier.send_notification('SABnzbd', T('SABnzbd shutdown finished'), notifier.NOTIFICATION['other']) - except AttributeError: - # Fails for the OSX binary - pass - logging.info('Leaving SABnzbd') - sys.stderr.flush() - sys.stdout.flush() return NSTerminateNow - - -def notify(notificationName, message): - """ Send a notification to the OS (OSX-only) """ - if sabnzbd.FOUNDATION: - pool = Foundation.NSAutoreleasePool.alloc().init() - nc = Foundation.NSDistributedNotificationCenter.defaultCenter() - nc.postNotificationName_object_(notificationName, message) - del pool