Skip to content

Commit

Permalink
Move status icon into separate blueman-tray appliction
Browse files Browse the repository at this point in the history
Instead of handling the icon itself, the StatusIcon plugin now only reveals the necessary information via D-Bus and the AppIndicator plugin only changes the implementation to use. blueman-tray uses that information to show a status icon using the requested implementation.
  • Loading branch information
cschramm committed Nov 24, 2017
1 parent db7d984 commit bf37750
Show file tree
Hide file tree
Showing 14 changed files with 281 additions and 119 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Makefile
/apps/blueman-rfcomm-watcher
/apps/blueman-sendto
/apps/blueman-services
/apps/blueman-tray
/blueman/Constants.py
/data/configs/blueman-applet.service
/data/configs/blueman-mechanism.service
Expand Down
5 changes: 3 additions & 2 deletions apps/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ APPS = \
blueman-services \
blueman-sendto \
blueman-assistant \
blueman-report

blueman-report \
blueman-tray

appsdir = $(bindir)
apps_SCRIPTS = $(APPS)

Expand Down
46 changes: 46 additions & 0 deletions apps/blueman-tray.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
# coding=utf-8

from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from __future__ import unicode_literals

import logging
import os
import sys
import signal

# support running uninstalled
_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if 'BLUEMAN_SOURCE' in os.environ:
sys.path.insert(0, _dirname)

from blueman.Functions import set_proc_title, create_parser, create_logger
from blueman.main.Tray import BluemanTray

# Workaround introspection bug, gnome bug 622084
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)

if __name__ == '__main__':
parser = create_parser()
args = parser.parse_args()

if args.LEVEL.upper() == "DEBUG":
log_level = logging.DEBUG
elif args.LEVEL.upper() == "INFO":
log_level = logging.INFO
elif args.LEVEL.upper() == "WARNING":
log_level = logging.WARNING
elif args.LEVEL.upper() == "ERROR":
log_level = logging.ERROR
elif args.LEVEL.upper() == "CRITICAL":
log_level = logging.CRITICAL
else:
log_level = logging.WARNING

create_logger(log_level, "blueman-tray", syslog=args.syslog)

set_proc_title()
BluemanTray()
5 changes: 3 additions & 2 deletions blueman/main/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SUBDIRS = applet
SUBDIRS = applet indicators

bluemandir = $(pythondir)/blueman/main

Expand All @@ -17,7 +17,8 @@ blueman_PYTHON = \
Applet.py \
Manager.py \
Sendto.py \
Services.py
Services.py \
Tray.py

if HAVE_PULSEAUDIO
blueman_PYTHON += PulseAudioUtils.py
Expand Down
51 changes: 51 additions & 0 deletions blueman/main/Tray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from importlib import import_module

import logging

from blueman.Functions import check_single_instance
from blueman.main.AppletService import AppletService

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, Gio


class BluemanTray(object):
def __init__(self):
check_single_instance("blueman-tray")

applet = AppletService()

main_loop = GLib.MainLoop()

Gio.bus_watch_name(Gio.BusType.SESSION, 'org.blueman.Applet',
Gio.BusNameWatcherFlags.NONE, None, lambda _connection, _name: main_loop.quit())

indicator_name = applet.GetStatusIconImplementation()
logging.info('Using indicator "%s"' % indicator_name)
indicator_class = getattr(import_module('blueman.main.indicators.' + indicator_name), indicator_name)
self.indicator = indicator_class(applet.GetIconName(), self._activate_menu_item, self._activate_status_icon)

applet.connect('g-signal', self.on_signal)

self.indicator.set_text(applet.GetText())
self.indicator.set_visibility(applet.GetVisibility())
self.indicator.set_menu(applet.GetMenu())

main_loop.run()

def _activate_menu_item(self, *indexes):
return AppletService().ActivateMenuItem('(ai)', indexes)

def _activate_status_icon(self):
return AppletService().Activate()

