summaryrefslogtreecommitdiff
path: root/ui4/systemtray.py
diff options
context:
space:
mode:
Diffstat (limited to 'ui4/systemtray.py')
-rw-r--r--ui4/systemtray.py810
1 files changed, 810 insertions, 0 deletions
diff --git a/ui4/systemtray.py b/ui4/systemtray.py
new file mode 100644
index 0000000..9572689
--- /dev/null
+++ b/ui4/systemtray.py
@@ -0,0 +1,810 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Author: Don Welch
+
+# Std Lib
+import sys
+import struct
+import select
+import os
+import signal
+import os.path
+import time
+
+
+# Local
+from base.g import *
+from base import device, utils, models
+from base.codes import *
+from ui_utils import *
+
+# PyQt
+try:
+ from PyQt4.QtCore import *
+ from PyQt4.QtGui import *
+except ImportError:
+ log.error("Python bindings for Qt4 not found. Try using --qt3. Exiting!")
+ sys.exit(1)
+
+from systrayframe import SystrayFrame
+
+# dbus (required)
+try:
+ import dbus
+ #import dbus.service
+ from dbus import SessionBus, lowlevel
+ #from dbus.mainloop.qt import DBusQtMainLoop
+except ImportError:
+ log.error("Python bindings for dbus not found. Exiting!")
+ sys.exit(1)
+
+import warnings
+# Ignore: .../dbus/connection.py:242: DeprecationWarning: object.__init__() takes no parameters
+# (occurring on Python 2.6/dBus 0.83/Ubuntu 9.04)
+warnings.simplefilter("ignore", DeprecationWarning)
+
+
+# pynotify (optional)
+have_pynotify = True
+try:
+ import pynotify
+except ImportError:
+ have_pynotify = False
+
+
+TRAY_MESSAGE_DELAY = 10000
+HIDE_INACTIVE_DELAY = 5000
+BLIP_DELAY = 2000
+SET_MENU_DELAY = 1000
+MAX_MENU_EVENTS = 10
+UPGRADE_CHECK_DELAY=24*60*60*1000 #1 day
+
+ERROR_STATE_TO_ICON = {
+ ERROR_STATE_CLEAR: QSystemTrayIcon.Information,
+ ERROR_STATE_OK: QSystemTrayIcon.Information,
+ ERROR_STATE_WARNING: QSystemTrayIcon.Warning,
+ ERROR_STATE_ERROR: QSystemTrayIcon.Critical,
+ ERROR_STATE_LOW_SUPPLIES: QSystemTrayIcon.Warning,
+ ERROR_STATE_BUSY: QSystemTrayIcon.Warning,
+ ERROR_STATE_LOW_PAPER: QSystemTrayIcon.Warning,
+ ERROR_STATE_PRINTING: QSystemTrayIcon.Information,
+ ERROR_STATE_SCANNING: QSystemTrayIcon.Information,
+ ERROR_STATE_PHOTOCARD: QSystemTrayIcon.Information,
+ ERROR_STATE_FAXING: QSystemTrayIcon.Information,
+ ERROR_STATE_COPYING: QSystemTrayIcon.Information,
+}
+
+if have_pynotify:
+ info = getPynotifyIcon('info')
+ warn = getPynotifyIcon('warning')
+ err = getPynotifyIcon('error')
+ ERROR_STATE_TO_ICON_AND_URGENCY_PYNOTIFY = {
+ ERROR_STATE_CLEAR: (info, pynotify.URGENCY_LOW),
+ ERROR_STATE_OK: (info, pynotify.URGENCY_LOW),
+ ERROR_STATE_WARNING: (warn, pynotify.URGENCY_NORMAL),
+ ERROR_STATE_ERROR: (err, pynotify.URGENCY_CRITICAL),
+ ERROR_STATE_LOW_SUPPLIES: (warn, pynotify.URGENCY_NORMAL),
+ ERROR_STATE_BUSY: (warn, pynotify.URGENCY_NORMAL),
+ ERROR_STATE_LOW_PAPER: (warn, pynotify.URGENCY_NORMAL),
+ ERROR_STATE_PRINTING: (info, pynotify.URGENCY_LOW),
+ ERROR_STATE_SCANNING: (info, pynotify.URGENCY_LOW),
+ ERROR_STATE_PHOTOCARD: (info, pynotify.URGENCY_LOW),
+ ERROR_STATE_FAXING: (info, pynotify.URGENCY_LOW),
+ ERROR_STATE_COPYING: (info, pynotify.URGENCY_LOW),
+ }
+
+devices = {} # { <device_uri> : HistoryDevice(), ... }
+
+
+class DeviceMenu(QMenu):
+ def __init__(self, title, parent, device_uri, device_hist, index):
+ QMenu.__init__(self, title, parent)
+ self.device_uri = device_uri
+ self.device_hist = device_hist
+ self.index = index
+
+
+ def update(self):
+ self.clear()
+
+ if self.device_hist:
+ first = True
+ for e in self.device_hist:
+ error_state = STATUS_TO_ERROR_STATE_MAP.get(e.event_code, ERROR_STATE_CLEAR)
+ ess = device.queryString(e.event_code, 0)
+
+ a = QAction(QIcon(getStatusListIcon(error_state)[self.index]),
+ QString("%1 %2").arg(ess).arg(getTimeDeltaDesc(e.timedate)), self)
+
+ if first:
+ f = a.font()
+ f.setBold(True)
+ a.setFont(f)
+ self.setIcon(QIcon(getStatusListIcon(error_state)[self.index]))
+ first = False
+
+ self.addAction(a)
+
+ else:
+ self.addAction(QIcon(load_pixmap("warning", "16x16")),
+ QApplication.translate("SystemTray", "(No events)", None, QApplication.UnicodeUTF8))
+
+
+
+class HistoryDevice(QObject):
+ def __init__(self, device_uri, needs_update=True):
+ self.needs_update = needs_update
+ self.device_uri = device_uri
+
+ back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
+ device.parseDeviceURI(device_uri)
+
+ if bus == 'usb':
+ self.id = serial
+ elif bus == 'net':
+ self.id = host
+ elif bus == 'par':
+ self.id = dev_file
+ else:
+ self.id = 'unknown'
+
+ self.model = models.normalizeModelUIName(model)
+
+ if back_end == 'hp':
+ self.device_type = DEVICE_TYPE_PRINTER
+ self.menu_text = self.__tr("%1 Printer (%2)").arg(self.model).arg(self.id)
+
+ elif back_end == 'hpaio':
+ self.device_type = DEVICE_TYPE_SCANNER
+ self.menu_text = self.__tr("%1 Scanner (%2)").arg(self.model).arg(self.id)
+
+ elif back_end == 'hpfax':
+ self.device_type = DEVICE_TYPE_FAX
+ self.menu_text = self.__tr("%1 Fax (%2)").arg(self.model).arg(self.id)
+
+ else:
+ self.device_type = DEVICE_TYPE_UNKNOWN
+ self.menu_text = self.__tr("%1 (%2)").arg(self.model).arg(self.id)
+
+ self.mq = device.queryModelByURI(self.device_uri)
+ self.index = 0
+ if self.mq.get('tech-type', TECH_TYPE_NONE) in (TECH_TYPE_MONO_LASER, TECH_TYPE_COLOR_LASER):
+ self.index = 1
+ self.history = None
+
+
+ def getHistory(self, service):
+ if service is not None and self.needs_update:
+ device_uri, h = service.GetHistory(self.device_uri)
+ self.history = [device.Event(*tuple(e)) for e in list(h)[:-MAX_MENU_EVENTS:-1]]
+ self.needs_update = False
+
+
+ def __tr(self, s, c=None):
+ return QApplication.translate("SystemTray", s, c, QApplication.UnicodeUTF8)
+
+
+
+
+class SystraySettingsDialog(QDialog):
+ def __init__(self, parent, systray_visible, polling,
+ polling_interval, systray_messages,
+ device_list=None,
+ upgrade_notify=True,
+ upgrade_pending_time=0,
+ upgrade_last_update_time=0,
+ upgrade_msg=""
+ ):
+# upgrade_pending_update_time=0,
+
+
+ QDialog.__init__(self, parent)
+
+ self.systray_visible = systray_visible
+ self.systray_messages = systray_messages
+
+ if device_list is not None:
+ self.device_list = device_list
+ else:
+ self.device_list = {}
+
+ self.polling = polling
+ self.polling_interval = polling_interval
+ self.upgrade_notify =upgrade_notify
+ self.upgrade_last_update_time=upgrade_last_update_time
+ self.upgrade_pending_time=upgrade_pending_time
+ self.upgrade_msg=upgrade_msg
+
+ self.initUi()
+ self.SystemTraySettings.updateUi()
+
+
+ def initUi(self):
+ self.setObjectName("SystraySettingsDialog")
+ self.resize(QSize(QRect(0,0,488,565).size()).expandedTo(self.minimumSizeHint()))
+
+ self.gridlayout = QGridLayout(self)
+ self.gridlayout.setObjectName("gridlayout")
+
+ self.SystemTraySettings = SystrayFrame(self)
+ self.SystemTraySettings.initUi(self.systray_visible,
+ self.polling, self.polling_interval,
+ self.device_list,
+ self.systray_messages,
+ self.upgrade_notify,
+ self.upgrade_pending_time,
+ self.upgrade_msg)
+
+ sizePolicy = QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.SystemTraySettings.sizePolicy().hasHeightForWidth())
+ self.SystemTraySettings.setSizePolicy(sizePolicy)
+ self.SystemTraySettings.setFrameShadow(QFrame.Raised)
+ self.SystemTraySettings.setObjectName("SystemTraySettings")
+ self.gridlayout.addWidget(self.SystemTraySettings,0,0,1,2)
+
+ spacerItem = QSpacerItem(301,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
+ self.gridlayout.addItem(spacerItem,1,0,1,1)
+
+ self.StdButtons = QDialogButtonBox(self)
+ self.StdButtons.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.NoButton|QDialogButtonBox.Ok)
+ self.StdButtons.setCenterButtons(False)
+ self.StdButtons.setObjectName("StdButtons")
+ self.gridlayout.addWidget(self.StdButtons,1,1,1,1)
+
+ QObject.connect(self.StdButtons, SIGNAL("accepted()"), self.acceptClicked)
+ QObject.connect(self.StdButtons, SIGNAL("rejected()"), self.reject)
+ #QMetaObject.connectSlotsByName(self)
+
+ self.setWindowTitle(self.__tr("HP Device Manager - System Tray Settings"))
+ self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
+# pm = load_pixmap("hp_logo", "32x32")
+# self.prop_icon = QIcon(pm)
+
+
+ def acceptClicked(self):
+ self.systray_visible = self.SystemTraySettings.systray_visible
+ self.polling = self.SystemTraySettings.polling
+ self.polling_interval = self.SystemTraySettings.polling_interval
+ self.device_list = self.SystemTraySettings.device_list
+ self.systray_messages = self.SystemTraySettings.systray_messages
+ self.upgrade_notify =self.SystemTraySettings.upgrade_notify
+ self.accept()
+
+
+ def __tr(self, s, c=None):
+ return QApplication.translate("SystraySettingsDialog", s, c, QApplication.UnicodeUTF8)
+
+
+
+
+class SystemTrayApp(QApplication):
+ def __init__(self, args, read_pipe):
+ QApplication.__init__(self, args)
+
+ self.menu = None
+ self.read_pipe = read_pipe
+ self.fmt = "80s80sI32sI80sf"
+ self.fmt_size = struct.calcsize(self.fmt)
+ self.timer_active = False
+ self.active_icon = False
+ self.user_settings = UserSettings()
+ self.user_settings.load()
+ self.user_settings.debug()
+
+ self.tray_icon = QSystemTrayIcon()
+
+ pm = load_pixmap("hp_logo", "32x32")
+ self.prop_icon = QIcon(pm)
+
+ a = load_pixmap('active', '16x16')
+ painter = QPainter(pm)
+ painter.drawPixmap(32, 0, a)
+ painter.end()
+
+ self.prop_active_icon = QIcon(pm)
+
+ self.tray_icon.setIcon(self.prop_icon)
+
+ self.session_bus = SessionBus()
+ self.service = None
+
+ for d in device.getSupportedCUPSDevices(back_end_filter=['hp', 'hpfax']):
+ self.addDevice(d)
+
+ self.tray_icon.setToolTip(self.__tr("HPLIP Status Service"))
+ QObject.connect(self.tray_icon, SIGNAL("messageClicked()"), self.messageClicked)
+ notifier = QSocketNotifier(self.read_pipe, QSocketNotifier.Read)
+ QObject.connect(notifier, SIGNAL("activated(int)"), self.notifierActivated)
+ QObject.connect(self.tray_icon, SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.trayActivated)
+ self.tray_icon.show()
+
+ if self.user_settings.systray_visible == SYSTRAY_VISIBLE_SHOW_ALWAYS:
+ self.tray_icon.setVisible(True)
+ else:
+ QTimer.singleShot(HIDE_INACTIVE_DELAY, self.timeoutHideWhenInactive) # show icon for awhile @ startup
+
+ self.tray_icon.setIcon(self.prop_active_icon)
+ self.active_icon = True
+
+ self.handle_hplip_updation()
+ QTimer.singleShot(SET_MENU_DELAY, self.initDone)
+
+ self.timer = QTimer()
+ self.timer.connect(self.timer,SIGNAL("timeout()"),self.handle_hplip_updation)
+ self.timer.start(UPGRADE_CHECK_DELAY)
+
+
+
+ def initDone(self):
+ self.tray_icon.setIcon(self.prop_icon)
+ self.active_icon = False
+
+ self.setMenu()
+
+
+ def addDevice(self, device_uri):
+ try:
+ devices[device_uri]
+ except KeyError:
+ devices[device_uri] = HistoryDevice(device_uri)
+ else:
+ devices[device_uri].needs_update = True
+
+
+ def handle_hplip_updation(self):
+ log.debug("handle_hplip_updation upgrade_notify =%d"%(self.user_settings.upgrade_notify))
+ path = utils.which('hp-upgrade')
+ if self.user_settings.upgrade_notify is False:
+ log.debug("upgrade notification is disabled in systray ")
+ if path:
+ path = os.path.join(path, 'hp-upgrade')
+ log.debug("Running hp-upgrade: %s " % (path))
+ # this just updates the available version in conf file. But won't notify
+ os.spawnlp(os.P_NOWAIT, path, 'hp-upgrade', '--check')
+ return
+
+
+ current_time = time.time()
+
+ if int(current_time) > self.user_settings.upgrade_pending_update_time:
+ path = utils.which('hp-upgrade')
+ if path:
+ path = os.path.join(path, 'hp-upgrade')
+ log.debug("Running hp-upgrade: %s " % (path))
+ os.spawnlp(os.P_NOWAIT, path, 'hp-upgrade', '--notify')
+
+ else:
+ log.error("Unable to find hp-upgrade --notify on PATH.")
+ else:
+ log.debug("upgrade schedule time is not yet completed. schedule time =%d current time =%d " %(self.user_settings.upgrade_pending_update_time, current_time))
+
+
+
+
+
+
+ def setMenu(self):
+ self.menu = QMenu()
+
+ title = QWidgetAction(self.menu)
+ #title.setDisabled(True)
+
+ hbox = QFrame(self.menu)
+ layout = QHBoxLayout(hbox)
+ layout.setMargin(3)
+ layout.setSpacing(5)
+ pix_label = QLabel(hbox)
+
+ layout.insertWidget(-1, pix_label, 0)
+
+ icon_size = self.menu.style().pixelMetric(QStyle.PM_SmallIconSize)
+ pix_label.setPixmap(self.prop_icon.pixmap(icon_size))
+
+ label = QLabel(hbox)
+ layout.insertWidget(-1, label, 20)
+ title.setDefaultWidget(hbox)
+
+ label.setText(self.__tr("HPLIP Status Service"))
+
+ f = label.font()
+ f.setBold(True)
+ label.setFont(f)
+ self.menu.insertAction(None, title)
+
+ if devices:
+ if self.service is None:
+ t = 0
+ while t < 3:
+ try:
+ self.service = self.session_bus.get_object('com.hplip.StatusService',
+ "/com/hplip/StatusService")
+ except DBusException:
+ log.warn("Unable to connect to StatusService. Retrying...")
+
+ t += 1
+ time.sleep(0.5)
+
+ if self.service is not None:
+ self.menu.addSeparator()
+
+ for d in devices:
+ devices[d].getHistory(self.service)
+
+ menu = DeviceMenu(devices[d].menu_text, self.menu, d, devices[d].history, devices[d].index)
+ self.menu.addMenu(menu)
+ menu.update()
+
+
+ self.menu.addSeparator()
+ self.menu.addAction(self.__tr("HP Device Manager..."), self.toolboxTriggered)
+
+ self.menu.addSeparator()
+
+ self.settings_action = self.menu.addAction(QIcon(load_pixmap('settings', '16x16')),
+ self.__tr("Settings..."), self.settingsTriggered)
+
+ self.menu.addSeparator()
+ self.menu.addAction(QIcon(load_pixmap('quit', '16x16')), "Quit", self.quitTriggered)
+ self.tray_icon.setContextMenu(self.menu)
+
+
+
+
+ def settingsTriggered(self):
+ if self.menu is None:
+ return
+
+ self.sendMessage('', '', EVENT_DEVICE_STOP_POLLING)
+# sys_conf
+ cur_vers = sys_conf.get('hplip', 'version')
+ self.user_settings.load()
+ installed_time =time.strftime("%d-%m-%Y", time.localtime(self.user_settings.upgrade_last_update_time))
+ if utils.Is_HPLIP_older_version(cur_vers, self.user_settings.latest_available_version):
+ if int(time.time()) < self.user_settings.upgrade_pending_update_time :
+ postponed_time =time.strftime("%d-%m-%Y", time.localtime(self.user_settings.upgrade_pending_update_time))
+ upgrade_msg ="HPLIP-%s version was installed on %s.\n\nNew version of HPLIP-%s is available for upgrade. HPLIP upgrade is scheduled on %s." %(cur_vers,installed_time , self.user_settings.latest_available_version, postponed_time)
+ elif self.user_settings.upgrade_last_update_time:
+ upgrade_msg ="HPLIP-%s version was installed on %s.\n\nNew version of HPLIP-%s is available for upgrade." %(cur_vers,installed_time , self.user_settings.latest_available_version)
+ else:
+ upgrade_msg ="HPLIP-%s version was installed.\n\nNew version of HPLIP-%s is available for upgrade." %(cur_vers, self.user_settings.latest_available_version)
+ elif self.user_settings.upgrade_last_update_time:
+ upgrade_msg ="HPLIP-%s version was installed on %s."%(cur_vers, installed_time)
+ else:
+ upgrade_msg ="HPLIP-%s version was installed."%(cur_vers)
+
+
+ try:
+ dlg = SystraySettingsDialog(self.menu, self.user_settings.systray_visible,
+ self.user_settings.polling, self.user_settings.polling_interval,
+ self.user_settings.systray_messages,
+ self.user_settings.polling_device_list,
+ self.user_settings.upgrade_notify,
+ self.user_settings.upgrade_pending_update_time,
+ self.user_settings.upgrade_last_update_time,
+ upgrade_msg)
+
+
+ if dlg.exec_() == QDialog.Accepted:
+ self.user_settings.systray_visible = dlg.systray_visible
+ self.user_settings.systray_messages = dlg.systray_messages
+ self.user_settings.upgrade_notify = dlg.upgrade_notify
+
+ log.debug("HPLIP update notification = %d"%(self.user_settings.upgrade_notify))
+ self.user_settings.save()
+
+ if self.user_settings.systray_visible == SYSTRAY_VISIBLE_SHOW_ALWAYS:
+ log.debug("Showing...")
+ self.tray_icon.setVisible(True)
+
+ else:
+ log.debug("Waiting to hide...")
+ QTimer.singleShot(HIDE_INACTIVE_DELAY, self.timeoutHideWhenInactive)
+
+ self.sendMessage('', '', EVENT_USER_CONFIGURATION_CHANGED)
+
+ finally:
+ self.sendMessage('', '', EVENT_DEVICE_START_POLLING)
+
+
+ def timeoutHideWhenInactive(self):
+ log.debug("Hiding...")
+ if self.user_settings.systray_visible in (SYSTRAY_VISIBLE_HIDE_WHEN_INACTIVE, SYSTRAY_VISIBLE_HIDE_ALWAYS):
+ self.tray_icon.setVisible(False)
+ log.debug("Hidden")
+
+
+ def updateMenu(self):
+ if self.menu is None:
+ return
+ for a in self.menu.actions():
+ try:
+ a.menu().update()
+ except AttributeError:
+ continue
+
+
+
+ def trayActivated(self, reason):
+ if reason == QSystemTrayIcon.Context:
+ self.updateMenu()
+
+
+ elif reason == QSystemTrayIcon.DoubleClick:
+ #print "double click"
+ self.toolboxTriggered()
+ pass
+
+ elif reason == QSystemTrayIcon.Trigger:
+ #print "single click"
+ pass
+
+ elif reason == QSystemTrayIcon.MiddleClick:
+ #print "middle click"
+ pass
+
+
+ def messageClicked(self):
+ #print "\nPARENT: message clicked"
+ pass
+
+
+ def quitTriggered(self):
+ log.debug("Exiting")
+ self.sendMessage('', '', EVENT_SYSTEMTRAY_EXIT)
+ self.quit()
+ del self.tray_icon
+
+ def toolboxTriggered(self):
+ try:
+ os.waitpid(-1, os.WNOHANG)
+ except OSError:
+ pass
+
+ # See if it is already running...
+ ok, lock_file = utils.lock_app('hp-toolbox', True)
+
+ if ok: # able to lock, not running...
+ utils.unlock(lock_file)
+
+ path = utils.which('hp-toolbox')
+ if path:
+ path = os.path.join(path, 'hp-toolbox')
+ else:
+ self.tray_icon.showMessage(self.__tr("HPLIP Status Service"),
+ self.__tr("Unable to locate hp-toolbox on system PATH."),
+ QSystemTrayIcon.Critical, TRAY_MESSAGE_DELAY)
+
+ log.error("Unable to find hp-toolbox on PATH.")
+ return
+
+ #log.debug(path)
+ log.debug("Running hp-toolbox: hp-toolbox")
+ os.spawnlp(os.P_NOWAIT, path, 'hp-toolbox')
+
+ else: # ...already running, raise it
+ self.sendMessage('', '', EVENT_RAISE_DEVICE_MANAGER, interface='com.hplip.Toolbox')
+
+
+ def sendMessage(self, device_uri, printer_name, event_code, username=prop.username,
+ job_id=0, title='', pipe_name='', interface='com.hplip.StatusService'):
+ #device.Event(device_uri, printer_name, event_code, username, job_id, title).send_via_dbus(SessionBus(), interface)
+ device.Event(device_uri, printer_name, event_code, username, job_id, title).send_via_dbus(self.session_bus, interface)
+
+
+ def notifierActivated(self, s):
+ m = ''
+ while True:
+ try:
+ r, w, e = select.select([self.read_pipe], [], [self.read_pipe], 1.0)
+ except select.error:
+ log.debug("Error in select()")
+ break
+
+ if e:
+ log.error("Pipe error: %s" % e)
+ break
+
+ if r:
+ m = ''.join([m, os.read(self.read_pipe, self.fmt_size)])
+ while len(m) >= self.fmt_size:
+ event = device.Event(*struct.unpack(self.fmt, m[:self.fmt_size]))
+
+ m = m[self.fmt_size:]
+
+ if event.event_code == EVENT_USER_CONFIGURATION_CHANGED:
+ log.debug("Re-reading configuration (EVENT_USER_CONFIGURATION_CHANGED)")
+ self.user_settings.load()
+ self.user_settings.debug()
+
+ elif event.event_code == EVENT_SYSTEMTRAY_EXIT:
+ self.quit()
+ return
+
+ if self.user_settings.systray_visible in \
+ (SYSTRAY_VISIBLE_SHOW_ALWAYS, SYSTRAY_VISIBLE_HIDE_WHEN_INACTIVE):
+
+ log.debug("Showing...")
+ self.tray_icon.setVisible(True)
+
+ if event.event_code == EVENT_DEVICE_UPDATE_ACTIVE:
+ if not self.active_icon:
+ self.tray_icon.setIcon(self.prop_active_icon)
+ self.active_icon = True
+ continue
+
+ elif event.event_code == EVENT_DEVICE_UPDATE_INACTIVE:
+ if self.active_icon:
+ self.tray_icon.setIcon(self.prop_icon)
+ self.active_icon = False
+ continue
+
+ elif event.event_code == EVENT_DEVICE_UPDATE_BLIP:
+ if not self.active_icon:
+ self.tray_icon.setIcon(self.prop_active_icon)
+ self.active_icon = True
+ QTimer.singleShot(BLIP_DELAY, self.blipTimeout)
+ continue
+
+ if self.user_settings.systray_visible in (SYSTRAY_VISIBLE_HIDE_WHEN_INACTIVE, SYSTRAY_VISIBLE_HIDE_ALWAYS):
+ log.debug("Waiting to hide...")
+ QTimer.singleShot(HIDE_INACTIVE_DELAY, self.timeoutHideWhenInactive)
+
+ if event.event_code <= EVENT_MAX_USER_EVENT:
+ self.addDevice(event.device_uri)
+ self.setMenu()
+
+ if self.tray_icon.supportsMessages():
+
+ log.debug("Tray icon message:")
+ event.debug()
+
+ error_state = STATUS_TO_ERROR_STATE_MAP.get(event.event_code, ERROR_STATE_CLEAR)
+ desc = device.queryString(event.event_code)
+
+ show_message = False
+ if self.user_settings.systray_messages == SYSTRAY_MESSAGES_SHOW_ALL: # OK, Busy
+ show_message = True
+
+ elif self.user_settings.systray_messages in (SYSTRAY_MESSAGES_SHOW_ERRORS_AND_WARNINGS, SYSTRAY_MESSAGES_SHOW_ERRORS_ONLY):
+ if error_state == ERROR_STATE_ERROR:
+ show_message = True
+
+ elif self.user_settings.systray_messages == SYSTRAY_MESSAGES_SHOW_ERRORS_AND_WARNINGS and \
+ error_state in (ERROR_STATE_WARNING, ERROR_STATE_LOW_SUPPLIES, ERROR_STATE_LOW_PAPER):
+
+ show_message = True
+
+ if event.printer_name:
+ d = QString(event.printer_name)
+ else:
+ back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
+ device.parseDeviceURI(event.device_uri)
+
+ if bus == 'usb':
+ idd = serial
+ elif bus == 'net':
+ idd = host
+ elif bus == 'par':
+ idd = dev_file
+ else:
+ idd = 'unknown'
+
+ self.model = models.normalizeModelUIName(model)
+
+ if back_end == 'hp':
+ d = self.__tr("%1 Printer (%2)").arg(model).arg(idd)
+
+ elif back_end == 'hpaio':
+ d = self.__tr("%1 Scanner (%2)").arg(model).arg(idd)
+
+ elif back_end == 'hpfax':
+ d = self.__tr("%1 Fax (%2)").arg(model).arg(idd)
+
+ else:
+ d = self.__tr("%1 (%2)").arg(model).arg(idd)
+
+ if show_message:
+ if have_pynotify and pynotify.init("hplip"): # Use libnotify/pynotify
+ icon, urgency = ERROR_STATE_TO_ICON_AND_URGENCY_PYNOTIFY.get(error_state,
+ (getPynotifyIcon('info'), pynotify.URGENCY_NORMAL))
+
+ if event.job_id and event.title:
+ msg = "%s\n%s: %s\n(%s/%s)" % (unicode(d), desc, event.title, event.username, event.job_id)
+ log.debug("Notify: uri=%s desc=%s title=%s user=%s job_id=%d code=%d" %
+ (event.device_uri, desc, event.title, event.username, event.job_id, event.event_code))
+ else:
+ msg = "%s\n%s (%s)" % (unicode(d), desc, event.event_code)
+ log.debug("Notify: uri=%s desc=%s code=%d" % (event.device_uri, desc, event.event_code))
+
+ n = pynotify.Notification("HPLIP Device Status", msg, icon)
+ n.set_urgency(urgency)
+
+ if error_state == ERROR_STATE_ERROR:
+ n.set_timeout(pynotify.EXPIRES_NEVER)
+ else:
+ n.set_timeout(TRAY_MESSAGE_DELAY)
+
+ n.show()
+
+ else: # Use "standard" message bubbles
+ icon = ERROR_STATE_TO_ICON.get(error_state, QSystemTrayIcon.Information)
+ if event.job_id and event.title:
+ log.debug("Bubble: uri=%s desc=%s title=%s user=%s job_id=%d code=%d" %
+ (event.device_uri, desc, event.title, event.username, event.job_id, event.event_code))
+ self.tray_icon.showMessage(self.__tr("HPLIP Device Status"),
+ QString("%1\n%2: %3\n(%4/%5)").\
+ arg(d).\
+ arg(desc).arg(event.title).\
+ arg(event.username).arg(event.job_id),
+ icon, TRAY_MESSAGE_DELAY)
+
+ else:
+ log.debug("Bubble: uri=%s desc=%s code=%d" % (event.device_uri, desc, event.event_code))
+ self.tray_icon.showMessage(self.__tr("HPLIP Device Status"),
+ QString("%1\n%2 (%3)").arg(d).\
+ arg(desc).arg(event.event_code),
+ icon, TRAY_MESSAGE_DELAY)
+
+ else:
+ break
+
+
+ def blipTimeout(self):
+ if self.active_icon:
+ self.tray_icon.setIcon(self.prop_icon)
+ self.active_icon = False
+
+
+
+ def __tr(self, s, c=None):
+ return QApplication.translate("SystemTray", s, c, QApplication.UnicodeUTF8)
+
+
+
+def run(read_pipe):
+ log.set_module("hp-systray(qt4)")
+ log.debug("PID=%d" % os.getpid())
+
+ app = SystemTrayApp(sys.argv, read_pipe)
+ app.setQuitOnLastWindowClosed(False) # If not set, settings dlg closes app
+
+ i = 0
+ while i < 60:
+ if QSystemTrayIcon.isSystemTrayAvailable():
+ break
+ time.sleep(1.0)
+ i += 1
+
+ if not QSystemTrayIcon.isSystemTrayAvailable():
+ FailureUI(None,
+ QApplication.translate("SystemTray",
+ "<b>No system tray detected on this system.</b><p>Unable to start, exiting.</p>",
+ None, QApplication.UnicodeUTF8),
+ QApplication.translate("SystemTray", "HPLIP Status Service",
+ None, QApplication.UnicodeUTF8))
+ else:
+ notifier = QSocketNotifier(read_pipe, QSocketNotifier.Read)
+ QObject.connect(notifier, SIGNAL("activated(int)"), app.notifierActivated)
+
+ app.exec_()
+
+