better battery icon in the systray
This commit is contained in:
		
							parent
							
								
									d6b18cd426
								
							
						
					
					
						commit
						932a015e49
					
				|  | @ -77,29 +77,39 @@ class ReceiverListener(_lur.listener.EventsListener): | ||||||
| 			self.receiver.close() | 			self.receiver.close() | ||||||
| 
 | 
 | ||||||
| 		self.receiver = None | 		self.receiver = None | ||||||
| 		self._status_changed(DUMMY, _lur.status.ALERT.LOW) | 		self._status_changed(None, alert=_lur.status.ALERT.LOW) | ||||||
| 
 | 
 | ||||||
| 	def tick(self, timestamp): | 	def tick(self, timestamp): | ||||||
| 		if _log.isEnabledFor(_DEBUG): | 		if _log.isEnabledFor(_DEBUG): | ||||||
| 			_log.debug("tick: polling status") | 			_log.debug("tick: polling status") | ||||||
|  | 
 | ||||||
|  | 		# read these in case they haven't been read already | ||||||
|  | 		self.receiver.serial, self.receiver.firmware | ||||||
|  | 
 | ||||||
|  | 		if self.receiver.status.lock_open: | ||||||
|  | 			# don't mess with stuff while pairing | ||||||
|  | 			return | ||||||
|  | 
 | ||||||
| 		for dev in self.receiver: | 		for dev in self.receiver: | ||||||
| 			if dev.status: | 			if dev.status: | ||||||
| 				dev.serial, dev.firmware | 				# read these in case they haven't been read already | ||||||
|  | 				dev.wpid, dev.serial, dev.protocol, dev.firmware | ||||||
|  | 
 | ||||||
| 				if dev.status.get(_lur.status.BATTERY_LEVEL) is None: | 				if dev.status.get(_lur.status.BATTERY_LEVEL) is None: | ||||||
| 					battery = _lur.hidpp20.get_battery(dev) or _lur.hidpp10.get_battery(dev) | 					battery = _lur.hidpp20.get_battery(dev) or _lur.hidpp10.get_battery(dev) | ||||||
| 					if battery: | 					if battery: | ||||||
| 						dev.status[_lur.status.BATTERY_LEVEL], dev.status[_lur.status.BATTERY_STATUS] = battery | 						dev.status[_lur.status.BATTERY_LEVEL], dev.status[_lur.status.BATTERY_STATUS] = battery | ||||||
| 						self._status_changed(dev) | 						self._status_changed(dev) | ||||||
|  | 
 | ||||||
| 			elif len(dev.status) > 0 and timestamp - dev.status.updated > _DEVICE_TIMEOUT: | 			elif len(dev.status) > 0 and timestamp - dev.status.updated > _DEVICE_TIMEOUT: | ||||||
| 				dev.status.clear() | 				dev.status.clear() | ||||||
| 				self._status_changed(dev, _lur.status.ALERT.LOW) | 				self._status_changed(dev, _lur.status.ALERT.LOW) | ||||||
| 
 | 
 | ||||||
| 	def _status_changed(self, device, alert=_lur.status.ALERT.NONE, reason=None): | 	def _status_changed(self, device, alert=_lur.status.ALERT.NONE, reason=None): | ||||||
| 		assert device is not None |  | ||||||
| 		if _log.isEnabledFor(_DEBUG): | 		if _log.isEnabledFor(_DEBUG): | ||||||
| 			_log.debug("status_changed %s: %s (%X) %s", device, device.status, alert, reason or '') | 			_log.debug("status_changed %s: %s (%X) %s", device, None if device is None else device.status, alert, reason or '') | ||||||
| 		if self.status_changed_callback: | 		if self.status_changed_callback: | ||||||
| 			if device is self.receiver: | 			if device is None or device is self.receiver: | ||||||
| 				self.status_changed_callback(self.receiver or DUMMY, None, alert, reason) | 				self.status_changed_callback(self.receiver or DUMMY, None, alert, reason) | ||||||
| 			else: | 			else: | ||||||
| 				self.status_changed_callback(self.receiver or DUMMY, device, alert, reason) | 				self.status_changed_callback(self.receiver or DUMMY, device, alert, reason) | ||||||
|  | @ -133,6 +143,7 @@ class ReceiverListener(_lur.listener.EventsListener): | ||||||
| 		receiver = _lur.Receiver.open() | 		receiver = _lur.Receiver.open() | ||||||
| 		if receiver: | 		if receiver: | ||||||
| 			receiver.handle = _lur.listener.ThreadedHandle(receiver.handle, receiver.path) | 			receiver.handle = _lur.listener.ThreadedHandle(receiver.handle, receiver.path) | ||||||
|  | 			receiver.kind = 'applications-system' | ||||||
| 			rl = ReceiverListener(receiver, status_changed_callback) | 			rl = ReceiverListener(receiver, status_changed_callback) | ||||||
| 			rl.start() | 			rl.start() | ||||||
| 			return rl | 			return rl | ||||||
|  |  | ||||||
|  | @ -9,15 +9,17 @@ GObject.threads_init() | ||||||
| from solaar import NAME | from solaar import NAME | ||||||
| _APP_ICONS = (NAME + '-init', NAME + '-fail', NAME) | _APP_ICONS = (NAME + '-init', NAME + '-fail', NAME) | ||||||
| def appicon(receiver_status): | def appicon(receiver_status): | ||||||
| 	return (_APP_ICONS[1] if type(receiver_status) == str else | 	return (_APP_ICONS[1] if type(receiver_status) == str | ||||||
| 			_APP_ICONS[2] if receiver_status else | 			else _APP_ICONS[2] if receiver_status | ||||||
| 			_APP_ICONS[0]) | 			else _APP_ICONS[0]) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| _ICON_THEME = Gtk.IconTheme.get_default() |  | ||||||
| 
 | 
 | ||||||