def on_signal(self, _applet, sender_name, signal_name, args):
if signal_name == 'IconNameChanged':
self.indicator.set_icon(*args)
elif signal_name == 'TextChanged':
self.indicator.set_text(*args)
elif signal_name == 'VisibilityChanged':
self.indicator.set_visibility(*args)
elif signal_name == 'MenuChanged':
self.indicator.set_menu(*args)
34 changes: 34 additions & 0 deletions blueman/main/indicators/AppIndicator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# coding=utf-8
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from __future__ import unicode_literals

import gi

gi.require_version('AppIndicator3', '0.1')
from gi.repository import AppIndicator3
from blueman.main.indicators.GtkStatusIcon import build_menu


class AppIndicator(object):
def __init__(self, icon_name, on_activate_menu_item, _on_activate_status_icon):
self._on_activate = on_activate_menu_item
self.indicator = AppIndicator3.Indicator.new('blueman', icon_name,
AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)

def set_icon(self, icon_name):
self.indicator.set_icon(icon_name)
self.indicator.set_status(AppIndicator3.IndicatorStatus.ATTENTION)
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)

def set_text(self, text):
self.indicator.props.title = text

def set_visibility(self, visible):
status = AppIndicator3.IndicatorStatus.ACTIVE if visible else AppIndicator3.IndicatorStatus.PASSIVE
self.indicator.set_status(status)

def set_menu(self, menu):
self.indicator.set_menu(build_menu(menu, self._on_activate))
60 changes: 60 additions & 0 deletions blueman/main/indicators/GtkStatusIcon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# coding=utf-8
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from __future__ import unicode_literals

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, GObject
from blueman.Functions import create_menuitem


def build_menu(items, activate):
menu = Gtk.Menu()
for index, item in enumerate(items):
if 'text' in item and 'icon_name' in item:
gtk_item = create_menuitem(item['text'], item['icon_name'])
label = gtk_item.get_child()
if item['markup']:
label.set_markup_with_mnemonic(item['text'])
else:
label.set_text_with_mnemonic(item['text'])
gtk_item.connect('activate', lambda _, idx=index: activate(idx))
if 'submenu' in item:
gtk_item.set_submenu(build_menu(item['submenu'], lambda subid, idx=index: activate(idx, subid)))
if 'tooltip' in item:
gtk_item.props.tooltip_text = item['tooltip']
gtk_item.props.sensitive = item['sensitive']
else:
gtk_item = Gtk.SeparatorMenuItem()
gtk_item.show()
menu.append(gtk_item)
return menu


class GtkStatusIcon(object):
def __init__(self, icon_name, on_activate_menu_item, on_activate_status_icon):
self._on_activate = on_activate_menu_item
self.indicator = Gtk.StatusIcon(icon_name=icon_name)
self.indicator.set_title('blueman')
self.indicator.connect('popup-menu', self.on_popup_menu)
self.indicator.connect('activate', lambda _status_icon: on_activate_status_icon())
self._menu = None

def on_popup_menu(self, status_icon, button, activate_time):
if self._menu:
self._menu.popup(None, None, Gtk.StatusIcon.position_menu, status_icon, button, activate_time)

def set_icon(self, icon_name):
self.indicator.props.icon_name = icon_name

def set_text(self, text):
self.indicator.props.tooltip_markup = text

def set_visibility(self, visible):
self.indicator.props.visible = visible

def set_menu(self, menu):
self._menu = build_menu(menu, self._on_activate)
15 changes: 15 additions & 0 deletions blueman/main/indicators/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
bluemandir = $(pythondir)/blueman/main/indicators
blueman_PYTHON = \
__init__.py \
AppIndicator.py \
GtkStatusIcon.py

CLEANFILES = \
$(BUILT_SOURCES)

DISTCLEANFILES = \
$(CLEANFILES)

clean-local:
rm -rf *.pyc *.pyo

Empty file.
44 changes: 3 additions & 41 deletions blueman/plugins/applet/AppIndicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,7 @@ class AppIndicator(AppletPlugin):
__description__ = _("Uses libappindicator to show a statusicon")
__icon__ = "blueman-tray"
__author__ = "Walmis"
__depends__ = ["StatusIcon", "Menu"]

def on_load(self, applet):

self.indicator = girAppIndicator.Indicator.new("blueman",
self.Applet.Plugins.StatusIcon.props.icon_name,
girAppIndicator.IndicatorCategory.APPLICATION_STATUS)

