# # # from __future__ import absolute_import, division, print_function, unicode_literals from gi.repository import Gtk, GObject, GdkPixbuf import ui from logitech.unifying_receiver import status as _status # # # _NO_DEVICES = [None] * 6 def create(window, menu_actions=None): name = window.get_title() icon = Gtk.StatusIcon() icon.set_title(name) icon.set_name(name) icon.set_from_icon_name(ui.appicon(False)) icon._devices = list(_NO_DEVICES) icon.set_tooltip_text(name) icon.connect('activate', window.toggle_visible) menu = Gtk.Menu() for action in menu_actions or (): if action: menu.append(action.create_menu_item()) menu.append(ui.action.quit.create_menu_item()) menu.show_all() icon.connect('popup_menu', lambda icon, button, time, menu: menu.popup(None, None, icon.position_menu, icon, button, time), menu) # use size-changed to detect if the systray is available or not def _size_changed(i, size, w): def _check_systray(i2, w2): w2.set_has_systray(i2.is_embedded() and i2.get_visible()) GObject.timeout_add(250, _check_systray, i, w) icon.connect('size-changed', _size_changed, window) return icon _PIXMAPS = {} def _icon_with_battery(s): battery_icon = ui.get_battery_icon(s[_status.BATTERY_LEVEL]) name = '%s-%s' % (battery_icon, bool(s)) if name not in _PIXMAPS: mask = ui.icon_file(ui.appicon(True) + '-mask', 128) assert mask mask = GdkPixbuf.Pixbuf.new_from_file(mask) assert mask.get_width() == 128 and mask.get_height() == 128 mask.saturate_and_pixelate(mask, 0.7, False) battery = ui.icon_file(battery_icon, 128) assert battery battery = GdkPixbuf.Pixbuf.new_from_file(battery) assert battery.get_width() == 128 and battery.get_height() == 128 if not s: battery.saturate_and_pixelate(battery, 0, True) # TODO can the masking be done at runtime? battery.composite(mask, 0, 7, 80, 121, -32, 7, 1, 1, GdkPixbuf.InterpType.NEAREST, 255) _PIXMAPS[name] = mask return _PIXMAPS[name] def update(icon, receiver, device=None): # print ("icon update", receiver, receiver.status, len(receiver), device) battery_status = None if device: icon._devices[device.number] = None if device.status is None else device if not receiver: icon._devices[:] = _NO_DEVICES if not icon.is_embedded(): return lines = [ui.NAME + ': ' + str(receiver.status), ''] for dev in icon._devices: if dev is None: continue lines.append('' + dev.name + '') assert hasattr(dev, 'status') and dev.status is not None p = str(dev.status) if p: if not dev.status: p += ' (inactive)' else: if dev.status: p = 'no status' else: p = '(inactive)' lines.append('\t' + p) lines.append('') if battery_status is None and dev.status.get(_status.BATTERY_LEVEL): battery_status = dev.status icon.set_tooltip_markup('\n'.join(lines).rstrip('\n')) if battery_status is None: icon.set_from_icon_name(ui.appicon(receiver.status)) else: icon.set_from_pixbuf(_icon_with_battery(battery_status))