diff --git a/gajim/common/app.py b/gajim/common/app.py index 010117a36..0c8822bb2 100644 --- a/gajim/common/app.py +++ b/gajim/common/app.py @@ -231,6 +231,13 @@ try: except (ImportError, ValueError): HAVE_FARSTREAM = False +HAVE_GEOCLUE = True +try: + gi.require_version('Geoclue', '2.0') + from gi.repository import Geoclue +except (ImportError, ValueError): + HAVE_GEOCLUE = False + HAVE_UPNP_IGD = True try: gi.require_version('GUPnPIgd', '1.0') diff --git a/gajim/common/location_listener.py b/gajim/common/location_listener.py index 10afafa4d..a70dc0e9e 100644 --- a/gajim/common/location_listener.py +++ b/gajim/common/location_listener.py @@ -19,14 +19,21 @@ ## from datetime import datetime +import logging from gajim.common import app -from gajim.common import dbus_support -if dbus_support.supported: - import dbus + +import gi +gi.require_version('Geoclue', '2.0') +from gi.repository import Geoclue +from gi.repository import GLib + +log = logging.getLogger('gajim.c.location_listener') + class LocationListener: _instance = None + @classmethod def get(cls): if cls._instance is None: @@ -36,89 +43,41 @@ class LocationListener: def __init__(self): self._data = {} - def get_data(self): - bus = dbus.SessionBus() + def _on_location_update(self, simple): + location = simple.get_location() + timestamp = location.get_property("timestamp")[0] + lat = location.get_property("latitude") + lon = location.get_property("longitude") + alt = location.get_property("altitude") + # in XEP-0080 it's horizontal accuracy + acc = location.get_property("accuracy") + + # update data with info we just received + self._data = {'lat': lat, 'lon': lon, 'alt': alt, 'accuracy': acc} + self._data['timestamp'] = self._timestamp_to_utc(timestamp) + self._send_location() + + def _on_simple_ready(self, obj, result): try: - # Initializes Geoclue. - obj = bus.get_object('org.freedesktop.Geoclue.Master', - '/org/freedesktop/Geoclue/Master') - # get MasterClient path - path = obj.Create() - # get MasterClient - cli = bus.get_object('org.freedesktop.Geoclue.Master', path) - cli.SetRequirements(1, 0, True, 1023) - - self._get_address(cli) - self._get_position(cli) - except: - self._on_geoclue_position_changed() - return - + self.simple = Geoclue.Simple.new_finish(result) + except GLib.Error as e: + if e.domain == 'g-dbus-error-quark': + log.warning("Could not enable geolocation: %s", e.message) + else: + raise + else: + self.simple.connect('notify::location', self._on_location_update) + self._on_location_update(self.simple) - def _get_address(self, cli): - bus = dbus.SessionBus() - cli.AddressStart() - # Check that there is a provider - name, description, service, path = cli.GetAddressProvider() - if path: - provider = bus.get_object(service, path) - timestamp, address, accuracy = provider.GetAddress() - self._on_geoclue_address_changed(timestamp, address, accuracy) - - def _get_position(self, cli): - bus = dbus.SessionBus() - cli.PositionStart() - # Check that there is a provider - name, description, service, path = cli.GetPositionProvider() - if path: - provider = bus.get_object(service, path) - fields, timestamp, lat, lon, alt, accuracy = provider.GetPosition() - self._on_geoclue_position_changed(fields, timestamp, lat, lon, alt, - accuracy) + def get_data(self): + Geoclue.Simple.new("org.gajim.Gajim", + Geoclue.AccuracyLevel.EXACT, + None, + self._on_simple_ready) def start(self): self.location_info = {} self.get_data() - bus = dbus.SessionBus() - # Geoclue - bus.add_signal_receiver(self._on_geoclue_address_changed, - 'AddressChanged', 'org.freedesktop.Geoclue.Address') - bus.add_signal_receiver(self._on_geoclue_position_changed, - 'PositionChanged', 'org.freedesktop.Geoclue.Position') - - def shut_down(self): - pass - - def _on_geoclue_address_changed(self, timestamp=None, address=None, - accuracy=None): - # update data with info we just received - if address is None: - address = {} - for field in ['country', 'countrycode', 'locality', 'postalcode', - 'region', 'street']: - self._data[field] = address.get(field, None) - if timestamp: - self._data['timestamp'] = self._timestamp_to_utc(timestamp) - if accuracy: - # in PEP it's horizontal accuracy - self._data['accuracy'] = accuracy[1] - self._send_location() - - def _on_geoclue_position_changed(self, fields=None, timestamp=None, lat=None, - lon=None, alt=None, accuracy=None): - if fields is None: - fields = [] - # update data with info we just received - _dict = {'lat': lat, 'lon': lon, 'alt': alt} - for field in _dict: - if _dict[field] is not None: - self._data[field] = _dict[field] - if timestamp: - self._data['timestamp'] = self._timestamp_to_utc(timestamp) - if accuracy: - # in PEP it's horizontal accuracy - self._data['accuracy'] = accuracy[1] - self._send_location() def _send_location(self): accounts = app.connections.keys() @@ -143,10 +102,7 @@ class LocationListener: time = datetime.utcfromtimestamp(timestamp) return time.strftime('%Y-%m-%dT%H:%MZ') + def enable(): listener = LocationListener.get() listener.start() - -def disable(): - listener = LocationListener.get() - listener.shut_down() diff --git a/gajim/gui_interface.py b/gajim/gui_interface.py index 458a23ac5..fc077ec79 100644 --- a/gajim/gui_interface.py +++ b/gajim/gui_interface.py @@ -57,9 +57,11 @@ from gajim.common import events from gajim.common import dbus_support if dbus_support.supported: from gajim.music_track_listener import MusicTrackListener - from gajim.common import location_listener import dbus +if app.HAVE_GEOCLUE: + from gajim.common import location_listener + from gajim import gtkgui_helpers from gajim import gui_menu_builder from gajim import dialogs @@ -1118,15 +1120,14 @@ class Interface: if connected == invisible_show: return # send currently played music - if obj.conn.pep_supported and dbus_support.supported and \ - app.config.get_per('accounts', account, 'publish_tune'): + if (obj.conn.pep_supported and dbus_support.supported and + app.config.get_per('accounts', account, 'publish_tune')): self.enable_music_listener() # enable location listener - if obj.conn.pep_supported and dbus_support.supported and \ - app.config.get_per('accounts', account, 'publish_location'): + if (obj.conn.pep_supported and app.HAVE_GEOCLUE and + app.config.get_per('accounts', account, 'publish_location')): location_listener.enable() - @staticmethod def handle_event_metacontacts(obj): app.contacts.define_metacontacts(obj.conn.name, obj.meta_list) diff --git a/gajim/roster_window.py b/gajim/roster_window.py index 4cf496d4a..34c2e36dc 100644 --- a/gajim/roster_window.py +++ b/gajim/roster_window.py @@ -64,7 +64,8 @@ from gajim.common import app from gajim.common import helpers from gajim.common.exceptions import GajimGeneralException from gajim.common import i18n -from gajim.common import location_listener +if app.HAVE_GEOCLUE: + from gajim.common import location_listener from gajim.common import ged from gajim.common import dbus_support from gajim.message_window import MessageWindowMgr @@ -3647,12 +3648,6 @@ class RosterWindow: location_listener.enable() else: app.connections[account].retract_location() - # disable music listener only if no other account uses it - for acc in app.connections: - if app.config.get_per('accounts', acc, 'publish_location'): - break - else: - location_listener.disable() helpers.update_optional_features(account) @@ -4979,21 +4974,28 @@ class RosterWindow: if app.connections[account].pep_supported: pep_submenu = Gtk.Menu() pep_menuitem.set_submenu(pep_submenu) - def add_item(label, opt_name, func): - item = Gtk.CheckMenuItem.new_with_label(label) - pep_submenu.append(item) - if not dbus_support.supported: - item.set_sensitive(False) - else: - activ = app.config.get_per('accounts', account, - opt_name) - item.set_active(activ) - item.connect('toggled', func, account) - add_item(_('Publish Tune'), 'publish_tune', - self.on_publish_tune_toggled) - add_item(_('Publish Location'), 'publish_location', - self.on_publish_location_toggled) + item = Gtk.CheckMenuItem(_('Publish Tune')) + pep_submenu.append(item) + if not dbus_support.supported: + item.set_sensitive(False) + else: + activ = app.config.get_per('accounts', account, + 'publish_tune') + item.set_active(activ) + item.connect('toggled', self.on_publish_tune_toggled, + account) + + item = Gtk.CheckMenuItem(_('Publish Location')) + pep_submenu.append(item) + if not app.HAVE_GEOCLUE: + item.set_sensitive(False) + else: + activ = app.config.get_per('accounts', account, + 'publish_location') + item.set_active(activ) + item.connect('toggled', self.on_publish_location_toggled, + account) pep_config = Gtk.MenuItem.new_with_label( _('Configure Services…'))