From db53de2233cb90738b145590600293ed08cef811 Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Sun, 26 May 2013 01:24:49 +0300 Subject: [PATCH] updated status_icon to support future appindicator implementation --- lib/solaar/gtk.py | 1 + lib/solaar/ui/indicate.py | 62 -------------- lib/solaar/ui/status_icon.py | 161 ++++++++++++++++++++++++++--------- 3 files changed, 121 insertions(+), 103 deletions(-) delete mode 100644 lib/solaar/ui/indicate.py diff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py index 6c85aa05..b3212d29 100644 --- a/lib/solaar/gtk.py +++ b/lib/solaar/gtk.py @@ -109,6 +109,7 @@ def _run(args): GLib.timeout_add(10, _base.notify_on_receivers, handle_receivers_events) from gi.repository import Gtk Gtk.main() + ui.status_icon.destroy(status_icon) for l in listeners.values(): l.stop() diff --git a/lib/solaar/ui/indicate.py b/lib/solaar/ui/indicate.py deleted file mode 100644 index 2a42a8ae..00000000 --- a/lib/solaar/ui/indicate.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# -# - -# import logging - -# try: -# from gi.repository import Indicate -# from time import time as _timestamp - -# # import ui - -# # necessary because the notifications daemon does not know about our XDG_DATA_DIRS -# _icons = {} - -# # def _icon(title): -# # if title not in _icons: -# # _icons[title] = ui.icon_file(title) - -# # return _icons.get(title) - -# def init(app_title): -# global available - -# try: -# s = Indicate.Server() -# s.set_type('message.im') -# s.set_default() -# print s -# s.show() -# s.connect('server-display', server_display) - -# i = Indicate.Indicator() -# i.set_property('sender', 'test message sender') -# i.set_property('body', 'test message body') -# i.set_property_time('time', _timestamp()) -# i.set_subtype('im') -# print i, i.list_properties() -# i.show() -# i.connect('user-display', display) - -# pass -# except: -# available = False - -# init('foo') - -# # assumed to be working since the import succeeded -# available = True - -# def server_display(s): -# print 'server display', s - -# def display(i): -# print "indicator display", i -# i.hide() - -# except ImportError: -# available = False -# init = lambda app_title: False -# uninit = lambda: None -# show = lambda dev: None diff --git a/lib/solaar/ui/status_icon.py b/lib/solaar/ui/status_icon.py index e23f38ce..c88502a0 100644 --- a/lib/solaar/ui/status_icon.py +++ b/lib/solaar/ui/status_icon.py @@ -14,35 +14,94 @@ from logitech.unifying_receiver import status as _status # # -def create(activate_callback, menu_activate_callback): - assert activate_callback - assert menu_activate_callback - - icon = Gtk.StatusIcon() - icon.set_title(NAME) - icon.set_name(NAME) - icon.set_from_icon_name(_icons.APP_ICON[0]) +def _create_common(icon, menu_activate_callback): icon._devices_info = [] - icon._receivers = set() - icon.set_tooltip_text(NAME) - icon.connect('activate', activate_callback) + icon.set_title(NAME) + icon._menu_activate_callback = menu_activate_callback + icon._menu = menu = Gtk.Menu() - menu = icon._menu = Gtk.Menu() + no_receiver = Gtk.MenuItem.new_with_label('No receiver found') + no_receiver.set_sensitive(False) + menu.append(no_receiver) # per-device menu entries will be generated as-needed - menu.append(Gtk.SeparatorMenuItem.new()) menu.append(_action.about.create_menu_item()) menu.append(_action.make('application-exit', 'Quit', Gtk.main_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) - return icon + +try: + raise ImportError + # try: + # from gi.repository import AppIndicator3 as AppIndicator + # except ImportError: + # from gi.repository import AppIndicator + + # def create(activate_callback, menu_activate_callback): + # assert activate_callback + # assert menu_activate_callback + + # ind = AppIndicator.Indicator.new('indicator-solaar', _icons.APP_ICON[0], AppIndicator.IndicatorCategory.HARDWARE) + # ind.set_status(AppIndicator.IndicatorStatus.ACTIVE) + + # _create_common(ind, menu_activate_callback) + # ind.set_menu(ind._menu) + + # return ind + + + # def destroy(ind): + # ind.set_status(AppIndicator.IndicatorStatus.PASSIVE) + # ind.set_menu(None) + + + # def _update_icon_tooltip(ind, lines_generator): + # pass + + + # def _update_icon_image(ind, image): + # if isinstance(image, GdkPixbuf.Pixbuf): + # pass + # else: + # ind.set_icon(image) + +except ImportError: + + def create(activate_callback, menu_activate_callback): + assert activate_callback + assert menu_activate_callback + + icon = Gtk.StatusIcon.new_from_icon_name(_icons.APP_ICON[0]) + icon.set_name(NAME) + icon.set_tooltip_text(NAME) + icon.connect('activate', activate_callback) + + _create_common(icon, menu_activate_callback) + icon.connect('popup_menu', + lambda icon, button, time, menu: + icon._menu.popup(None, None, icon.position_menu, icon, button, time), + icon._menu) + + return icon + + + def destroy(icon): + icon.set_visible(False) + + + def _update_icon_tooltip(icon, lines_generator): + tooltip_lines = lines_generator(icon) + icon.set_tooltip_markup('\n'.join(tooltip_lines).rstrip('\n')) + + + def _update_icon_image(icon, image): + if isinstance(image, GdkPixbuf.Pixbuf): + icon.set_from_pixbuf(image) + else: + icon.set_from_icon_name(image) # # @@ -94,48 +153,41 @@ def _icon_with_battery(level, active): return _PIXMAPS[name] -def _update_image(icon): - if not icon._receivers: - icon.set_from_icon_name(_icons.APP_ICON[-1]) - return + +def _generate_image(icon): + if not icon._devices_info: + return _icons.APP_ICON[-1] battery_status = None battery_level = 1000 for _, serial, name, status in icon._devices_info: + if serial is None: # is receiver + continue level = status.get(_status.BATTERY_LEVEL) if level is not None and level < battery_level: battery_status = status battery_level = level if battery_status is None: - icon.set_from_icon_name(_icons.APP_ICON[1]) + return _icons.APP_ICON[1] else: pixbuf = _icon_with_battery(battery_level, bool(battery_status)) if pixbuf: - icon.set_from_pixbuf(pixbuf) + return pixbuf else: - icon.set_from_icon_name(_icons.APP_ICON[1]) + return _icons.APP_ICON[1] # # # -def _device_index(icon, device): - if device.receiver.serial in icon._receivers: - for index, (rserial, serial, name, _) in enumerate(icon._devices_info): - if rserial == device.receiver.serial and serial == device.serial: - return index - - # print ("== device", device, device.receiver.serial, "not found in", icon._receivers, "/", icon._devices_info) - - def _add_device(icon, device): index = len(icon._devices_info) device_info = (device.receiver.serial, device.serial, device.name, device.status) icon._devices_info.append(device_info) - menu_item = Gtk.ImageMenuItem.new_with_label(device.name) + menu_item = Gtk.ImageMenuItem.new_with_label(' ' + device.name) icon._menu.insert(menu_item, index) menu_item.set_image(Gtk.Image()) menu_item.show_all() @@ -152,8 +204,20 @@ def _remove_device(icon, index): icon._menu.remove(menu_items[index]) +def _add_receiver(icon, receiver): + device_info = (receiver.serial, None, receiver.name, None) + icon._devices_info.insert(0, device_info) + + menu_item = Gtk.ImageMenuItem.new_with_label(receiver.name) + icon._menu.insert(menu_item, 0) + menu_item.set_image(Gtk.Image().new_from_icon_name(receiver.name, Gtk.IconSize.LARGE_TOOLBAR)) + menu_item.show_all() + menu_item.connect('activate', icon._menu_activate_callback, receiver.path, icon) + + return 0 + + def _remove_receiver(icon, receiver): - icon._receivers.remove(receiver.serial) index = 0 while index < len(icon._devices_info): rserial, _, _, _ = icon._devices_info[index] @@ -170,6 +234,7 @@ def _update_menu_item(icon, index, device_status): image = menu_item.get_image() battery_level = device_status.get(_status.BATTERY_LEVEL) + print ("device_status", dict(device_status), battery_level) image.set_from_icon_name(_icons.battery(battery_level), Gtk.IconSize.LARGE_TOOLBAR) image.set_sensitive(bool(device_status)) # menu_item.set_sensitive(bool(device_status)) @@ -186,12 +251,24 @@ def update(icon, device=None): # receiver receiver = device if receiver: - icon._receivers.add(receiver.serial) + index = None + for idx, (rserial, _, _, _) in enumerate(icon._devices_info): + if rserial == receiver.serial: + index = idx + break + + if index is None: + _add_receiver(icon, receiver) else: _remove_receiver(icon, receiver) + else: # peripheral - index = _device_index(icon, device) + index = None + for idx, (rserial, serial, name, _) in enumerate(icon._devices_info): + if rserial == device.receiver.serial and serial == device.serial: + index = idx + if device.status is None: # was just unpaired assert index is not None @@ -201,6 +278,8 @@ def update(icon, device=None): index = _add_device(icon, device) _update_menu_item(icon, index, device.status) - tooltip_lines = _generate_tooltip_lines(icon) - icon.set_tooltip_markup('\n'.join(tooltip_lines).rstrip('\n')) - _update_image(icon) + menu_items = icon._menu.get_children() + menu_items[len(icon._devices_info)].set_visible(not icon._devices_info) + + _update_icon_tooltip(icon, _generate_tooltip_lines) + _update_icon_image(icon, _generate_image(icon))