Beispiel #1
0
class SoundIcon(QObject, VolumeMixin, MediaKeysMixin):
    icon_updated = pyqtSignal(object)
    media_key_pressed = pyqtSignal(list)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.app = QApplication(sys.argv)
        self.app.setQuitOnLastWindowClosed(False)
        self.app.setApplicationName(APP_NAME)
        self.screen_height = self.app.primaryScreen().geometry().height()
        with open(LINUX_CSS, 'r') as css_file:
            self.app.setStyleSheet(css_file.read())
        self.mixer = PulseMixer()
        self.init_dbus()
        self.create_icon()
        self.mixer.start_listener(self.get_pulse_callback)
        self.icon_updated.connect(self.update_icon)
        self.create_menu()
        self.update_icon()
        self.init_keys()
        self.media_key_pressed.connect(self.on_media_key_pressed)

        self.run()

    def get_pulse_callback(self):
        return lambda e: self.icon_updated.emit(e)

    def get_notify_callback(self):
        return lambda k, t: self.media_key_pressed.emit([k, t])

    def create_icon(self):
        self.icon_name = ''
        self.icon = QSystemTrayIcon()
        self.icon.activated.connect(self.activate)
        self.icon.eventFilter = self.on_scroll
        self.icon.installEventFilter(self.icon)

    def create_menu(self):
        self.menu = QMenu()
        self.slider_item = SliderItem(self.menu)
        self.slider_item.value_changed.connect(self.on_value_changed)
        mixer_item = self.create_mixer()
        exit_item = self.create_exit()
        self.menu.addAction(self.slider_item)
        self.menu.addAction(mixer_item)
        self.menu.addSeparator()
        self.menu.addSeparator()
        self.menu.addAction(exit_item)

    def create_mixer(self):
        item = MenuItem(LABEL_MIXER, self.menu)
        item.triggered.connect(self.activate_mixer)
        return item

    def create_exit(self):
        item = MenuItem(LABEL_EXIT, self.menu)
        item.triggered.connect(self.activate_exit)
        return item

    def activate_exit(self, *args):
        os._exit(0)
        return True

    def on_value_changed(self, value):
        self.mixer.set_volume(value)
        return True

    def activate(self, reason):
        if reason == QSystemTrayIcon.Context:
            self.mixer.toggle_mute()
            return True
        if reason != QSystemTrayIcon.Trigger:
            return False
        self.update_menu()
        volume, mute = self.mixer.get_sink_volume_and_mute()
        self.slider_item.setValue(int(volume))
        self.slider_item.setEnabled(not mute)

        icon_pos = self.icon.geometry().bottomRight()
        width = min(self.menu.geometry().width(), VOLUME_WIDTH)
        if icon_pos.y() > self.screen_height / 2:
            pos = icon_pos - QPoint(width, 40)
            self.menu.popup(pos, self.menu.actions()[-1])
        else:
            pos = icon_pos - QPoint(width, 0)
            self.menu.popup(pos)
        return True

    def destroy_item(self, item):
        self.menu.removeAction(item)
        item.deleteLater()

    def insert_label_item(self, label, pos):
        item = MenuItem(label, self.menu)
        item.label.setProperty('objectName', 'section')
        before = self.menu.actions()[pos]
        self.menu.insertAction(before, item)
        item.setEnabled(False)
        self.profile_items.append(item)

    def insert_subaction_item(self, profile, link, pos):
        item = MenuItem(profile, self.menu)
        item.label.setProperty('objectName', 'subaction')
        item.triggered.connect(lambda c: self.mixer.set_profile(link))
        before = self.menu.actions()[pos]
        self.menu.insertAction(before, item)
        if link == self.mixer.current_profile:
            item.setEnabled(False)
        self.profile_items.append(item)

    def on_scroll(self, obj, event):
        if not isinstance(event, QWheelEvent):
            return False
        delta_y = event.angleDelta().y()
        if delta_y == 0:
            return
        change = SCROLL_BY if delta_y > 0 else -SCROLL_BY
        self.mixer.change_volume(change)
        return True

    def set_theme_icon(self, icon_name):
        qicon = QIcon.fromTheme(icon_name)
        self.icon.setIcon(qicon)

    def is_menu_visible(self):
        return self.menu.isVisible()

    def run(self):
        self.icon.show()
        sys.exit(self.app.exec_())