# # # from gi.repository import Gtk from gi.repository import Gdk from logitech.devices import constants as C _DEVICE_ICON_SIZE = Gtk.IconSize.DIALOG _STATUS_ICON_SIZE = Gtk.IconSize.DIALOG _PLACEHOLDER = '~' _MAX_DEVICES = 6 def _update_receiver_box(box, receiver): icon, vbox = box.get_children() label, buttons_box = vbox.get_children() label.set_text(receiver.text or '') buttons_box.set_visible(receiver.code >= C.STATUS.CONNECTED) def _update_device_box(frame, devstatus): frame.set_visible(devstatus is not None) box = frame.get_child() icon, expander = box.get_children() if devstatus: if icon.get_name() != devstatus.name: icon.set_name(devstatus.name) icon.set_from_icon_name(devstatus.name, _DEVICE_ICON_SIZE) if devstatus.code < C.STATUS.CONNECTED: expander.set_sensitive(False) expander.set_expanded(False) expander.set_label('%s\n%s' % (devstatus.name, devstatus.text)) else: expander.set_sensitive(True) ebox = expander.get_child() texts = [] light_icon = ebox.get_children()[-2] light_level = getattr(devstatus, C.PROPS.LIGHT_LEVEL, None) light_icon.set_visible(light_level is not None) if light_level is not None: texts.append('Light: %d lux' % light_level) icon_name = 'light_%02d' % (20 * ((light_level + 50) // 100)) light_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE) light_icon.set_tooltip_text(texts[-1]) battery_icon = ebox.get_children()[-1] battery_level = getattr(devstatus, C.PROPS.BATTERY_LEVEL, None) battery_icon.set_sensitive(battery_level is not None) if battery_level is None: battery_icon.set_from_icon_name('battery_unknown', _STATUS_ICON_SIZE) battery_icon.set_tooltip_text('Battery: unknown') else: texts.append('Battery: %d%%' % battery_level) icon_name = 'battery_%02d' % (20 * ((battery_level + 10) // 20)) battery_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE) battery_icon.set_tooltip_text(texts[-1]) battery_status = getattr(devstatus, C.PROPS.BATTERY_STATUS, None) if battery_status is not None: texts.append(battery_status) battery_icon.set_tooltip_text(battery_icon.get_tooltip_text() + '\n' + battery_status) if texts: expander.set_label('%s\n%s' % (devstatus.name, ', '.join(texts))) else: expander.set_label('%s\n%s' % (devstatus.name, devstatus.text)) else: icon.set_name(_PLACEHOLDER) expander.set_label(_PLACEHOLDER) def update(window, receiver, devices): if window and window.get_child(): controls = list(window.get_child().get_children()) _update_receiver_box(controls[0], receiver) for index in range(1, 1 + _MAX_DEVICES): _update_device_box(controls[index], devices.get(index)) def _receiver_box(rstatus): box = Gtk.HBox(homogeneous=False, spacing=8) box.set_border_width(8) icon = Gtk.Image.new_from_icon_name(rstatus.name, _DEVICE_ICON_SIZE) icon.set_alignment(0.5, 0) icon.set_name(rstatus.name) box.pack_start(icon, False, False, 0) vbox = Gtk.VBox(homogeneous=False, spacing=4) box.pack_start(vbox, True, True, 0) label = Gtk.Label() label.set_can_focus(False) label.set_alignment(0, 0) vbox.pack_start(label, False, False, 0) buttons_box = Gtk.HButtonBox() buttons_box.set_spacing(8) buttons_box.set_layout(Gtk.ButtonBoxStyle.START) vbox.pack_start(buttons_box, True, True, 0) def _action(button, action): button.set_sensitive(False) action() button.set_sensitive(True) def _add_button(name, icon, action): button = Gtk.Button(name.split(' ')[0]) button.set_image(Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON)) button.set_relief(Gtk.ReliefStyle.HALF) button.set_tooltip_text(name) button.set_focus_on_click(False) if action: button.connect('clicked', _action, action) else: button.set_sensitive(False) buttons_box.pack_start(button, False, False, 0) _add_button('Scan for devices', 'reload', rstatus.refresh) _add_button('Pair new device', 'add', rstatus.pair) box.show_all() return box def _device_box(): icon = Gtk.Image() icon.set_alignment(0.5, 0) icon.set_name(_PLACEHOLDER) box = Gtk.HBox(homogeneous=False, spacing=8) box.pack_start(icon, False, False, 0) box.set_border_width(8) expander = Gtk.Expander() expander.set_can_focus(False) expander.set_label(_PLACEHOLDER) expander.set_use_markup(True) expander.set_spacing(4) ebox = Gtk.HBox(False, 8) battery_icon = Gtk.Image.new_from_icon_name('battery_unknown', _STATUS_ICON_SIZE) ebox.pack_end(battery_icon, False, True, 0) light_icon = Gtk.Image.new_from_icon_name('light_unknown', _STATUS_ICON_SIZE) ebox.pack_end(light_icon, False, True, 0) expander.add(ebox) box.pack_start(expander, True, True, 1) frame = Gtk.Frame() frame.add(box) frame.show_all() frame.set_visible(False) return frame def create(title, rstatus, show=True, close_to_tray=False): window = Gtk.Window() Gtk.Window.set_default_icon_name('mouse') window.set_icon_name(title) window.set_title(title) window.set_keep_above(True) window.set_deletable(False) window.set_resizable(False) window.set_size_request(200, 50) window.set_default_size(200, 50) window.set_position(Gtk.WindowPosition.MOUSE) window.set_type_hint(Gdk.WindowTypeHint.UTILITY) # window.set_skip_taskbar_hint(True) # window.set_skip_pager_hint(True) # window.set_wmclass(title, 'status-window') # window.set_role('status-window') vbox = Gtk.VBox(homogeneous=False, spacing=4) vbox.set_border_width(4) vbox.add(_receiver_box(rstatus)) for i in range(1, 1 + _MAX_DEVICES): vbox.add(_device_box()) vbox.set_visible(True) window.add(vbox) if close_to_tray: def _state_event(window, event): if event.new_window_state & Gdk.WindowState.ICONIFIED: position = window.get_position() window.hide() window.deiconify() window.move(*position) return True window.connect('window-state-event', _state_event) window.connect('delete-event', lambda w, e: toggle(None, window) or True) else: window.connect('delete-event', Gtk.main_quit) if show: window.present() return window def toggle(_, window): if window.get_visible(): position = window.get_position() window.hide() window.move(*position) else: window.present()