self.indicator.set_status(girAppIndicator.IndicatorStatus.ACTIVE)

self.indicator.set_menu(applet.Plugins.Menu.get_menu())

self.s = self.Applet.Plugins.StatusIcon.connect("notify::icon-name", self.on_notify)
__depends__ = ['StatusIcon']

self.override_method(self.Applet.Plugins.StatusIcon, "set_visible", self.set_visible)
self.override_method(self.Applet.Plugins.StatusIcon, "update_tooltip", self.update_title)

self.Applet.Plugins.StatusIcon.props.visible = False
self.Applet.Plugins.StatusIcon.update_text()

def update_title(self, _, text):
self.indicator.set_title(text)

def set_visible(self, _, visible):
if visible:
self.indicator.set_status(girAppIndicator.IndicatorStatus.ACTIVE)
else:
self.indicator.set_status(girAppIndicator.IndicatorStatus.PASSIVE)

def on_notify(self, *args):
self.update_icon()

def on_unload(self):
del self.indicator
self.Applet.Plugins.StatusIcon.QueryVisibility()
self.Applet.Plugins.StatusIcon.disconnect(self.s)
self.Applet.Plugins.StatusIcon.update_text()

def update_icon(self):
self.indicator.set_icon(self.Applet.Plugins.StatusIcon.props.icon_name)
self.indicator.set_status(girAppIndicator.IndicatorStatus.ATTENTION)
self.indicator.set_status(girAppIndicator.IndicatorStatus.ACTIVE)
def on_query_status_icon_implementation(self):
return 'AppIndicator'
32 changes: 0 additions & 32 deletions blueman/plugins/applet/Menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,10 @@

import dbus
import dbus.service
from blueman.Functions import create_menuitem

from blueman.plugins.AppletPlugin import AppletPlugin
from operator import attrgetter

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk


def build_menu(items, activate):
menu = Gtk.Menu()
for index, item in enumerate(items):
if 'text' in item and 'icon_name' in item:
gtk_item = create_menuitem(item['text'], item['icon_name'])
label = gtk_item.get_child().get_children()[1]
if item['markup']:
label.set_markup_with_mnemonic(item['text'])
else:
label.set_text_with_mnemonic(item['text'])
gtk_item.connect('activate', lambda _, idx=index: activate(idx))
if 'submenu' in item:
gtk_item.set_submenu(item['submenu'])
if 'tooltip' in item:
gtk_item.props.tooltip_text = item['tooltip']
gtk_item.props.sensitive = item['sensitive']
else:
gtk_item = Gtk.SeparatorMenuItem()
gtk_item.show()
menu.append(gtk_item)
return menu


class MenuItem(object):
def __init__(self, menu_plugin, owner, priority, text, markup, icon_name, tooltip, callback, submenu_function,
Expand Down Expand Up @@ -114,7 +86,6 @@ def set_sensitive(self, sensitive):


class Menu(AppletPlugin):
__depends__ = ["StatusIcon"]
__description__ = _("Provides a menu for the applet and an API for other plugins to manipulate it")
__icon__ = "menu-editor"
__author__ = "Walmis"
Expand Down Expand Up @@ -150,9 +121,6 @@ def on_plugins_loaded(self):
self.__plugins_loaded = True
self.__sort()

def get_menu(self):
return build_menu(self.GetMenu(), self.ActivateMenuItem)

def on_menu_changed(self):
self.MenuChanged(self.GetMenu())

Expand Down
2 changes: 1 addition & 1 deletion blueman/plugins/applet/StandardItems.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def on_load(self, applet):

self.Applet.Plugins.Menu.add(self, 85, text=_("_Plugins"), icon_name="blueman-plugin", callback=self.on_plugins)

self.Applet.Plugins.StatusIcon.connect("activate", lambda status_icon: self.on_devices(None))
self.Applet.Plugins.StatusIcon.connect("activate", lambda _status_icon: self.on_devices())

def change_sensitivity(self, sensitive):
try:
Expand Down
Loading

0 comments on commit bf37750

Please sign in to comment.