Philipp Hörist pushed to branch master at gajim / gajim
Commits: d37b95e4 by Philipp Hörist at 2019-02-02T11:51:24Z Refactor UserTune
- Simplify modules because nbxmpp handles more stuff
- - - - - 59b39b04 by Philipp Hörist at 2019-02-02T11:51:28Z Refactor UserLocation
- Simplify modules because nbxmpp handles more stuff
- - - - - 3f03e6e0 by Philipp Hörist at 2019-02-02T11:55:07Z Better handle disable notifitcations
- - - - -
12 changed files:
- gajim/chat_control.py - gajim/common/dbus/location.py - gajim/common/modules/user_activity.py - gajim/common/modules/user_location.py - gajim/common/modules/user_mood.py - gajim/common/modules/user_tune.py - gajim/common/types.py - gajim/gtk/tooltips.py - gajim/gtk/util.py - gajim/gtkgui_helpers.py - gajim/gui_interface.py - gajim/roster_window.py
Changes:
===================================== gajim/chat_control.py ===================================== @@ -61,6 +61,8 @@ from gajim.gtk.util import get_cursor from gajim.gtk.util import ensure_proper_control from gajim.gtk.util import format_mood from gajim.gtk.util import format_activity +from gajim.gtk.util import format_tune +from gajim.gtk.util import format_location from gajim.gtk.util import get_activity_icon_name
from gajim.command_system.implementation.hosts import ChatCommands @@ -131,12 +133,7 @@ class ChatControl(ChatControlBase): self.video_available = False
self.update_toolbar() - - self._pep_images = {} - self._pep_images['tune'] = self.xml.get_object('tune_image') - self._pep_images['geoloc'] = self.xml.get_object('location_image') self.update_all_pep_types() - self.show_avatar()
# Hook up signals @@ -228,14 +225,16 @@ class ChatControl(ChatControlBase): self.restore_conversation() self.msg_textview.grab_focus()
- app.ged.register_event_handler('pep-received', ged.GUI1, - self._nec_pep_received) app.ged.register_event_handler('nickname-received', ged.GUI1, self._on_nickname_received) app.ged.register_event_handler('mood-received', ged.GUI1, self._on_mood_received) app.ged.register_event_handler('activity-received', ged.GUI1, self._on_activity_received) + app.ged.register_event_handler('tune-received', ged.GUI1, + self._on_tune_received) + app.ged.register_event_handler('location-received', ged.GUI1, + self._on_location_received) if self.TYPE_ID == message_control.TYPE_CHAT: # Dont connect this when PrivateChatControl is used app.ged.register_event_handler('update-roster-avatar', ged.GUI1, @@ -416,36 +415,10 @@ class ChatControl(ChatControlBase): self.audio_available = False
def update_all_pep_types(self): - for pep_type in self._pep_images: - self.update_pep(pep_type) + self._update_pep(PEPEventType.LOCATION) self._update_pep(PEPEventType.MOOD) self._update_pep(PEPEventType.ACTIVITY) - - def update_pep(self, pep_type): - if isinstance(self.contact, GC_Contact): - return - if pep_type not in self._pep_images: - return - pep = self.contact.pep - img = self._pep_images[pep_type] - if pep_type in pep: - icon = gtkgui_helpers.get_pep_icon(pep[pep_type]) - if isinstance(icon, str): - img.set_from_icon_name(icon, Gtk.IconSize.MENU) - else: - img.set_from_pixbuf(icon) - img.set_tooltip_markup(pep[pep_type].as_markup_text()) - img.show() - else: - img.hide() - - def _nec_pep_received(self, obj): - if obj.conn.name != self.account: - return - if obj.jid != self.contact.jid: - return - - self.update_pep(obj.pep_type) + self._update_pep(PEPEventType.TUNE)
def _update_pep(self, type_): image = self._get_pep_widget(type_) @@ -460,6 +433,12 @@ class ChatControl(ChatControlBase): elif type_ == PEPEventType.ACTIVITY: icon = get_activity_icon_name(data.activity, data.subactivity) formated_text = format_activity(*data) + elif type_ == PEPEventType.TUNE: + icon = 'audio-x-generic' + formated_text = format_tune(*data) + elif type_ == PEPEventType.LOCATION: + icon = 'applications-internet' + formated_text = format_location(data)
image.set_from_icon_name(icon, Gtk.IconSize.MENU) image.set_tooltip_markup(formated_text) @@ -470,6 +449,10 @@ class ChatControl(ChatControlBase): return self.xml.get_object('mood_image') if type_ == PEPEventType.ACTIVITY: return self.xml.get_object('activity_image') + if type_ == PEPEventType.TUNE: + return self.xml.get_object('tune_image') + if type_ == PEPEventType.LOCATION: + return self.xml.get_object('location_image')
@ensure_proper_control def _on_mood_received(self, _event): @@ -479,6 +462,14 @@ class ChatControl(ChatControlBase): def _on_activity_received(self, _event): self._update_pep(PEPEventType.ACTIVITY)
+ @ensure_proper_control + def _on_tune_received(self, _event): + self._update_pep(PEPEventType.TUNE) + + @ensure_proper_control + def _on_location_received(self, _event): + self._update_pep(PEPEventType.LOCATION) + @ensure_proper_control def _on_nickname_received(self, _event): self.update_ui() @@ -1092,15 +1083,16 @@ class ChatControl(ChatControlBase): # PluginSystem: removing GUI extension points connected with ChatControl # instance object app.plugin_manager.remove_gui_extension_point('chat_control', self) - - app.ged.remove_event_handler('pep-received', ged.GUI1, - self._nec_pep_received) app.ged.remove_event_handler('nickname-received', ged.GUI1, self._on_nickname_received) app.ged.remove_event_handler('mood-received', ged.GUI1, self._on_mood_received) app.ged.remove_event_handler('activity-received', ged.GUI1, self._on_activity_received) + app.ged.remove_event_handler('tune-received', ged.GUI1, + self._on_tune_received) + app.ged.remove_event_handler('location-received', ged.GUI1, + self._on_location_received) if self.TYPE_ID == message_control.TYPE_CHAT: app.ged.remove_event_handler('update-roster-avatar', ged.GUI1, self._nec_update_avatar)
===================================== gajim/common/dbus/location.py ===================================== @@ -18,6 +18,7 @@ import logging from datetime import datetime
from gi.repository import GLib +from nbxmpp.structs import LocationData
from gajim.common import app
@@ -93,7 +94,8 @@ class LocationListener: del new_data['timestamp'] if last_data == new_data: continue - app.connections[acct].get_module('UserLocation').send(self._data) + app.connections[acct].get_module('UserLocation').set_location( + LocationData(**self._data)) self.location_info = self._data.copy()
def _timestamp_to_utc(self, timestamp):
===================================== gajim/common/modules/user_activity.py ===================================== @@ -45,17 +45,17 @@ class UserActivity(BaseModule): @event_node(nbxmpp.NS_ACTIVITY) def _activity_received(self, _con, _stanza, properties): data = properties.pubsub_event.data - if data is None: - return + empty = properties.pubsub_event.empty + for contact in app.contacts.get_contacts(self._account, str(properties.jid)): - if data.activity is not None: + if not empty: contact.pep[PEPEventType.ACTIVITY] = data else: contact.pep.pop(PEPEventType.ACTIVITY, None)
if properties.is_self_message: - if data.activity is not None: + if not empty: self._con.pep[PEPEventType.ACTIVITY] = data else: self._con.pep.pop(PEPEventType.ACTIVITY, None)
===================================== gajim/common/modules/user_location.py ===================================== @@ -17,64 +17,57 @@ import logging
import nbxmpp -from gi.repository import GLib
-from gajim.common.const import PEPEventType, LOCATION_DATA -from gajim.common.exceptions import StanzaMalformed -from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData +from gajim.common import app +from gajim.common.nec import NetworkEvent +from gajim.common.modules.base import BaseModule +from gajim.common.modules.util import event_node +from gajim.common.modules.util import store_publish +from gajim.common.const import PEPEventType
log = logging.getLogger('gajim.c.m.user_location')
-class UserLocationData(AbstractPEPData): - - type_ = PEPEventType.LOCATION - - def as_markup_text(self): - location = self.data - location_string = '' - - for entry in location.keys(): - text = location[entry] - text = GLib.markup_escape_text(text) - # Translate standard location tag - tag = LOCATION_DATA.get(entry, entry) - location_string += '\n<b>%(tag)s</b>: %(text)s' % { - 'tag': tag.capitalize(), 'text': text} - - return location_string.strip() - - -class UserLocation(AbstractPEPModule): - - name = 'geoloc' - namespace = nbxmpp.NS_LOCATION - pep_class = UserLocationData - store_publish = True - _log = log - - def _extract_info(self, item): - location_dict = {} - location_tag = item.getTag('geoloc', namespace=nbxmpp.NS_LOCATION) - if location_tag is None: - raise StanzaMalformed('No geoloc node') - - for child in location_tag.getChildren(): - name = child.getName().strip() - data = child.getData().strip() - if child.getName() in LOCATION_DATA: - location_dict[name] = data - - return location_dict or None - - def _build_node(self, data): - item = nbxmpp.Node('geoloc', {'xmlns': nbxmpp.NS_LOCATION}) - if data is None: - return item - for field in LOCATION_DATA: - if data.get(field, False): - item.addChild(field, payload=data[field]) - return item +class UserLocation(BaseModule): + + _nbxmpp_extends = 'Location' + _nbxmpp_methods = [ + 'set_location', + ] + + def __init__(self, con): + BaseModule.__init__(self, con) + self._register_pubsub_handler(self._location_received) + + @event_node(nbxmpp.NS_LOCATION) + def _location_received(self, _con, _stanza, properties): + data = properties.pubsub_event.data + empty = properties.pubsub_event.empty + + for contact in app.contacts.get_contacts(self._account, + str(properties.jid)): + if not empty: + contact.pep[PEPEventType.LOCATION] = data + else: + contact.pep.pop(PEPEventType.LOCATION, None) + + if properties.is_self_message: + if not empty: + self._con.pep[PEPEventType.LOCATION] = data + else: + self._con.pep.pop(PEPEventType.LOCATION, None) + + app.nec.push_incoming_event( + NetworkEvent('location-received', + account=self._account, + jid=properties.jid.getBare(), + location=data, + is_self_message=properties.is_self_message)) + + @store_publish + def set_location(self, location): + log.info('Send %s', location) + self._nbxmpp('Location').set_location(location)
def get_instance(*args, **kwargs):
===================================== gajim/common/modules/user_mood.py ===================================== @@ -45,17 +45,17 @@ class UserMood(BaseModule): @event_node(nbxmpp.NS_MOOD) def _mood_received(self, _con, _stanza, properties): data = properties.pubsub_event.data - if data is None: - return + empty = properties.pubsub_event.empty + for contact in app.contacts.get_contacts(self._account, str(properties.jid)): - if data.mood is not None: + if not empty: contact.pep[PEPEventType.MOOD] = data else: contact.pep.pop(PEPEventType.MOOD, None)
if properties.is_self_message: - if data.mood is not None: + if not empty: self._con.pep[PEPEventType.MOOD] = data else: self._con.pep.pop(PEPEventType.MOOD, None)
===================================== gajim/common/modules/user_tune.py ===================================== @@ -15,90 +15,62 @@ # XEP-0118: User Tune
from typing import Any -from typing import List # pylint: disable=unused-import -from typing import Dict -from typing import Optional from typing import Tuple
import logging
import nbxmpp -from gi.repository import GLib
-from gajim.common.i18n import _ +from gajim.common import app +from gajim.common.nec import NetworkEvent +from gajim.common.modules.base import BaseModule +from gajim.common.modules.util import event_node +from gajim.common.modules.util import store_publish from gajim.common.const import PEPEventType -from gajim.common.exceptions import StanzaMalformed -from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData -from gajim.common.types import UserTuneDataT
log = logging.getLogger('gajim.c.m.user_tune')
-class UserTuneData(AbstractPEPData): - - type_ = PEPEventType.TUNE - - def as_markup_text(self) -> str: - if self.data is None: - return '' - - tune = self.data - - artist = tune.get('artist', _('Unknown Artist')) - artist = GLib.markup_escape_text(artist) - - title = tune.get('title', _('Unknown Title')) - title = GLib.markup_escape_text(title) - - source = tune.get('source', _('Unknown Source')) - source = GLib.markup_escape_text(source) - - tune_string = _('<b>"%(title)s"</b> by <i>%(artist)s</i>\n' - 'from <i>%(source)s</i>') % {'title': title, - 'artist': artist, - 'source': source} - return tune_string - - -class UserTune(AbstractPEPModule): - - name = 'tune' - namespace = nbxmpp.NS_TUNE - pep_class = UserTuneData - store_publish = True - _log = log - - def _extract_info(self, item: nbxmpp.Node) -> Optional[Dict[str, str]]: - tune_dict = {} - tune_tag = item.getTag('tune', namespace=self.namespace) - if tune_tag is None: - raise StanzaMalformed('No tune node') - - for child in tune_tag.getChildren(): - name = child.getName().strip() - data = child.getData().strip() - if child.getName() in ['artist', 'title', 'source', - 'track', 'length']: - tune_dict[name] = data - - return tune_dict or None - - def _build_node(self, data: UserTuneDataT) -> nbxmpp.Node: - item = nbxmpp.Node('tune', {'xmlns': nbxmpp.NS_TUNE}) - if data is None: - return item - artist, title, source, track, length = data - if artist: - item.addChild('artist', payload=artist) - if title: - item.addChild('title', payload=title) - if source: - item.addChild('source', payload=source) - if track: - item.addChild('track', payload=track) - if length: - item.addChild('length', payload=length) - return item +class UserTune(BaseModule): + + _nbxmpp_extends = 'Tune' + _nbxmpp_methods = [ + 'set_tune', + ] + + def __init__(self, con): + BaseModule.__init__(self, con) + self._register_pubsub_handler(self._tune_received) + + @event_node(nbxmpp.NS_TUNE) + def _tune_received(self, _con, _stanza, properties): + data = properties.pubsub_event.data + empty = properties.pubsub_event.empty + + for contact in app.contacts.get_contacts(self._account, + str(properties.jid)): + if not empty: + contact.pep[PEPEventType.TUNE] = data + else: + contact.pep.pop(PEPEventType.TUNE, None) + + if properties.is_self_message: + if not empty: + self._con.pep[PEPEventType.TUNE] = data + else: + self._con.pep.pop(PEPEventType.TUNE, None) + + app.nec.push_incoming_event( + NetworkEvent('tune-received', + account=self._account, + jid=properties.jid.getBare(), + tune=data, + is_self_message=properties.is_self_message)) + + @store_publish + def set_tune(self, tune): + log.info('Send %s', tune) + self._nbxmpp('Tune').set_tune(tune)
def get_instance(*args: Any, **kwargs: Any) -> Tuple[UserTune, str]:
===================================== gajim/common/types.py ===================================== @@ -47,8 +47,6 @@ ConnectionT = Union['Connection', 'ConnectionZeroconf'] ContactsT = Union['Contact', 'GC_Contact'] ContactT = Union['Contact']
-UserTuneDataT = Optional[Tuple[str, str, str, str, str]] - # PEP PEPNotifyCallback = Callable[[nbxmpp.JID, nbxmpp.Node], None] PEPHandlersDict = Dict[str, List[PEPNotifyCallback]]
===================================== gajim/gtk/tooltips.py ===================================== @@ -44,6 +44,8 @@ from gajim.gtk.util import get_builder from gajim.gtk.util import get_icon_name from gajim.gtk.util import format_mood from gajim.gtk.util import format_activity +from gajim.gtk.util import format_tune +from gajim.gtk.util import format_location
log = logging.getLogger('gajim.gtk.tooltips') @@ -487,14 +489,14 @@ class RosterTooltip(StatusTable): self._ui.activity.show() self._ui.activity_label.show()
- if 'tune' in contact.pep: - tune = contact.pep['tune'].as_markup_text() + if PEPEventType.TUNE in contact.pep: + tune = format_tune(*contact.pep[PEPEventType.TUNE]) self._ui.tune.set_markup(tune) self._ui.tune.show() self._ui.tune_label.show()
- if 'geoloc' in contact.pep: - location = contact.pep['geoloc'].as_markup_text() + if PEPEventType.LOCATION in contact.pep: + location = format_location(contact.pep[PEPEventType.LOCATION]) self._ui.location.set_markup(location) self._ui.location.show() self._ui.location_label.show()
===================================== gajim/gtk/util.py ===================================== @@ -38,6 +38,7 @@ from gajim.common import i18n from gajim.common.i18n import _ from gajim.common.const import MOODS from gajim.common.const import ACTIVITIES +from gajim.common.const import LOCATION_DATA
from gajim.gtk.const import GajimIconSet
@@ -546,3 +547,34 @@ def get_activity_icon_name(activity, subactivity=None): if subactivity is not None: icon_name += '-%s' % subactivity.replace('_', '-') return icon_name + + +def format_tune(artist, length, rating, source, title, track, uri): + if artist is None and title is None and source is None: + return + artist = GLib.markup_escape_text(artist or _('Unknown Artist')) + title = GLib.markup_escape_text(title or _('Unknown Title')) + source = GLib.markup_escape_text(source or _('Unknown Source')) + + tune_string = _('<b>"%(title)s"</b> by <i>%(artist)s</i>\n' + 'from <i>%(source)s</i>') % {'title': title, + 'artist': artist, + 'source': source} + return tune_string + + +def format_location(location): + location = location._asdict() + location_string = '' + for attr, value in location.items(): + if value is None: + continue + text = GLib.markup_escape_text(value) + # Translate standard location tag + tag = LOCATION_DATA.get(attr) + if tag is None: + continue + location_string += '\n<b>%(tag)s</b>: %(text)s' % { + 'tag': tag.capitalize(), 'text': text} + + return location_string.strip()
===================================== gajim/gtkgui_helpers.py ===================================== @@ -264,15 +264,6 @@ def create_list_multi(value_list, selected_values=None): treeview.show_all() return treeview
-def get_pep_icon(pep_class): - if pep_class == PEPEventType.TUNE: - return 'audio-x-generic' - - if pep_class == PEPEventType.LOCATION: - return 'applications-internet' - - return None - def label_set_autowrap(widget): """ Make labels automatically re-wrap if their containers are resized.
===================================== gajim/gui_interface.py ===================================== @@ -47,6 +47,7 @@ from gi.repository import Gio from gi.repository import Gdk from nbxmpp import idlequeue from nbxmpp import Hashes2 +from nbxmpp.structs import TuneData import OpenSSL
try: @@ -1942,8 +1943,8 @@ class Interface: continue if app.connections[acct].music_track_info == music_track_info: continue - app.connections[acct].get_module('UserTune').send( - (artist, title, source, '', '')) + app.connections[acct].get_module('UserTune').set_tune( + TuneData(artist=artist, title=title, source=source)) app.connections[acct].music_track_info = music_track_info
def read_sleepy(self):
===================================== gajim/roster_window.py ===================================== @@ -1058,16 +1058,13 @@ class RosterWindow: else: self.model[child_iter][Column.ACTIVITY_PIXBUF] = None
- if app.config.get('show_tunes_in_roster') and 'tune' in pep_dict: - self.model[child_iter][Column.TUNE_ICON] = \ - gtkgui_helpers.get_pep_icon(pep_dict['tune']) + if app.config.get('show_tunes_in_roster') and PEPEventType.TUNE in pep_dict: + self.model[child_iter][Column.TUNE_ICON] = 'audio-x-generic' else: self.model[child_iter][Column.TUNE_ICON] = None
- if app.config.get('show_location_in_roster') and 'geoloc' in \ - pep_dict: - self.model[child_iter][Column.LOCATION_ICON] = \ - gtkgui_helpers.get_pep_icon(pep_dict['geoloc']) + if app.config.get('show_location_in_roster') and PEPEventType.LOCATION in pep_dict: + self.model[child_iter][Column.LOCATION_ICON] = 'applications-internet' else: self.model[child_iter][Column.LOCATION_ICON] = None
@@ -1319,39 +1316,19 @@ class RosterWindow: if pep_type == PEPEventType.ACTIVITY: return app.config.get('show_activity_in_roster')
- if pep_type == 'tune': + if pep_type == PEPEventType.TUNE: return app.config.get('show_tunes_in_roster')
- if pep_type == 'geoloc': + if pep_type == PEPEventType.LOCATION: return app.config.get('show_location_in_roster')
return False
def draw_all_pep_types(self, jid, account, contact=None): - for pep_type in self._pep_type_to_model_column: - self.draw_pep(jid, account, pep_type, contact=contact) self._draw_pep(account, jid, PEPEventType.MOOD) self._draw_pep(account, jid, PEPEventType.ACTIVITY) - - def draw_pep(self, jid, account, pep_type, contact=None): - if pep_type not in self._pep_type_to_model_column: - return - if not self._is_pep_shown_in_roster(pep_type): - return - - model_column = self._pep_type_to_model_column[pep_type] - iters = self._get_contact_iter(jid, account, model=self.model) - if not iters: - return - if not contact: - contact = app.contacts.get_contact(account, jid) - - pixbuf = None - if pep_type in contact.pep: - pixbuf = gtkgui_helpers.get_pep_icon(contact.pep[pep_type]) - - for child_iter in iters: - self.model[child_iter][model_column] = pixbuf + self._draw_pep(account, jid, PEPEventType.TUNE) + self._draw_pep(account, jid, PEPEventType.LOCATION)
def _draw_pep(self, account, jid, type_): if not self._is_pep_shown_in_roster(type_): @@ -1373,6 +1350,14 @@ class RosterWindow: column = Column.ACTIVITY_PIXBUF if data is not None: icon = get_activity_icon_name(data.activity, data.subactivity) + elif type_ == PEPEventType.TUNE: + column = Column.TUNE_ICON + if data is not None: + icon = 'audio-x-generic' + elif type_ == PEPEventType.LOCATION: + column = Column.LOCATION_ICON + if data is not None: + icon = 'applications-internet'
for child_iter in iters: self.model[child_iter][column] = icon @@ -2636,8 +2621,7 @@ class RosterWindow: self.remove_contact(jid, obj.conn.name, backend=True)
def _nec_pep_received(self, obj): - if obj.user_pep.type_ not in (PEPEventType.TUNE, - PEPEventType.LOCATION): + if obj.user_pep.type_ != PEPEventType.LOCATION: return
if obj.jid == app.get_jid_from_account(obj.conn.name): @@ -2655,6 +2639,16 @@ class RosterWindow: self.draw_account(event.account) self._draw_pep(event.account, event.jid, PEPEventType.ACTIVITY)
+ def _on_tune_received(self, event): + if event.is_self_message: + self.draw_account(event.account) + self._draw_pep(event.account, event.jid, PEPEventType.TUNE) + + def _on_location_received(self, event): + if event.is_self_message: + self.draw_account(event.account) + self._draw_pep(event.account, event.jid, PEPEventType.LOCATION) + def _on_nickname_received(self, event): self.draw_contact(event.jid, event.account)
@@ -3595,7 +3589,7 @@ class RosterWindow: if active: app.interface.enable_music_listener() else: - app.connections[account].get_module('UserTune').send(None) + app.connections[account].get_module('UserTune').set_tune(None) # disable music listener only if no other account uses it for acc in app.connections: if app.config.get_per('accounts', acc, 'publish_tune'): @@ -3611,7 +3605,7 @@ class RosterWindow: if active: location.enable() else: - app.connections[account].get_module('UserLocation').send(None) + app.connections[account].get_module('UserLocation').set_location(None)
helpers.update_optional_features(account)
@@ -5591,9 +5585,8 @@ class RosterWindow: # [icon, name, type, jid, account, editable, mood_pixbuf, # activity_pixbuf, TUNE_ICON, LOCATION_ICON, avatar_img, # padlock_pixbuf, visible] - self.columns = [str, str, str, str, str, - str, str, str, str, - Gtk.Image, str, bool] + self.columns = [str, str, str, str, str, str, str, str, str, + Gtk.Image, str, bool]
self.xml = get_builder('roster_window.ui') self.window = self.xml.get_object('roster_window') @@ -5692,8 +5685,6 @@ class RosterWindow: # cell_data_func, func_arg) self.renderers_list = [] self.renderers_propertys = {} - self._pep_type_to_model_column = {'tune': Column.TUNE_ICON, - 'geoloc': Column.LOCATION_ICON}
renderer_text = Gtk.CellRendererText() self.renderers_propertys[renderer_text] = ('ellipsize', @@ -5847,6 +5838,10 @@ class RosterWindow: self._on_mood_received) app.ged.register_event_handler('activity-received', ged.GUI1, self._on_activity_received) + app.ged.register_event_handler('tune-received', ged.GUI1, + self._on_tune_received) + app.ged.register_event_handler('location-received', ged.GUI1, + self._on_location_received) app.ged.register_event_handler('update-roster-avatar', ged.GUI1, self._nec_update_avatar) app.ged.register_event_handler('update-room-avatar', ged.GUI1,
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/18c422d843a60bccf6dcc43ba3a9e95610...