| def get_icon(name, fallback): | def get_icon(name, *fallback): | ||||||
| 	return name if name and _ICON_THEME.has_icon(name) else fallback | 	theme = Gtk.IconTheme.get_default() | ||||||
|  | 	return (str(name) if name and theme.has_icon(str(name)) | ||||||
|  | 			else get_icon(*fallback) if fallback | ||||||
|  | 			else None) | ||||||
| 
 | 
 | ||||||
| def get_battery_icon(level): | def get_battery_icon(level): | ||||||
| 	if level < 0: | 	if level < 0: | ||||||
|  | @ -25,9 +27,9 @@ def get_battery_icon(level): | ||||||
| 	return 'battery_%03d' % (10 * ((level + 5) // 10)) | 	return 'battery_%03d' % (10 * ((level + 5) // 10)) | ||||||
| 
 | 
 | ||||||
| def icon_file(name): | def icon_file(name): | ||||||
| 	if name and _ICON_THEME.has_icon(name): | 	theme = Gtk.IconTheme.get_default() | ||||||
| 		return _ICON_THEME.lookup_icon(name, 0, 0).get_filename() | 	return (theme.lookup_icon(str(name), 0, 0).get_filename() if name and theme.has_icon(str(name)) | ||||||
| 	return None | 			else None) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def error(window, title, text): | def error(window, title, text): | ||||||
|  |  | ||||||
|  | @ -89,7 +89,7 @@ def _make_device_box(index): | ||||||
| 	label.set_alignment(0, 0.5) | 	label.set_alignment(0, 0.5) | ||||||
| 	label.set_padding(4, 4) | 	label.set_padding(4, 4) | ||||||
| 
 | 
 | ||||||
| 	battery_icon = Gtk.Image.new_from_icon_name('battery_unknown', _STATUS_ICON_SIZE) | 	battery_icon = Gtk.Image.new_from_icon_name(ui.get_battery_icon(-1), _STATUS_ICON_SIZE) | ||||||
| 
 | 
 | ||||||
| 	battery_label = Gtk.Label() | 	battery_label = Gtk.Label() | ||||||
| 	battery_label.set_width_chars(6) | 	battery_label.set_width_chars(6) | ||||||
|  | @ -186,6 +186,7 @@ def create(title, name, max_devices, systray=False): | ||||||
| 	vbox.set_visible(True) | 	vbox.set_visible(True) | ||||||
| 
 | 
 | ||||||
| 	window.add(vbox) | 	window.add(vbox) | ||||||
|  | 	window._vbox = vbox | ||||||
| 
 | 
 | ||||||
| 	geometry = Gdk.Geometry() | 	geometry = Gdk.Geometry() | ||||||
| 	geometry.min_width = 320 | 	geometry.min_width = 320 | ||||||
|  | @ -198,6 +199,10 @@ def create(title, name, max_devices, systray=False): | ||||||
| 
 | 
 | ||||||
| 	if systray: | 	if systray: | ||||||
| 		window.set_keep_above(True) | 		window.set_keep_above(True) | ||||||
|  | 		# window.set_decorated(False) | ||||||
|  | 		# window.set_type_hint(Gdk.WindowTypeHint.TOOLTIP) | ||||||
|  | 		# window.set_skip_taskbar_hint(True) | ||||||
|  | 		# window.set_skip_pager_hint(True) | ||||||
| 		window.connect('delete-event', toggle) | 		window.connect('delete-event', toggle) | ||||||
| 	else: | 	else: | ||||||
| 		window.connect('delete-event', Gtk.main_quit) | 		window.connect('delete-event', Gtk.main_quit) | ||||||
|  | @ -248,14 +253,14 @@ def _update_device_info_label(label, dev): | ||||||
| 		if firmware: | 		if firmware: | ||||||
| 			items += [(f.kind, f.name + ' ' + f.version) for f in firmware] | 			items += [(f.kind, f.name + ' ' + f.version) for f in firmware] | ||||||
| 
 | 
 | ||||||
| 		label.set_markup('<small><tt>%s</tt></small>' % '\n'.join('%-12s: %s' % (item[0], str(item[1])) for item in items)) | 		label.set_markup('<small><tt>' + '\n'.join('%-12s: %s' % item for item in items) + '</tt></small>') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _update_receiver_info_label(label, dev): | def _update_receiver_info_label(label, dev): | ||||||
| 	if label.get_visible() and '\n' not in label.get_text(): | 	if label.get_visible() and '\n' not in label.get_text(): | ||||||
| 		items = [('Serial', dev.serial)] + \ | 		items = [('Serial', dev.serial)] + \ | ||||||
| 				[(f.kind, f.version) for f in dev.firmware] | 				[(f.kind, f.version) for f in dev.firmware] | ||||||
| 		label.set_markup('<small><tt>%s</tt></small>' % '\n'.join('%-10s: %s' % (item[0], str(item[1])) for item in items)) | 		label.set_markup('<small><tt>' + '\n'.join('%-10s: %s' % item for item in items) + '</tt></small>') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _toggle_info_box(action, label_widget, box_widget, frame, update_function): | def _toggle_info_box(action, label_widget, box_widget, frame, update_function): | ||||||
|  | @ -319,7 +324,7 @@ def _update_device_box(frame, dev): | ||||||
| 
 | 
 | ||||||
| 		if battery_level is None: | 		if battery_level is None: | ||||||
| 			battery_icon.set_sensitive(False) | 			battery_icon.set_sensitive(False) | ||||||
| 			battery_icon.set_from_icon_name('battery_unknown', _STATUS_ICON_SIZE) | 			battery_icon.set_from_icon_name(ui.get_battery_icon(-1), _STATUS_ICON_SIZE) | ||||||
| 			text = 'no status' if dev.protocol < 2.0 else 'waiting for status...' | 			text = 'no status' if dev.protocol < 2.0 else 'waiting for status...' | ||||||
| 			battery_label.set_markup('<small>%s</small>' % text) | 			battery_label.set_markup('<small>%s</small>' % text) | ||||||
| 			battery_label.set_sensitive(True) | 			battery_label.set_sensitive(True) | ||||||
|  | @ -355,8 +360,9 @@ def update(window, receiver, device=None): | ||||||
| 	assert receiver is not None | 	assert receiver is not None | ||||||
| 	window.set_icon_name(ui.appicon(receiver.status)) | 	window.set_icon_name(ui.appicon(receiver.status)) | ||||||
| 
 | 
 | ||||||
| 	vbox = window.get_child() | 	vbox = window._vbox | ||||||
| 	frames = list(vbox.get_children()) | 	frames = list(vbox.get_children()) | ||||||
|  | 	assert len(frames) == 1 + receiver.max_devices, frames | ||||||
| 
 | 
 | ||||||
| 	if device is None: | 	if device is None: | ||||||
| 		_update_receiver_box(frames[0], receiver) | 		_update_receiver_box(frames[0], receiver) | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ try: | ||||||
| 
 | 
 | ||||||
| 			message = reason or ('unpaired' if dev.status is None else | 			message = reason or ('unpaired' if dev.status is None else | ||||||
| 						(str(dev.status) or ('connected' if dev.status else 'inactive'))) | 						(str(dev.status) or ('connected' if dev.status else 'inactive'))) | ||||||
| 			n.update(summary, message, _icon(summary) or dev.kind) | 			n.update(summary, message, _icon(summary) or str(dev.kind)) | ||||||
| 			urgency = Notify.Urgency.LOW if dev.status else Notify.Urgency.NORMAL | 			urgency = Notify.Urgency.LOW if dev.status else Notify.Urgency.NORMAL | ||||||
| 			n.set_urgency(urgency) | 			n.set_urgency(urgency) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,18 +2,20 @@ | ||||||
| # | # | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| from gi.repository import Gtk | from gi.repository import Gtk, GdkPixbuf | ||||||
| 
 | 
 | ||||||
| import ui | import ui | ||||||
| from logitech.unifying_receiver import status as _status | from logitech.unifying_receiver import status as _status | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def create(window, menu_actions=None): | def create(window, menu_actions=None): | ||||||
|  | 	name = window.get_title() | ||||||
| 	icon = Gtk.StatusIcon() | 	icon = Gtk.StatusIcon() | ||||||
| 	icon.set_title(window.get_title()) | 	icon.set_title(name) | ||||||
| 	icon.set_name(window.get_title()) | 	icon.set_name(name) | ||||||
| 	icon.set_from_icon_name(ui.appicon(0)) | 	icon.set_from_icon_name(ui.appicon(False)) | ||||||
| 
 | 
 | ||||||
|  | 	icon.set_tooltip_text(name) | ||||||
| 	icon.connect('activate', window.toggle_visible) | 	icon.connect('activate', window.toggle_visible) | ||||||
| 
 | 
 | ||||||
| 	menu = Gtk.Menu() | 	menu = Gtk.Menu() | ||||||
|  | @ -66,4 +68,15 @@ def update(icon, receiver, device=None): | ||||||
| 	if battery_level is None: | 	if battery_level is None: | ||||||
| 		icon.set_from_icon_name(ui.appicon(receiver.status)) | 		icon.set_from_icon_name(ui.appicon(receiver.status)) | ||||||
| 	else: | 	else: | ||||||
| 		icon.set_from_icon_name(ui.get_battery_icon(battery_level)) | 		appicon = ui.icon_file(ui.appicon(True) + '-mask') | ||||||
|  | 		assert appicon | ||||||
|  | 		pbuf = GdkPixbuf.Pixbuf.new_from_file(appicon) | ||||||
|  | 		assert pbuf.get_width() == 128 and pbuf.get_height() == 128 | ||||||
|  | 
 | ||||||
|  | 		baticon = ui.icon_file(ui.get_battery_icon(battery_level)) | ||||||
|  | 		assert baticon | ||||||
|  | 		pbuf2 = GdkPixbuf.Pixbuf.new_from_file(baticon) | ||||||
|  | 		assert pbuf2.get_width() == 128 and pbuf2.get_height() == 128 | ||||||
|  | 
 | ||||||
|  | 		pbuf2.composite(pbuf, 0, 7, 80, 121, -32, 7, 1, 1, GdkPixbuf.InterpType.NEAREST, 255) | ||||||
|  | 		icon.set_from_pixbuf(pbuf) | ||||||
|  |  | ||||||
|  | @ -109,7 +109,7 @@ def close(handle): | ||||||
| 			# _log.info("closed receiver handle %s", repr(handle)) | 			# _log.info("closed receiver handle %s", repr(handle)) | ||||||
| 			return True | 			return True | ||||||
| 		except: | 		except: | ||||||
| 			_log.exception("closing receiver handle %s", repr(handle)) | 			# _log.exception("closing receiver handle %s", repr(handle)) | ||||||
| 			pass | 			pass | ||||||
| 
 | 
 | ||||||
| 	return False | 	return False | ||||||
|  |  | ||||||
|  | @ -129,7 +129,8 @@ class EventsListener(_threading.Thread): | ||||||
| 				event = self._queued_events.get() | 				event = self._queued_events.get() | ||||||
| 
 | 
 | ||||||
| 			if event: | 			if event: | ||||||
| 				_log.debug("processing event %s", event) | 				# if _log.isEnabledFor(_DEBUG): | ||||||
|  | 				# 	_log.debug("processing event %s", event) | ||||||
| 				try: | 				try: | ||||||
| 					self._events_callback(event) | 					self._events_callback(event) | ||||||
| 				except: | 				except: | ||||||
|  | @ -164,7 +165,7 @@ class EventsListener(_threading.Thread): | ||||||
| 	def _events_hook(self, event): | 	def _events_hook(self, event): | ||||||
| 		# only consider unhandled events that were sent from this thread, | 		# only consider unhandled events that were sent from this thread, | ||||||
| 		# i.e. triggered during a callback of a previous event | 		# i.e. triggered during a callback of a previous event | ||||||
| 		if _threading.current_thread() == self: | 		if self._active and _threading.current_thread() == self: | ||||||
| 			_log.info("queueing unhandled event %s", event) | 			_log.info("queueing unhandled event %s", event) | ||||||
| 			self._queued_events.put(event) | 			self._queued_events.put(event) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -107,8 +107,8 @@ class DeviceStatus(dict): | ||||||
| 		if self.updated == 0: | 		if self.updated == 0: | ||||||
| 			alert |= ALERT.LOW | 			alert |= ALERT.LOW | ||||||
| 		self.updated = _timestamp() | 		self.updated = _timestamp() | ||||||
| 		if _log.isEnabledFor(_DEBUG): | 		# if _log.isEnabledFor(_DEBUG): | ||||||
| 			_log.debug("device %d changed: active=%s %s", self._device.number, self._active, dict(self)) | 		# 	_log.debug("device %d changed: active=%s %s", self._device.number, self._active, dict(self)) | ||||||
| 		self._changed_callback(self._device, alert, reason) | 		self._changed_callback(self._device, alert, reason) | ||||||
| 
 | 
 | ||||||
| 	# @property | 	# @property | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 803 B | 
		Loading…
	
		Reference in New Issue