From 678f9c7374440d0b6897fe65f66f8909e966b2ac Mon Sep 17 00:00:00 2001 From: hansvqp Date: Sat, 20 Dec 2014 13:33:20 +0100 Subject: [PATCH] Add System Tray menu for Linux systems with GTK support. --- SABnzbd.py | 13 +++- sabnzbd/sabtraylinux.py | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 sabnzbd/sabtraylinux.py diff --git a/SABnzbd.py b/SABnzbd.py index e6419aa..889a5e5 100755 --- a/SABnzbd.py +++ b/SABnzbd.py @@ -1387,9 +1387,16 @@ def main(): # Save the INI file config.save_config(force=True) - if sabnzbd.WIN32 and sabnzbd.cfg.win_menu() and not sabnzbd.DAEMON: - import sabnzbd.sabtray - sabnzbd.WINTRAY = sabnzbd.sabtray.SABTrayThread() + if sabnzbd.cfg.win_menu() and not sabnzbd.DAEMON: + if sabnzbd.WIN32: + import sabnzbd.sabtray + sabnzbd.WINTRAY = sabnzbd.sabtray.SABTrayThread() + elif sabnzbd.LINUX_POWER and os.environ.get('DISPLAY'): + try: + import gtk, sabnzbd.sabtraylinux + sabnzbd.LINUXTRAY = sabnzbd.sabtraylinux.StatusIcon() + except: + logging.info("pygtk2 not found. No SysTray.") print_modules() diff --git a/sabnzbd/sabtraylinux.py b/sabnzbd/sabtraylinux.py new file mode 100644 index 0000000..1f98b75 --- /dev/null +++ b/sabnzbd/sabtraylinux.py @@ -0,0 +1,180 @@ +#!/usr/bin/python -OO +# Copyright 2008-2014 The SABnzbd-Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +""" +sabnzbd.sabtraylinux - System tray icon for Linux, inspired from the Windows one +""" + +import os +import gtk,gobject +import cherrypy +from time import sleep +import subprocess +import threading +from threading import Thread + +import sabnzbd +from sabnzbd.panic import launch_a_browser +import sabnzbd.api as api +import sabnzbd.scheduler as scheduler +from sabnzbd.downloader import Downloader +import sabnzbd.cfg as cfg +from sabnzbd.constants import MEBI +from sabnzbd.misc import to_units +from sabnzbd.utils.upload import add_local + + +class StatusIcon(Thread): + sabicons = { + 'default': 'icons/sabnzbd16.ico', + 'green': 'icons/sabnzbd16green.ico', + 'pause': 'icons/sabnzbd16paused.ico' + } + + updatefreq = 1000#ms + + def __init__(self): + self.mythread = Thread(target=self.dowork) + self.mythread.start() + + def dowork(self): + # Wait for translated texts to be loaded + while not sabnzbd.WEBUI_READY: + sleep(0.2) + logging.debug('language file not loaded, waiting') + + self.sabpaused = False + self.statusicon = gtk.StatusIcon() + self.icon = self.sabicons['default'] + self.refresh_icon() + self.tooltip = "SABnzbd" + self.refresh_tooltip() + self.statusicon.connect("popup-menu", self.right_click_event) + + gtk.gdk.threads_init() + gtk.gdk.threads_enter() + gobject.timeout_add(self.updatefreq, self.run) + gtk.main() + + def refresh_icon(self): + self.statusicon.set_from_file(self.icon) + + def refresh_tooltip(self): + self.statusicon.set_tooltip(self.tooltip) + + # run this every updatefreq ms + def run(self): + self.sabpaused, bytes_left, bpsnow, time_left = api.fast_queue() + mb_left = to_units(bytes_left, dec_limit=1) + speed = to_units(bpsnow, dec_limit=1) + + if self.sabpaused: + self.tooltip = T('Paused') + self.icon = self.sabicons['pause'] + elif bytes_left > 0: + self.tooltip = "%sB/s %s: %sB (%s)" % (speed, T('Remaining'), mb_left, time_left) + self.icon = self.sabicons['green'] + else: + self.tooltip = T('Idle') + self.icon = self.sabicons['default'] + + self.refresh_icon() + self.refresh_tooltip() + return 1 + + # menu + def right_click_event(self,icon,button,time): + menu = gtk.Menu() + + maddnzb = gtk.MenuItem(T("Add NZB")) + mshowinterface = gtk.MenuItem(T("Show interface")) + mopencomplete = gtk.MenuItem(T("Open complete folder")) + + if self.sabpaused: + mpauseresume = gtk.MenuItem(T("Resume")) + else: + mpauseresume = gtk.MenuItem(T("Pause")) + mrestart = gtk.MenuItem(T("Restart")) + mshutdown = gtk.MenuItem(T("Shutdown")) + + maddnzb.connect("activate",self.addnzb) + mshowinterface.connect("activate",self.browse) + mopencomplete.connect("activate",self.opencomplete) + mpauseresume.connect("activate",self.pauseresume) + mrestart.connect("activate",self.restart) + mshutdown.connect("activate", self.shutdown) + + menu.append(maddnzb) + menu.append(mshowinterface) + menu.append(mopencomplete) + menu.append(mpauseresume) + menu.append(mrestart) + menu.append(mshutdown) + + menu.show_all() + menu.popup(None, None, gtk.status_icon_position_menu, button, time, self.statusicon) + + # menu handlers + def addnzb(self,icon): + dialog = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN, + buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + dialog.set_select_multiple(True) + + filter = gtk.FileFilter() + filter.set_name("*.nbz,*.nbz.gz,*.zip,*.rar") + filter.add_pattern("*.nzb*") + filter.add_pattern("*.nzb.gz") + filter.add_pattern("*.zip") + filter.add_pattern("*.rar") + dialog.add_filter(filter) + + response = dialog.run() + if response == gtk.RESPONSE_OK: + for filename in dialog.get_filenames(): + add_local(filename) + dialog.destroy() + + def opencomplete(self,icon): + subprocess.Popen(["xdg-open", cfg.complete_dir.get_path()]) + + def browse(self,icon): + launch_a_browser(sabnzbd.BROWSER_URL, True) + + def pauseresume(self,icon): + if self.sabpaused: + self.resume() + else: + self.pause() + + def restart(self,icon): + self.hover_text = T('Restart') + sabnzbd.halt() + cherrypy.engine.restart() + + def shutdown(self,icon): + self.hover_text = T('Shutdown') + sabnzbd.halt() + cherrypy.engine.exit() + sabnzbd.SABSTOP = True + + def pause(self): + scheduler.plan_resume(0) + Downloader.do.pause() + + def resume(self): + scheduler.plan_resume(0) + sabnzbd.unpause_all() \ No newline at end of file