Philipp Hörist pushed to branch master at gajim / gajim

Commits:

18 changed files:

Changes:

  • gajim/common/app.py
    ... ... @@ -378,6 +378,19 @@ def get_number_of_connected_accounts(accounts_list=None):
    378 378
                 connected_accounts = connected_accounts + 1
    
    379 379
         return connected_accounts
    
    380 380
     
    
    381
    +def get_available_clients(account=None):
    
    382
    +    clients = []
    
    383
    +    if account is not None:
    
    384
    +        client = connections.get(account)
    
    385
    +        if client is None or not client.state.is_available:
    
    386
    +            return []
    
    387
    +        return [client]
    
    388
    +
    
    389
    +    for client in connections.values():
    
    390
    +        if client.state.is_available:
    
    391
    +            clients.append(client)
    
    392
    +    return clients
    
    393
    +
    
    381 394
     def get_connected_accounts(exclude_local=False):
    
    382 395
         """
    
    383 396
         Returns a list of CONNECTED accounts
    

  • gajim/common/client.py
    ... ... @@ -102,6 +102,10 @@ class Client(ConnectionHandlers):
    102 102
         def state(self):
    
    103 103
             return self._state
    
    104 104
     
    
    105
    +    @property
    
    106
    +    def account(self):
    
    107
    +        return self._account
    
    108
    +
    
    105 109
         @property
    
    106 110
         def status(self):
    
    107 111
             return self._status
    
    ... ... @@ -384,6 +388,10 @@ class Client(ConnectionHandlers):
    384 388
     
    
    385 389
             # We are connected
    
    386 390
             if show == 'offline':
    
    391
    +            self.set_user_activity(None)
    
    392
    +            self.set_user_mood(None)
    
    393
    +            self.set_user_tune(None)
    
    394
    +            self.set_user_location(None)
    
    387 395
                 presence = self.get_module('Presence').get_presence(
    
    388 396
                     typ='unavailable',
    
    389 397
                     status=message,
    
    ... ... @@ -409,6 +417,18 @@ class Client(ConnectionHandlers):
    409 417
             if include_muc:
    
    410 418
                 self.get_module('MUC').update_presence()
    
    411 419
     
    
    420
    +    def set_user_activity(self, activity):
    
    421
    +        self.get_module('UserActivity').set_activity(activity)
    
    422
    +
    
    423
    +    def set_user_mood(self, mood):
    
    424
    +        self.get_module('UserMood').set_mood(mood)
    
    425
    +
    
    426
    +    def set_user_tune(self, tune):
    
    427
    +        self.get_module('UserTune').set_tune(tune)
    
    428
    +
    
    429
    +    def set_user_location(self, location):
    
    430
    +        self.get_module('UserLocation').set_location(location)
    
    431
    +
    
    412 432
         def get_module(self, name):
    
    413 433
             return modules.get(self._account, name)
    
    414 434
     
    

  • gajim/common/config.py
    ... ... @@ -246,6 +246,7 @@ class Config:
    246 246
             'show_help_start_chat': [opt_bool, True, _('Shows an info bar with helpful hints in the Start / Join Chat dialog')],
    
    247 247
             'check_for_update': [opt_bool, True, _('Check for Gajim updates periodically')],
    
    248 248
             'last_update_check': [opt_str, '', _('Date of the last update check')],
    
    249
    +        'always_ask_for_status_message': [opt_bool, True],
    
    249 250
         }, {})  # type: Tuple[Dict[str, List[Any]], Dict[Any, Any]]
    
    250 251
     
    
    251 252
         __options_per_key = {
    
    ... ... @@ -269,7 +270,6 @@ class Config:
    269 270
                 'autopriority_xa': [opt_int, 30],
    
    270 271
                 'autopriority_dnd': [opt_int, 20],
    
    271 272
                 'autoconnect': [opt_bool, False, '', True],
    
    272
    -            'autoconnect_as': [opt_str, 'online', _('Status to be used automatically when connecting. Can be \'online\', \'chat\', \'away\', \'xa\' or \'dnd\'. NOTE: This option is used only if \'restore_last_status\' is disabled.'), True],
    
    273 273
                 'restore_last_status': [opt_bool, False, _('If enabled, the last status will be restored.')],
    
    274 274
                 'autoauth': [opt_bool, False, _('If enabled, contacts requesting authorization will be accepted automatically.')],
    
    275 275
                 'active': [opt_bool, True, _('If disabled, this account will be disabled and will not appear in the contact list window.'), True],
    

  • gajim/common/helpers.py
    ... ... @@ -1428,3 +1428,17 @@ def should_log(account, jid):
    1428 1428
         no_log_for = no_log_for.split()
    
    1429 1429
     
    
    1430 1430
         return (account not in no_log_for) and (jid not in no_log_for)
    
    1431
    +
    
    1432
    +
    
    1433
    +def ask_for_status_message(status, signin=False):
    
    1434
    +    if status is None:
    
    1435
    +        # We try to change the message
    
    1436
    +        return True
    
    1437
    +
    
    1438
    +    if signin:
    
    1439
    +        return app.config.get('ask_online_status')
    
    1440
    +
    
    1441
    +    if status == 'offline':
    
    1442
    +        return app.config.get('ask_offline_status')
    
    1443
    +
    
    1444
    +    return app.config.get('always_ask_for_status_message')

  • gajim/common/modules/user_activity.py
    ... ... @@ -18,12 +18,12 @@ from typing import Any
    18 18
     from typing import Tuple
    
    19 19
     
    
    20 20
     from nbxmpp.namespaces import Namespace
    
    21
    +from nbxmpp.structs import ActivityData
    
    21 22
     
    
    22 23
     from gajim.common import app
    
    23 24
     from gajim.common.nec import NetworkEvent
    
    24 25
     from gajim.common.modules.base import BaseModule
    
    25 26
     from gajim.common.modules.util import event_node
    
    26
    -from gajim.common.modules.util import store_publish
    
    27 27
     from gajim.common.const import PEPEventType
    
    28 28
     
    
    29 29
     
    
    ... ... @@ -38,6 +38,11 @@ class UserActivity(BaseModule):
    38 38
             BaseModule.__init__(self, con)
    
    39 39
             self._register_pubsub_handler(self._activity_received)
    
    40 40
     
    
    41
    +        self._current_activity = None
    
    42
    +
    
    43
    +    def get_current_activity(self):
    
    44
    +        return self._current_activity
    
    45
    +
    
    41 46
         @event_node(Namespace.ACTIVITY)
    
    42 47
         def _activity_received(self, _con, _stanza, properties):
    
    43 48
             if properties.pubsub_event.retracted:
    
    ... ... @@ -56,6 +61,7 @@ class UserActivity(BaseModule):
    56 61
                     self._con.pep[PEPEventType.ACTIVITY] = data
    
    57 62
                 else:
    
    58 63
                     self._con.pep.pop(PEPEventType.ACTIVITY, None)
    
    64
    +            self._current_activity = data
    
    59 65
     
    
    60 66
             app.nec.push_incoming_event(
    
    61 67
                 NetworkEvent('activity-received',
    
    ... ... @@ -64,9 +70,20 @@ class UserActivity(BaseModule):
    64 70
                              activity=data,
    
    65 71
                              is_self_message=properties.is_self_message))
    
    66 72
     
    
    67
    -    @store_publish
    
    68 73
         def set_activity(self, activity):
    
    69
    -        self._log.info('Send %s', activity)
    
    74
    +        if activity is not None:
    
    75
    +            activity = ActivityData(*activity, None)
    
    76
    +
    
    77
    +        if activity == self._current_activity:
    
    78
    +            return
    
    79
    +
    
    80
    +        self._current_activity = activity
    
    81
    +
    
    82
    +        if activity is None:
    
    83
    +            self._log.info('Remove user activity')
    
    84
    +        else:
    
    85
    +            self._log.info('Set %s', activity)
    
    86
    +
    
    70 87
             self._nbxmpp('Activity').set_activity(activity)
    
    71 88
     
    
    72 89
     
    

  • gajim/common/modules/user_location.py
    ... ... @@ -35,6 +35,11 @@ class UserLocation(BaseModule):
    35 35
             BaseModule.__init__(self, con)
    
    36 36
             self._register_pubsub_handler(self._location_received)
    
    37 37
     
    
    38
    +        self._current_location = None
    
    39
    +
    
    40
    +    def get_current_location(self):
    
    41
    +        return self._current_location
    
    42
    +
    
    38 43
         @event_node(Namespace.LOCATION)
    
    39 44
         def _location_received(self, _con, _stanza, properties):
    
    40 45
             if properties.pubsub_event.retracted:
    
    ... ... @@ -53,6 +58,7 @@ class UserLocation(BaseModule):
    53 58
                     self._con.pep[PEPEventType.LOCATION] = data
    
    54 59
                 else:
    
    55 60
                     self._con.pep.pop(PEPEventType.LOCATION, None)
    
    61
    +            self._current_location = data
    
    56 62
     
    
    57 63
             app.nec.push_incoming_event(
    
    58 64
                 NetworkEvent('location-received',
    
    ... ... @@ -63,6 +69,7 @@ class UserLocation(BaseModule):
    63 69
     
    
    64 70
         @store_publish
    
    65 71
         def set_location(self, location):
    
    72
    +        self._current_location = location
    
    66 73
             self._log.info('Send %s', location)
    
    67 74
             self._nbxmpp('Location').set_location(location)
    
    68 75
     
    

  • gajim/common/modules/user_mood.py
    ... ... @@ -18,12 +18,12 @@ from typing import Any
    18 18
     from typing import Tuple
    
    19 19
     
    
    20 20
     from nbxmpp.namespaces import Namespace
    
    21
    +from nbxmpp.structs import MoodData
    
    21 22
     
    
    22 23
     from gajim.common import app
    
    23 24
     from gajim.common.nec import NetworkEvent
    
    24 25
     from gajim.common.modules.base import BaseModule
    
    25 26
     from gajim.common.modules.util import event_node
    
    26
    -from gajim.common.modules.util import store_publish
    
    27 27
     from gajim.common.const import PEPEventType
    
    28 28
     
    
    29 29
     
    
    ... ... @@ -38,6 +38,11 @@ class UserMood(BaseModule):
    38 38
             BaseModule.__init__(self, con)
    
    39 39
             self._register_pubsub_handler(self._mood_received)
    
    40 40
     
    
    41
    +        self._current_mood = None
    
    42
    +
    
    43
    +    def get_current_mood(self):
    
    44
    +        return self._current_mood
    
    45
    +
    
    41 46
         @event_node(Namespace.MOOD)
    
    42 47
         def _mood_received(self, _con, _stanza, properties):
    
    43 48
             if properties.pubsub_event.retracted:
    
    ... ... @@ -56,6 +61,7 @@ class UserMood(BaseModule):
    56 61
                     self._con.pep[PEPEventType.MOOD] = data
    
    57 62
                 else:
    
    58 63
                     self._con.pep.pop(PEPEventType.MOOD, None)
    
    64
    +            self._current_mood = data
    
    59 65
     
    
    60 66
             app.nec.push_incoming_event(
    
    61 67
                 NetworkEvent('mood-received',
    
    ... ... @@ -64,9 +70,20 @@ class UserMood(BaseModule):
    64 70
                              mood=data,
    
    65 71
                              is_self_message=properties.is_self_message))
    
    66 72
     
    
    67
    -    @store_publish
    
    68 73
         def set_mood(self, mood):
    
    69
    -        self._log.info('Send %s', mood)
    
    74
    +        if mood is not None:
    
    75
    +            mood = MoodData(mood, None)
    
    76
    +
    
    77
    +        if mood == self._current_mood:
    
    78
    +            return
    
    79
    +
    
    80
    +        self._current_mood = mood
    
    81
    +
    
    82
    +        if mood is None:
    
    83
    +            self._log.info('Remove user mood')
    
    84
    +        else:
    
    85
    +            self._log.info('Set %s', mood)
    
    86
    +
    
    70 87
             self._nbxmpp('Mood').set_mood(mood)
    
    71 88
     
    
    72 89
     
    

  • gajim/common/modules/user_tune.py
    ... ... @@ -47,6 +47,9 @@ class UserTune(BaseModule):
    47 47
                 ('signed-in', ged.CORE, self._on_signed_in),
    
    48 48
             ])
    
    49 49
     
    
    50
    +    def get_current_tune(self):
    
    51
    +        return self._tune_data
    
    52
    +
    
    50 53
         @event_node(Namespace.TUNE)
    
    51 54
         def _tune_received(self, _con, _stanza, properties):
    
    52 55
             if properties.pubsub_event.retracted:
    
    ... ... @@ -65,6 +68,7 @@ class UserTune(BaseModule):
    65 68
                     self._con.pep[PEPEventType.TUNE] = data
    
    66 69
                 else:
    
    67 70
                     self._con.pep.pop(PEPEventType.TUNE, None)
    
    71
    +            self._tune_data = data
    
    68 72
     
    
    69 73
             app.nec.push_incoming_event(
    
    70 74
                 NetworkEvent('tune-received',
    
    ... ... @@ -82,6 +86,12 @@ class UserTune(BaseModule):
    82 86
                                       self._account,
    
    83 87
                                       'publish_tune'):
    
    84 88
                 return
    
    89
    +
    
    90
    +        if tune == self._tune_data:
    
    91
    +            return
    
    92
    +
    
    93
    +        self._tune_data = tune
    
    94
    +
    
    85 95
             self._log.info('Send %s', tune)
    
    86 96
             self._nbxmpp('Tune').set_tune(tune)
    
    87 97
     
    
    ... ... @@ -110,7 +120,7 @@ class UserTune(BaseModule):
    110 120
         def _on_music_track_changed(self, event):
    
    111 121
             if self._tune_data == event.info:
    
    112 122
                 return
    
    113
    -        self._tune_data = event.info
    
    123
    +
    
    114 124
             self.set_tune(event.info)
    
    115 125
     
    
    116 126
     
    

  • gajim/data/gui/preferences_window.ui
    ... ... @@ -827,14 +827,14 @@
    827 827
                               </packing>
    
    828 828
                             </child>
    
    829 829
                             <child>
    
    830
    -                          <object class="GtkCheckButton" id="status_change_checkbutton">
    
    830
    +                          <object class="GtkCheckButton" id="show_status_change_checkbutton">
    
    831 831
                                 <property name="label" translatable="yes">Show status changes (Default)</property>
    
    832 832
                                 <property name="visible">True</property>
    
    833 833
                                 <property name="can_focus">True</property>
    
    834 834
                                 <property name="receives_default">False</property>
    
    835 835
                                 <property name="tooltip_text" translatable="yes">If status change messages are shown in the group chat. This setting can be overridden in the group chat menu.</property>
    
    836 836
                                 <property name="draw_indicator">True</property>
    
    837
    -                            <signal name="toggled" handler="_on_status_change_toggled" swapped="no"/>
    
    837
    +                            <signal name="toggled" handler="_on_show_status_change_toggled" swapped="no"/>
    
    838 838
                               </object>
    
    839 839
                               <packing>
    
    840 840
                                 <property name="left_attach">0</property>
    
    ... ... @@ -1276,6 +1276,146 @@
    1276 1276
                 <property name="border_width">18</property>
    
    1277 1277
                 <property name="orientation">vertical</property>
    
    1278 1278
                 <property name="spacing">6</property>
    
    1279
    +            <child>
    
    1280
    +              <object class="GtkFrame">
    
    1281
    +                <property name="visible">True</property>
    
    1282
    +                <property name="can_focus">False</property>
    
    1283
    +                <property name="valign">start</property>
    
    1284
    +                <property name="label_xalign">0</property>
    
    1285
    +                <property name="shadow_type">none</property>
    
    1286
    +                <child>
    
    1287
    +                  <object class="GtkGrid">
    
    1288
    +                    <property name="visible">True</property>
    
    1289
    +                    <property name="can_focus">False</property>
    
    1290
    +                    <property name="margin_top">6</property>
    
    1291
    +                    <property name="row_spacing">6</property>
    
    1292
    +                    <child>
    
    1293
    +                      <object class="GtkCheckButton" id="restore_last_status_checkbutton">
    
    1294
    +                        <property name="label" translatable="yes">_Remember last status</property>
    
    1295
    +                        <property name="visible">True</property>
    
    1296
    +                        <property name="can_focus">True</property>
    
    1297
    +                        <property name="receives_default">False</property>
    
    1298
    +                        <property name="tooltip_text" translatable="yes">If checked, the status and status message used in the last session will be restored</property>
    
    1299
    +                        <property name="halign">start</property>
    
    1300
    +                        <property name="use_underline">True</property>
    
    1301
    +                        <property name="draw_indicator">True</property>
    
    1302
    +                        <signal name="toggled" handler="on_restore_last_status_checkbutton_toggled" swapped="no"/>
    
    1303
    +                      </object>
    
    1304
    +                      <packing>
    
    1305
    +                        <property name="left_attach">0</property>
    
    1306
    +                        <property name="top_attach">0</property>
    
    1307
    +                      </packing>
    
    1308
    +                    </child>
    
    1309
    +                  </object>
    
    1310
    +                </child>
    
    1311
    +                <child type="label">
    
    1312
    +                  <object class="GtkLabel">
    
    1313
    +                    <property name="visible">True</property>
    
    1314
    +                    <property name="can_focus">False</property>
    
    1315
    +                    <property name="label" translatable="yes">General</property>
    
    1316
    +                    <property name="use_markup">True</property>
    
    1317
    +                    <style>
    
    1318
    +                      <class name="bold"/>
    
    1319
    +                      <class name="margin-top6"/>
    
    1320
    +                    </style>
    
    1321
    +                  </object>
    
    1322
    +                </child>
    
    1323
    +              </object>
    
    1324
    +              <packing>
    
    1325
    +                <property name="expand">True</property>
    
    1326
    +                <property name="fill">True</property>
    
    1327
    +                <property name="position">0</property>
    
    1328
    +              </packing>
    
    1329
    +            </child>
    
    1330
    +            <child>
    
    1331
    +              <object class="GtkFrame">
    
    1332
    +                <property name="visible">True</property>
    
    1333
    +                <property name="can_focus">False</property>
    
    1334
    +                <property name="label_xalign">0</property>
    
    1335
    +                <property name="shadow_type">none</property>
    
    1336
    +                <child>
    
    1337
    +                  <object class="GtkAlignment">
    
    1338
    +                    <property name="visible">True</property>
    
    1339
    +                    <property name="can_focus">False</property>
    
    1340
    +                    <child>
    
    1341
    +                      <object class="GtkGrid">
    
    1342
    +                        <property name="visible">True</property>
    
    1343
    +                        <property name="can_focus">False</property>
    
    1344
    +                        <property name="margin_top">6</property>
    
    1345
    +                        <property name="row_spacing">6</property>
    
    1346
    +                        <child>
    
    1347
    +                          <object class="GtkCheckButton" id="sign_in_status_checkbutton">
    
    1348
    +                            <property name="label" translatable="yes">Sign _In</property>
    
    1349
    +                            <property name="visible">True</property>
    
    1350
    +                            <property name="can_focus">True</property>
    
    1351
    +                            <property name="receives_default">False</property>
    
    1352
    +                            <property name="tooltip_text" translatable="yes">Show the status change dialog on Sign In</property>
    
    1353
    +                            <property name="halign">start</property>
    
    1354
    +                            <property name="use_underline">True</property>
    
    1355
    +                            <property name="draw_indicator">True</property>
    
    1356
    +                            <signal name="toggled" handler="on_sign_in_status_checkbutton_toggled" swapped="no"/>
    
    1357
    +                          </object>
    
    1358
    +                          <packing>
    
    1359
    +                            <property name="left_attach">0</property>
    
    1360
    +                            <property name="top_attach">0</property>
    
    1361
    +                          </packing>
    
    1362
    +                        </child>
    
    1363
    +                        <child>
    
    1364
    +                          <object class="GtkCheckButton" id="sign_out_status_checkbutton">
    
    1365
    +                            <property name="label" translatable="yes">Sign _Out</property>
    
    1366
    +                            <property name="visible">True</property>
    
    1367
    +                            <property name="can_focus">True</property>
    
    1368
    +                            <property name="receives_default">False</property>
    
    1369
    +                            <property name="tooltip_text" translatable="yes">Show the status change dialog on Sign Out</property>
    
    1370
    +                            <property name="halign">start</property>
    
    1371
    +                            <property name="use_underline">True</property>
    
    1372
    +                            <property name="draw_indicator">True</property>
    
    1373
    +                            <signal name="toggled" handler="on_sign_out_status_checkbutton_toggled" swapped="no"/>
    
    1374
    +                          </object>
    
    1375
    +                          <packing>
    
    1376
    +                            <property name="left_attach">0</property>
    
    1377
    +                            <property name="top_attach">1</property>
    
    1378
    +                          </packing>
    
    1379
    +                        </child>
    
    1380
    +                        <child>
    
    1381
    +                          <object class="GtkCheckButton" id="status_change_checkbutton">
    
    1382
    +                            <property name="label" translatable="yes">_Status Change</property>
    
    1383
    +                            <property name="visible">True</property>
    
    1384
    +                            <property name="can_focus">True</property>
    
    1385
    +                            <property name="receives_default">False</property>
    
    1386
    +                            <property name="tooltip_text" translatable="yes">Show the status change dialog on all status changes</property>
    
    1387
    +                            <property name="halign">start</property>
    
    1388
    +                            <property name="use_underline">True</property>
    
    1389
    +                            <property name="draw_indicator">True</property>
    
    1390
    +                            <signal name="toggled" handler="on_status_change_checkbutton_toggled" swapped="no"/>
    
    1391
    +                          </object>
    
    1392
    +                          <packing>
    
    1393
    +                            <property name="left_attach">0</property>
    
    1394
    +                            <property name="top_attach">2</property>
    
    1395
    +                          </packing>
    
    1396
    +                        </child>
    
    1397
    +                      </object>
    
    1398
    +                    </child>
    
    1399
    +                  </object>
    
    1400
    +                </child>
    
    1401
    +                <child type="label">
    
    1402
    +                  <object class="GtkLabel">
    
    1403
    +                    <property name="visible">True</property>
    
    1404
    +                    <property name="can_focus">False</property>
    
    1405
    +                    <property name="label" translatable="yes">Ask for Status Message on …</property>
    
    1406
    +                    <style>
    
    1407
    +                      <class name="bold"/>
    
    1408
    +                      <class name="margin-top6"/>
    
    1409
    +                    </style>
    
    1410
    +                  </object>
    
    1411
    +                </child>
    
    1412
    +              </object>
    
    1413
    +              <packing>
    
    1414
    +                <property name="expand">False</property>
    
    1415
    +                <property name="fill">True</property>
    
    1416
    +                <property name="position">1</property>
    
    1417
    +              </packing>
    
    1418
    +            </child>
    
    1279 1419
                 <child>
    
    1280 1420
                   <object class="GtkFrame">
    
    1281 1421
                     <property name="visible">True</property>
    
    ... ... @@ -1389,6 +1529,7 @@ $T will be replaced by auto-not-available timeout.</property>
    1389 1529
                             <property name="visible">True</property>
    
    1390 1530
                             <property name="can_focus">False</property>
    
    1391 1531
                             <property name="label" translatable="yes">Minutes</property>
    
    1532
    +                        <property name="xalign">0</property>
    
    1392 1533
                             <style>
    
    1393 1534
                               <class name="dim-label"/>
    
    1394 1535
                             </style>
    
    ... ... @@ -1403,6 +1544,7 @@ $T will be replaced by auto-not-available timeout.</property>
    1403 1544
                             <property name="visible">True</property>
    
    1404 1545
                             <property name="can_focus">False</property>
    
    1405 1546
                             <property name="label" translatable="yes">Message</property>
    
    1547
    +                        <property name="xalign">0</property>
    
    1406 1548
                             <style>
    
    1407 1549
                               <class name="dim-label"/>
    
    1408 1550
                             </style>
    
    ... ... @@ -1417,6 +1559,7 @@ $T will be replaced by auto-not-available timeout.</property>
    1417 1559
                             <property name="visible">True</property>
    
    1418 1560
                             <property name="can_focus">False</property>
    
    1419 1561
                             <property name="label" translatable="yes">Status</property>
    
    1562
    +                        <property name="xalign">0</property>
    
    1420 1563
                             <style>
    
    1421 1564
                               <class name="dim-label"/>
    
    1422 1565
                             </style>
    
    ... ... @@ -1444,139 +1587,9 @@ $T will be replaced by auto-not-available timeout.</property>
    1444 1587
                   <packing>
    
    1445 1588
                     <property name="expand">False</property>
    
    1446 1589
                     <property name="fill">False</property>
    
    1447
    -                <property name="position">0</property>
    
    1448
    -              </packing>
    
    1449
    -            </child>
    
    1450
    -            <child>
    
    1451
    -              <object class="GtkFrame">
    
    1452
    -                <property name="visible">True</property>
    
    1453
    -                <property name="can_focus">False</property>
    
    1454
    -                <property name="valign">start</property>
    
    1455
    -                <property name="label_xalign">0</property>
    
    1456
    -                <property name="shadow_type">none</property>
    
    1457
    -                <child>
    
    1458
    -                  <object class="GtkBox">
    
    1459
    -                    <property name="visible">True</property>
    
    1460
    -                    <property name="can_focus">False</property>
    
    1461
    -                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    
    1462
    -                    <property name="valign">start</property>
    
    1463
    -                    <property name="margin_top">6</property>
    
    1464
    -                    <property name="orientation">vertical</property>
    
    1465
    -                    <property name="spacing">6</property>
    
    1466
    -                    <child>
    
    1467
    -                      <object class="GtkCheckButton" id="restore_last_status_checkbutton">
    
    1468
    -                        <property name="label" translatable="yes">_Remember and restore status of the last session</property>
    
    1469
    -                        <property name="visible">True</property>
    
    1470
    -                        <property name="can_focus">True</property>
    
    1471
    -                        <property name="receives_default">False</property>
    
    1472
    -                        <property name="tooltip_text" translatable="yes">If checked, the status and status message used in the last session will be restored</property>
    
    1473
    -                        <property name="halign">start</property>
    
    1474
    -                        <property name="use_underline">True</property>
    
    1475
    -                        <property name="draw_indicator">True</property>
    
    1476
    -                        <signal name="toggled" handler="on_restore_last_status_checkbutton_toggled" swapped="no"/>
    
    1477
    -                      </object>
    
    1478
    -                      <packing>
    
    1479
    -                        <property name="expand">False</property>
    
    1480
    -                        <property name="fill">True</property>
    
    1481
    -                        <property name="position">0</property>
    
    1482
    -                      </packing>
    
    1483
    -                    </child>
    
    1484
    -                    <child>
    
    1485
    -                      <object class="GtkBox">
    
    1486
    -                        <property name="visible">True</property>
    
    1487
    -                        <property name="can_focus">False</property>
    
    1488
    -                        <property name="spacing">12</property>
    
    1489
    -                        <child>
    
    1490
    -                          <object class="GtkLabel">
    
    1491
    -                            <property name="visible">True</property>
    
    1492
    -                            <property name="can_focus">False</property>
    
    1493
    -                            <property name="halign">end</property>
    
    1494
    -                            <property name="label" translatable="yes">Ask for status message when I</property>
    
    1495
    -                            <property name="justify">right</property>
    
    1496
    -                          </object>
    
    1497
    -                          <packing>
    
    1498
    -                            <property name="expand">False</property>
    
    1499
    -                            <property name="fill">False</property>
    
    1500
    -                            <property name="position">0</property>
    
    1501
    -                          </packing>
    
    1502
    -                        </child>
    
    1503
    -                        <child>
    
    1504
    -                          <object class="GtkBox">
    
    1505
    -                            <property name="visible">True</property>
    
    1506
    -                            <property name="can_focus">False</property>
    
    1507
    -                            <property name="spacing">12</property>
    
    1508
    -                            <child>
    
    1509
    -                              <object class="GtkCheckButton" id="prompt_online_status_message_checkbutton">
    
    1510
    -                                <property name="label" translatable="yes">Sign _in</property>
    
    1511
    -                                <property name="visible">True</property>
    
    1512
    -                                <property name="can_focus">True</property>
    
    1513
    -                                <property name="receives_default">False</property>
    
    1514
    -                                <property name="halign">start</property>
    
    1515
    -                                <property name="use_underline">True</property>
    
    1516
    -                                <property name="draw_indicator">True</property>
    
    1517
    -                                <signal name="toggled" handler="on_prompt_online_status_message_checkbutton_toggled" swapped="no"/>
    
    1518
    -                              </object>
    
    1519
    -                              <packing>
    
    1520
    -                                <property name="expand">False</property>
    
    1521
    -                                <property name="fill">False</property>
    
    1522
    -                                <property name="position">0</property>
    
    1523
    -                              </packing>
    
    1524
    -                            </child>
    
    1525
    -                            <child>
    
    1526
    -                              <object class="GtkCheckButton" id="prompt_offline_status_message_checkbutton">
    
    1527
    -                                <property name="label" translatable="yes">Sign _out</property>
    
    1528
    -                                <property name="visible">True</property>
    
    1529
    -                                <property name="can_focus">True</property>
    
    1530
    -                                <property name="receives_default">False</property>
    
    1531
    -                                <property name="halign">start</property>
    
    1532
    -                                <property name="use_underline">True</property>
    
    1533
    -                                <property name="draw_indicator">True</property>
    
    1534
    -                                <signal name="toggled" handler="on_prompt_offline_status_message_checkbutton_toggled" swapped="no"/>
    
    1535
    -                              </object>
    
    1536
    -                              <packing>
    
    1537
    -                                <property name="expand">False</property>
    
    1538
    -                                <property name="fill">False</property>
    
    1539
    -                                <property name="position">1</property>
    
    1540
    -                              </packing>
    
    1541
    -                            </child>
    
    1542
    -                          </object>
    
    1543
    -                          <packing>
    
    1544
    -                            <property name="expand">False</property>
    
    1545
    -                            <property name="fill">False</property>
    
    1546
    -                            <property name="position">1</property>
    
    1547
    -                          </packing>
    
    1548
    -                        </child>
    
    1549
    -                      </object>
    
    1550
    -                      <packing>
    
    1551
    -                        <property name="expand">False</property>
    
    1552
    -                        <property name="fill">False</property>
    
    1553
    -                        <property name="position">1</property>
    
    1554
    -                      </packing>
    
    1555
    -                    </child>
    
    1556
    -                  </object>
    
    1557
    -                </child>
    
    1558
    -                <child type="label">
    
    1559
    -                  <object class="GtkLabel">
    
    1560
    -                    <property name="visible">True</property>
    
    1561
    -                    <property name="can_focus">False</property>
    
    1562
    -                    <property name="label" translatable="yes">Status Messages</property>
    
    1563
    -                    <property name="use_markup">True</property>
    
    1564
    -                    <style>
    
    1565
    -                      <class name="bold"/>
    
    1566
    -                      <class name="margin-top6"/>
    
    1567
    -                    </style>
    
    1568
    -                  </object>
    
    1569
    -                </child>
    
    1570
    -              </object>
    
    1571
    -              <packing>
    
    1572
    -                <property name="expand">True</property>
    
    1573
    -                <property name="fill">True</property>
    
    1574
    -                <property name="position">1</property>
    
    1590
    +                <property name="position">2</property>
    
    1575 1591
                   </packing>
    
    1576 1592
                 </child>
    
    1577
    -            <child>
    
    1578
    -              <placeholder/>
    
    1579
    -            </child>
    
    1580 1593
               </object>
    
    1581 1594
               <packing>
    
    1582 1595
                 <property name="name">status</property>
    

  • gajim/data/gui/status_change_window.ui
    ... ... @@ -48,7 +48,7 @@
    48 48
                     <property name="focus_on_click">False</property>
    
    49 49
                     <property name="receives_default">True</property>
    
    50 50
                     <property name="popover">preset_popover</property>
    
    51
    -                <signal name="toggled" handler="_stop_timeout" swapped="no"/>
    
    51
    +                <signal name="toggled" handler="stop_timeout" swapped="no"/>
    
    52 52
                     <child>
    
    53 53
                       <object class="GtkLabel">
    
    54 54
                         <property name="visible">True</property>
    

  • gajim/gtk/dialogs.py
    ... ... @@ -524,14 +524,21 @@ class TimeoutWindow:
    524 524
         Derived windows close automatically after reaching the timeout
    
    525 525
         """
    
    526 526
         def __init__(self, timeout):
    
    527
    -        self.countdown_left = timeout
    
    528
    -        self.countdown_enabled = True
    
    529 527
             self.title_text = ''
    
    528
    +        self._countdown_left = timeout
    
    529
    +        self._timeout_source_id = None
    
    530 530
     
    
    531
    -    def run_timeout(self):
    
    532
    -        if self.countdown_left > 0:
    
    531
    +    def start_timeout(self):
    
    532
    +        if self._countdown_left > 0:
    
    533 533
                 self.countdown()
    
    534
    -            GLib.timeout_add_seconds(1, self.countdown)
    
    534
    +            self._timeout_source_id = GLib.timeout_add_seconds(
    
    535
    +                1, self.countdown)
    
    536
    +
    
    537
    +    def stop_timeout(self, *args, **kwargs):
    
    538
    +        if self._timeout_source_id is not None:
    
    539
    +            GLib.source_remove(self._timeout_source_id)
    
    540
    +            self._timeout_source_id = None
    
    541
    +        self.set_title(self.title_text)
    
    535 542
     
    
    536 543
         def on_timeout(self):
    
    537 544
             """
    
    ... ... @@ -539,17 +546,15 @@ class TimeoutWindow:
    539 546
             """
    
    540 547
     
    
    541 548
         def countdown(self):
    
    542
    -        if self.countdown_enabled:
    
    543
    -            if self.countdown_left <= 0:
    
    544
    -                self.on_timeout()
    
    545
    -                return False
    
    546
    -            self.set_title('%s [%s]' % (
    
    547
    -                self.title_text, str(self.countdown_left)))
    
    548
    -            self.countdown_left -= 1
    
    549
    -            return True
    
    549
    +        if self._countdown_left <= 0:
    
    550
    +            self._timeout_source_id = None
    
    551
    +            self.on_timeout()
    
    552
    +            return False
    
    550 553
     
    
    551
    -        self.set_title(self.title_text)
    
    552
    -        return False
    
    554
    +        self.set_title('%s [%s]' % (
    
    555
    +            self.title_text, str(self._countdown_left)))
    
    556
    +        self._countdown_left -= 1
    
    557
    +        return True
    
    553 558
     
    
    554 559
     
    
    555 560
     class ShortcutsWindow:
    

  • gajim/gtk/preferences.py
    ... ... @@ -168,7 +168,7 @@ class Preferences(Gtk.ApplicationWindow):
    168 168
             self._ui.join_leave_checkbutton.set_active(st)
    
    169 169
     
    
    170 170
             st = app.config.get('print_status_muc_default')
    
    171
    -        self._ui.status_change_checkbutton.set_active(st)
    
    171
    +        self._ui.show_status_change_checkbutton.set_active(st)
    
    172 172
     
    
    173 173
             # Displayed chat state notifications
    
    174 174
             st = app.config.get('show_chatstate_in_tabs')
    
    ... ... @@ -266,9 +266,11 @@ class Preferences(Gtk.ApplicationWindow):
    266 266
     
    
    267 267
             # Ask for status when online/offline
    
    268 268
             st = app.config.get('ask_online_status')
    
    269
    -        self._ui.prompt_online_status_message_checkbutton.set_active(st)
    
    269
    +        self._ui.sign_in_status_checkbutton.set_active(st)
    
    270 270
             st = app.config.get('ask_offline_status')
    
    271
    -        self._ui.prompt_offline_status_message_checkbutton.set_active(st)
    
    271
    +        self._ui.sign_out_status_checkbutton.set_active(st)
    
    272
    +        st = app.config.get('always_ask_for_status_message')
    
    273
    +        self._ui.status_change_checkbutton.set_active(st)
    
    272 274
     
    
    273 275
             ### Style tab ###
    
    274 276
             # Themes
    
    ... ... @@ -568,7 +570,7 @@ class Preferences(Gtk.ApplicationWindow):
    568 570
             for control in self._get_all_muc_controls():
    
    569 571
                 control.update_actions()
    
    570 572
     
    
    571
    -    def _on_status_change_toggled(self, widget):
    
    573
    +    def _on_show_status_change_toggled(self, widget):
    
    572 574
             self.on_checkbutton_toggled(widget, 'print_status_muc_default')
    
    573 575
             for control in self._get_all_muc_controls():
    
    574 576
                 control.update_actions()
    
    ... ... @@ -665,12 +667,15 @@ class Preferences(Gtk.ApplicationWindow):
    665 667
             widget.set_inconsistent(False)
    
    666 668
             self.on_per_account_checkbutton_toggled(widget, 'restore_last_status')
    
    667 669
     
    
    668
    -    def on_prompt_online_status_message_checkbutton_toggled(self, widget):
    
    670
    +    def on_sign_in_status_checkbutton_toggled(self, widget):
    
    669 671
             self.on_checkbutton_toggled(widget, 'ask_online_status')
    
    670 672
     
    
    671
    -    def on_prompt_offline_status_message_checkbutton_toggled(self, widget):
    
    673
    +    def on_sign_out_status_checkbutton_toggled(self, widget):
    
    672 674
             self.on_checkbutton_toggled(widget, 'ask_offline_status')
    
    673 675
     
    
    676
    +    def on_status_change_checkbutton_toggled(self, widget):
    
    677
    +        self.on_checkbutton_toggled(widget, 'always_ask_for_status_message')
    
    678
    +
    
    674 679
         ### Style ###
    
    675 680
         @staticmethod
    
    676 681
         def on_theme_combobox_changed(combobox):
    

  • gajim/gtk/status_change.py
    ... ... @@ -50,7 +50,7 @@ ACTIVITY_PAGELIST = [
    50 50
     
    
    51 51
     
    
    52 52
     class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    
    53
    -    def __init__(self, callback, account=None, show=None, show_pep=True):
    
    53
    +    def __init__(self, callback=None, account=None, status=None, show_pep=True):
    
    54 54
             Gtk.ApplicationWindow.__init__(self)
    
    55 55
             countdown_time = app.config.get('change_status_window_timeout')
    
    56 56
             TimeoutWindow.__init__(self, countdown_time)
    
    ... ... @@ -64,7 +64,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    64 64
     
    
    65 65
             self.account = account
    
    66 66
             self._callback = callback
    
    67
    -        self._show = show
    
    67
    +        self._status = status
    
    68 68
             self._show_pep = show_pep
    
    69 69
     
    
    70 70
             self._ui = get_builder('status_change_window.ui')
    
    ... ... @@ -80,7 +80,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    80 80
             self._preset_messages_dict = {}
    
    81 81
             self._get_presets()
    
    82 82
     
    
    83
    -        if self._show:
    
    83
    +        if self._status:
    
    84 84
                 self._ui.activity_switch.set_active(self._pep_dict['activity'])
    
    85 85
                 self._ui.activity_page_button.set_sensitive(
    
    86 86
                     self._pep_dict['activity'])
    
    ... ... @@ -100,21 +100,18 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    100 100
                 self._ui.pep_grid.set_no_show_all(True)
    
    101 101
                 self._ui.pep_grid.hide()
    
    102 102
     
    
    103
    -        self._message_buffer.connect('changed', self._stop_timeout)
    
    103
    +        self._message_buffer.connect('changed', self.stop_timeout)
    
    104 104
             self.connect('key-press-event', self._on_key_press)
    
    105 105
             self._ui.connect_signals(self)
    
    106 106
     
    
    107 107
             self.show_all()
    
    108
    -        self.run_timeout()
    
    108
    +        self.start_timeout()
    
    109 109
     
    
    110 110
         def on_timeout(self):
    
    111 111
             self._change_status()
    
    112 112
     
    
    113
    -    def _stop_timeout(self, *args):
    
    114
    -        self.countdown_enabled = False
    
    115
    -
    
    116 113
         def _on_key_press(self, _widget, event):
    
    117
    -        self.countdown_enabled = False
    
    114
    +        self.stop_timeout()
    
    118 115
             if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
    
    119 116
                 if event.get_state() & Gdk.ModifierType.CONTROL_MASK:
    
    120 117
                     self._change_status()
    
    ... ... @@ -374,7 +371,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    374 371
                 self._ui.mood_button_label.set_text(_('No mood'))
    
    375 372
     
    
    376 373
         def _on_preset_select(self, widget):
    
    377
    -        self.countdown_enabled = False
    
    374
    +        self.stop_timeout()
    
    378 375
             self._ui.preset_popover.popdown()
    
    379 376
             name = widget.get_name()
    
    380 377
             self._message_buffer.set_text(self._preset_messages_dict[name][0])
    
    ... ... @@ -390,13 +387,13 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    390 387
             self._ui.mood_page_button.set_sensitive(self._pep_dict['mood'])
    
    391 388
     
    
    392 389
         def _on_preset_remove(self, widget):
    
    393
    -        self.countdown_enabled = False
    
    390
    +        self.stop_timeout()
    
    394 391
             name = widget.get_name()
    
    395 392
             app.config.del_per('statusmsg', name)
    
    396 393
             self._get_presets()
    
    397 394
     
    
    398 395
         def _on_save_as_preset_clicked(self, _widget):
    
    399
    -        self.countdown_enabled = False
    
    396
    +        self.stop_timeout()
    
    400 397
             start_iter, finish_iter = self._message_buffer.get_bounds()
    
    401 398
             message_text = self._message_buffer.get_text(
    
    402 399
                 start_iter, finish_iter, True)
    
    ... ... @@ -452,7 +449,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    452 449
                 transient_for=self).show()
    
    453 450
     
    
    454 451
         def _on_activity_page_clicked(self, _widget):
    
    455
    -        self.countdown_enabled = False
    
    452
    +        self.stop_timeout()
    
    456 453
             self._ui.status_stack.set_visible_child_full(
    
    457 454
                 'activity-page',
    
    458 455
                 Gtk.StackTransitionType.SLIDE_LEFT)
    
    ... ... @@ -467,7 +464,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    467 464
             self._pep_dict['subactivity'] = ''
    
    468 465
     
    
    469 466
         def _on_mood_page_clicked(self, _widget):
    
    470
    -        self.countdown_enabled = False
    
    467
    +        self.stop_timeout()
    
    471 468
             self._ui.status_stack.set_visible_child_full(
    
    472 469
                 'mood-page',
    
    473 470
                 Gtk.StackTransitionType.SLIDE_LEFT)
    
    ... ... @@ -487,24 +484,62 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
    487 484
             self._draw_mood()
    
    488 485
     
    
    489 486
         def _on_activity_switch(self, switch, *args):
    
    490
    -        self.countdown_enabled = False
    
    487
    +        self.stop_timeout()
    
    491 488
             self._ui.activity_page_button.set_sensitive(switch.get_active())
    
    492 489
     
    
    493 490
         def _on_mood_switch(self, switch, *args):
    
    494
    -        self.countdown_enabled = False
    
    491
    +        self.stop_timeout()
    
    495 492
             self._ui.mood_page_button.set_sensitive(switch.get_active())
    
    496 493
     
    
    494
    +    def _send_user_mood(self):
    
    495
    +        mood = None
    
    496
    +        if self._ui.mood_switch.get_active():
    
    497
    +            mood = self._pep_dict['mood']
    
    498
    +
    
    499
    +        for client in app.get_available_clients(self.account):
    
    500
    +            if not app.config.get_per('accounts', client.account,
    
    501
    +                                      'sync_with_global_status'):
    
    502
    +                continue
    
    503
    +            client.set_user_mood(mood)
    
    504
    +
    
    505
    +    def _send_user_activity(self):
    
    506
    +        activity = None
    
    507
    +        if self._ui.activity_switch.get_active():
    
    508
    +            activity = (self._pep_dict['activity'],
    
    509
    +                        self._pep_dict['subactivity'])
    
    510
    +
    
    511
    +        for client in app.get_available_clients(self.account):
    
    512
    +            if not app.config.get_per('accounts', client.account,
    
    513
    +                                      'sync_with_global_status'):
    
    514
    +                continue
    
    515
    +            client.set_user_activity(activity)
    
    516
    +
    
    517
    +    def _send_status_and_message(self, message):
    
    518
    +        if self.account is not None:
    
    519
    +            app.interface.roster.send_status(self.account,
    
    520
    +                                             self._status,
    
    521
    +                                             message)
    
    522
    +            return
    
    523
    +
    
    524
    +        for account in app.connections:
    
    525
    +            if not app.config.get_per('accounts', account,
    
    526
    +                                      'sync_with_global_status'):
    
    527
    +                continue
    
    528
    +
    
    529
    +            app.interface.roster.send_status(account, self._status, message)
    
    530
    +
    
    497 531
         def _change_status(self, *args):
    
    532
    +        self.stop_timeout()
    
    498 533
             beg, end = self._message_buffer.get_bounds()
    
    499 534
             message = self._message_buffer.get_text(beg, end, True).strip()
    
    500 535
             message = remove_invalid_xml_chars(message)
    
    501 536
     
    
    502
    -        if not self._ui.activity_switch.get_active():
    
    503
    -            self._pep_dict['activity'] = ''
    
    504
    -            self._pep_dict['subactivity'] = ''
    
    537
    +        if self._show_pep:
    
    538
    +            self._send_user_activity()
    
    539
    +            self._send_user_mood()
    
    505 540
     
    
    506
    -        if not self._ui.mood_switch.get_active():
    
    507
    -            self._pep_dict['mood'] = ''
    
    508
    -
    
    509
    -        self._callback(message, self._pep_dict)
    
    541
    +        if self._callback is not None:
    
    542
    +            self._callback(message)
    
    543
    +        else:
    
    544
    +            self._send_status_and_message(message)
    
    510 545
             self.destroy()

  • gajim/gtk/status_selector.py
    ... ... @@ -22,7 +22,6 @@ from gajim.common.helpers import statuses_unified
    22 22
     from gajim.common.i18n import _
    
    23 23
     
    
    24 24
     from gajim.gtk.util import get_icon_name
    
    25
    -from gajim.gtk.util import open_window
    
    26 25
     
    
    27 26
     
    
    28 27
     class StatusSelector(Gtk.MenuButton):
    
    ... ... @@ -100,25 +99,11 @@ class StatusSelector(Gtk.MenuButton):
    100 99
             self.set_popover(self._status_popover)
    
    101 100
     
    
    102 101
         def _on_change_status(self, button):
    
    103
    -        def _on_response(message, pep_dict):
    
    104
    -            if message is None:  # None if user canceled
    
    105
    -                return
    
    106
    -            for account in app.contacts.get_accounts():
    
    107
    -                sync_account = app.config.get_per(
    
    108
    -                    'accounts', account, 'sync_with_global_status')
    
    109
    -                if not sync_account:
    
    110
    -                    continue
    
    111
    -                app.interface.roster.send_status(account, new_show, message)
    
    112
    -                app.interface.roster.send_pep(account, pep_dict)
    
    113
    -
    
    114 102
             self._status_popover.popdown()
    
    115
    -        new_show = button.get_name()
    
    116
    -        if new_show == 'change_status_message':
    
    117
    -            new_show = get_global_show()
    
    118
    -            open_window('StatusChange', callback=_on_response, show=new_show)
    
    119
    -            return
    
    120
    -
    
    121
    -        app.interface.roster.get_status_message(new_show, _on_response)
    
    103
    +        new_status = button.get_name()
    
    104
    +        if new_status == 'change_status_message':
    
    105
    +            new_status = None
    
    106
    +        app.interface.change_status(status=new_status)
    
    122 107
     
    
    123 108
         def update(self):
    
    124 109
             show = get_global_show()
    

  • gajim/gtk/statusicon.py
    ... ... @@ -24,8 +24,6 @@ import os
    24 24
     from gi.repository import Gtk
    
    25 25
     from gi.repository import GLib
    
    26 26
     
    
    27
    -from gajim import dialogs
    
    28
    -
    
    29 27
     from gajim.common import app
    
    30 28
     from gajim.common import helpers
    
    31 29
     from gajim.common.i18n import _
    
    ... ... @@ -354,35 +352,8 @@ class StatusIcon:
    354 352
     
    
    355 353
         @staticmethod
    
    356 354
         def _on_show(_widget, show):
    
    357
    -        # we all add some fake (we cannot select those nor have them as show)
    
    358
    -        # but this helps to align with roster's status_combobox index positions
    
    359
    -        status = ['online', 'chat', 'away', 'xa', 'dnd',
    
    360
    -                  'SEPARATOR', 'CHANGE_STATUS_MSG_MENUITEM', 'SEPARATOR',
    
    361
    -                  'offline']
    
    362
    -        index = status.index(show)
    
    363
    -        if not helpers.statuses_unified():
    
    364
    -            app.interface.roster.status_combobox.set_active(index + 2)
    
    365
    -            return
    
    366
    -        current = app.interface.roster.status_combobox.get_active()
    
    367
    -        if index != current:
    
    368
    -            app.interface.roster.status_combobox.set_active(index)
    
    355
    +        app.interface.change_status(status=show)
    
    369 356
     
    
    370 357
         @staticmethod
    
    371 358
         def _on_change_status(_widget):
    
    372
    -        model = app.interface.roster.status_combobox.get_model()
    
    373
    -        active = app.interface.roster.status_combobox.get_active()
    
    374
    -        status = model[active][2]
    
    375
    -        def on_response(message, pep_dict):
    
    376
    -            if message is None: # None if user press Cancel
    
    377
    -                return
    
    378
    -            accounts = app.connections.keys()
    
    379
    -            for acct in accounts:
    
    380
    -                if not app.config.get_per('accounts',
    
    381
    -                                          acct,
    
    382
    -                                          'sync_with_global_status'):
    
    383
    -                    continue
    
    384
    -                show = app.connections[acct].status
    
    385
    -                app.interface.roster.send_status(acct, show, message)
    
    386
    -                app.interface.roster.send_pep(acct, pep_dict)
    
    387
    -        dlg = dialogs.ChangeStatusMessageDialog(on_response, status)
    
    388
    -        dlg.dialog.present()
    359
    +        app.interface.change_status()

  • gajim/gtk/util.py
    ... ... @@ -545,6 +545,12 @@ def format_mood(mood, text):
    545 545
         return markuptext
    
    546 546
     
    
    547 547
     
    
    548
    +def get_account_mood_icon_name(account):
    
    549
    +    client = app.get_client(account)
    
    550
    +    mood = client.get_module('UserMood').get_current_mood()
    
    551
    +    return f'mood-{mood.mood}' if mood is not None else mood
    
    552
    +
    
    553
    +
    
    548 554
     def format_activity(activity, subactivity, text):
    
    549 555
         if activity is None:
    
    550 556
             return None
    
    ... ... @@ -569,6 +575,14 @@ def get_activity_icon_name(activity, subactivity=None):
    569 575
         return icon_name
    
    570 576
     
    
    571 577
     
    
    578
    +def get_account_activity_icon_name(account):
    
    579
    +    client = app.get_client(account)
    
    580
    +    activity = client.get_module('UserActivity').get_current_activity()
    
    581
    +    if activity is None:
    
    582
    +        return None
    
    583
    +    return get_activity_icon_name(activity.activity, activity.subactivity)
    
    584
    +
    
    585
    +
    
    572 586
     def format_tune(artist, _length, _rating, source, title, _track, _uri):
    
    573 587
         if artist is None and title is None and source is None:
    
    574 588
             return None
    
    ... ... @@ -583,6 +597,12 @@ def format_tune(artist, _length, _rating, source, title, _track, _uri):
    583 597
         return tune_string
    
    584 598
     
    
    585 599
     
    
    600
    +def get_account_tune_icon_name(account):
    
    601
    +    client = app.get_client(account)
    
    602
    +    tune = client.get_module('UserTune').get_current_tune()
    
    603
    +    return None if tune is None else 'audio-x-generic'
    
    604
    +
    
    605
    +
    
    586 606
     def format_location(location):
    
    587 607
         location = location._asdict()
    
    588 608
         location_string = ''
    
    ... ... @@ -600,6 +620,12 @@ def format_location(location):
    600 620
         return location_string.strip()
    
    601 621
     
    
    602 622
     
    
    623
    +def get_account_location_icon_name(account):
    
    624
    +    client = app.get_client(account)
    
    625
    +    location = client.get_module('UserLocation').get_current_location()
    
    626
    +    return None if location is None else 'applications-internet'
    
    627
    +
    
    628
    +
    
    603 629
     def format_fingerprint(fingerprint):
    
    604 630
         fplen = len(fingerprint)
    
    605 631
         wordsize = fplen // 8
    

  • gajim/gui_interface.py
    ... ... @@ -75,6 +75,7 @@ from gajim.common import socks5
    75 75
     from gajim.common import helpers
    
    76 76
     from gajim.common import passwords
    
    77 77
     from gajim.common import logging_helpers
    
    78
    +from gajim.common.helpers import ask_for_status_message
    
    78 79
     from gajim.common.structs import MUCData
    
    79 80
     from gajim.common.nec import NetworkEvent
    
    80 81
     from gajim.common.i18n import _
    
    ... ... @@ -809,6 +810,9 @@ class Interface:
    809 810
                     app.config.get_per('accounts', account, 'publish_location')):
    
    810 811
                 location.enable()
    
    811 812
     
    
    813
    +        if ask_for_status_message(obj.conn.status, signin=True):
    
    814
    +            open_window('StatusChange', status=obj.conn.status)
    
    815
    +
    
    812 816
         @staticmethod
    
    813 817
         def show_httpupload_progress(transfer):
    
    814 818
             FileTransferProgress(transfer)
    
    ... ... @@ -1657,31 +1661,58 @@ class Interface:
    1657 1661
             """
    
    1658 1662
             Auto connect at startup
    
    1659 1663
             """
    
    1660
    -        # dict of account that want to connect sorted by status
    
    1661
    -        shows = {}
    
    1662
    -        for a in app.connections:
    
    1663
    -            if app.config.get_per('accounts', a, 'autoconnect'):
    
    1664
    -                if app.config.get_per('accounts', a, 'restore_last_status'):
    
    1665
    -                    self.roster.send_status(a, app.config.get_per('accounts',
    
    1666
    -                        a, 'last_status'), helpers.from_one_line(
    
    1667
    -                        app.config.get_per('accounts', a, 'last_status_msg')))
    
    1668
    -                    continue
    
    1669
    -                show = app.config.get_per('accounts', a, 'autoconnect_as')
    
    1670
    -                if show not in ['online', 'chat', 'away', 'xa', 'dnd']:
    
    1671
    -                    continue
    
    1672
    -                if show not in shows:
    
    1673
    -                    shows[show] = [a]
    
    1674
    -                else:
    
    1675
    -                    shows[show].append(a)
    
    1676
    -        def on_message(message, pep_dict):
    
    1677
    -            if message is None:
    
    1678
    -                return
    
    1679
    -            for a in shows[show]:
    
    1680
    -                self.roster.send_status(a, show, message)
    
    1681
    -                self.roster.send_pep(a, pep_dict)
    
    1682
    -        for show in shows:
    
    1683
    -            self.roster.get_status_message(show, on_message)
    
    1684
    -        return False
    
    1664
    +
    
    1665
    +        for account in app.connections:
    
    1666
    +            if not app.config.get_per('accounts', account, 'autoconnect'):
    
    1667
    +                continue
    
    1668
    +
    
    1669
    +            status = 'online'
    
    1670
    +            status_message = ''
    
    1671
    +
    
    1672
    +            if app.config.get_per('accounts', account, 'restore_last_status'):
    
    1673
    +                status = app.config.get_per('accounts', account, 'last_status')
    
    1674
    +                status_message = app.config.get_per('accounts',
    
    1675
    +                                                    account,
    
    1676
    +                                                    'last_status_msg')
    
    1677
    +                status_message = helpers.from_one_line(status_message)
    
    1678
    +
    
    1679
    +            self.roster.send_status(account, status, status_message)
    
    1680
    +
    
    1681
    +    def change_status(self, status=None):
    
    1682
    +        # status=None means we want to change the message only
    
    1683
    +
    
    1684
    +        ask = ask_for_status_message(status)
    
    1685
    +
    
    1686
    +        if status is None:
    
    1687
    +            status = helpers.get_global_show()
    
    1688
    +
    
    1689
    +        if ask:
    
    1690
    +            open_window('StatusChange', status=status)
    
    1691
    +            return
    
    1692
    +
    
    1693
    +        for account in app.connections:
    
    1694
    +            if not app.config.get_per('accounts', account,
    
    1695
    +                                      'sync_with_global_status'):
    
    1696
    +                continue
    
    1697
    +
    
    1698
    +            message = app.get_client(account).status_message
    
    1699
    +            self.roster.send_status(account, status, message)
    
    1700
    +
    
    1701
    +    def change_account_status(self, account, status=None):
    
    1702
    +        # status=None means we want to change the message only
    
    1703
    +
    
    1704
    +        ask = ask_for_status_message(status)
    
    1705
    +
    
    1706
    +        client = app.get_client(account)
    
    1707
    +        if status is None:
    
    1708
    +            status = client.status
    
    1709
    +
    
    1710
    +        if ask:
    
    1711
    +            open_window('StatusChange', status=status, account=account)
    
    1712
    +            return
    
    1713
    +
    
    1714
    +        message = client.status_message
    
    1715
    +        self.roster.send_status(account, status, message)
    
    1685 1716
     
    
    1686 1717
         def show_systray(self):
    
    1687 1718
             if not app.is_display(Display.WAYLAND):
    

  • gajim/roster_window.py
    ... ... @@ -42,8 +42,6 @@ from gi.repository import GObject
    42 42
     from gi.repository import GLib
    
    43 43
     from gi.repository import Gio
    
    44 44
     from nbxmpp.namespaces import Namespace
    
    45
    -from nbxmpp.structs import MoodData
    
    46
    -from nbxmpp.structs import ActivityData
    
    47 45
     
    
    48 46
     from gajim import dialogs
    
    49 47
     from gajim import vcard
    
    ... ... @@ -55,6 +53,7 @@ from gajim.common import helpers
    55 53
     from gajim.common.exceptions import GajimGeneralException
    
    56 54
     from gajim.common import i18n
    
    57 55
     from gajim.common.helpers import save_roster_position
    
    56
    +from gajim.common.helpers import ask_for_status_message
    
    58 57
     from gajim.common.i18n import _
    
    59 58
     from gajim.common.const import PEPEventType, AvatarSize, StyleAttr
    
    60 59
     from gajim.common.dbus import location
    
    ... ... @@ -84,6 +83,10 @@ from gajim.gtk.util import get_metacontact_surface
    84 83
     from gajim.gtk.util import get_builder
    
    85 84
     from gajim.gtk.util import set_urgency_hint
    
    86 85
     from gajim.gtk.util import get_activity_icon_name
    
    86
    +from gajim.gtk.util import get_account_activity_icon_name
    
    87
    +from gajim.gtk.util import get_account_mood_icon_name
    
    88
    +from gajim.gtk.util import get_account_tune_icon_name
    
    89
    +from gajim.gtk.util import get_account_location_icon_name
    
    87 90
     from gajim.gtk.util import open_window
    
    88 91
     
    
    89 92
     
    
    ... ... @@ -1006,29 +1009,17 @@ class RosterWindow:
    1006 1009
     
    
    1007 1010
             self.model[child_iter][Column.NAME] = GLib.markup_escape_text(account_name)
    
    1008 1011
     
    
    1009
    -        pep_dict = app.connections[account].pep
    
    1010
    -        if app.config.get('show_mood_in_roster') and PEPEventType.MOOD in pep_dict:
    
    1011
    -            self.model[child_iter][Column.MOOD_PIXBUF] = 'mood-%s' % pep_dict[PEPEventType.MOOD].mood
    
    1012
    -        else:
    
    1013
    -            self.model[child_iter][Column.MOOD_PIXBUF] = None
    
    1012
    +        mood_icon_name = get_account_mood_icon_name(account)
    
    1013
    +        self.model[child_iter][Column.MOOD_PIXBUF] = mood_icon_name
    
    1014 1014
     
    
    1015
    -        if app.config.get('show_activity_in_roster') and PEPEventType.ACTIVITY in pep_dict:
    
    1016
    -            activity = pep_dict[PEPEventType.ACTIVITY].activity
    
    1017
    -            subactivity = pep_dict[PEPEventType.ACTIVITY].subactivity
    
    1018
    -            icon_name = get_activity_icon_name(activity, subactivity)
    
    1019
    -            self.model[child_iter][Column.ACTIVITY_PIXBUF] = icon_name
    
    1020
    -        else:
    
    1021
    -            self.model[child_iter][Column.ACTIVITY_PIXBUF] = None
    
    1015
    +        activity_icon_name = get_account_activity_icon_name(account)
    
    1016
    +        self.model[child_iter][Column.ACTIVITY_PIXBUF] = activity_icon_name
    
    1022 1017
     
    
    1023
    -        if app.config.get('show_tunes_in_roster') and PEPEventType.TUNE in pep_dict:
    
    1024
    -            self.model[child_iter][Column.TUNE_ICON] = 'audio-x-generic'
    
    1025
    -        else:
    
    1026
    -            self.model[child_iter][Column.TUNE_ICON] = None
    
    1018
    +        tune_icon_name = get_account_tune_icon_name(account)
    
    1019
    +        self.model[child_iter][Column.TUNE_ICON] = tune_icon_name
    
    1027 1020
     
    
    1028
    -        if app.config.get('show_location_in_roster') and PEPEventType.LOCATION in pep_dict:
    
    1029
    -            self.model[child_iter][Column.LOCATION_ICON] = 'applications-internet'
    
    1030
    -        else:
    
    1031
    -            self.model[child_iter][Column.LOCATION_ICON] = None
    
    1021
    +        location_icon_name = get_account_location_icon_name(account)
    
    1022
    +        self.model[child_iter][Column.LOCATION_ICON] = location_icon_name
    
    1032 1023
     
    
    1033 1024
         def _really_draw_accounts(self):
    
    1034 1025
             for acct in self.accounts_to_draw:
    
    ... ... @@ -2024,27 +2015,11 @@ class RosterWindow:
    2024 2015
                 if not app.account_is_available(account):
    
    2025 2016
                     self.set_connecting_state(account)
    
    2026 2017
     
    
    2027
    -        self.send_status_continue(account, status, txt)
    
    2028
    -
    
    2029
    -    def send_pep(self, account, pep_dict):
    
    2030
    -        connection = app.connections[account]
    
    2031
    -        if 'activity' in pep_dict:
    
    2032
    -            activity = pep_dict['activity']
    
    2033
    -            subactivity = pep_dict.get('subactivity', None)
    
    2034
    -            activity_text = pep_dict.get('activity_text', None)
    
    2035
    -            connection.get_module('UserActivity').set_activity(ActivityData(
    
    2036
    -                activity, subactivity, activity_text))
    
    2037
    -        else:
    
    2038
    -            connection.get_module('UserActivity').set_activity(None)
    
    2039
    -
    
    2040
    -        if 'mood' in pep_dict:
    
    2041
    -            mood = pep_dict['mood']
    
    2042
    -            mood_text = pep_dict.get('mood_text', None)
    
    2043
    -            connection.get_module('UserMood').set_mood(MoodData(mood, mood_text))
    
    2044
    -        else:
    
    2045
    -            connection.get_module('UserMood').set_mood(None)
    
    2018
    +        if status == 'offline':
    
    2019
    +            self.delete_pep(app.get_jid_from_account(account), account)
    
    2046 2020
     
    
    2047
    -        connection.get_module('UserTune').set_tune(None)
    
    2021
    +        app.connections[account].change_status(status, txt)
    
    2022
    +        self._status_selector.update()
    
    2048 2023
     
    
    2049 2024
         def delete_pep(self, jid, account):
    
    2050 2025
             if jid == app.get_jid_from_account(account):
    
    ... ... @@ -2059,13 +2034,6 @@ class RosterWindow:
    2059 2034
             if ctrl:
    
    2060 2035
                 ctrl.update_all_pep_types()
    
    2061 2036
     
    
    2062
    -    def send_status_continue(self, account, status, txt):
    
    2063
    -        if status == 'offline':
    
    2064
    -            self.delete_pep(app.get_jid_from_account(account), account)
    
    2065
    -
    
    2066
    -        app.connections[account].change_status(status, txt)
    
    2067
    -        self._status_selector.update()
    
    2068
    -
    
    2069 2037
         def chg_contact_status(self, contact, show, status_message, account):
    
    2070 2038
             """
    
    2071 2039
             When a contact changes their status
    
    ... ... @@ -2159,36 +2127,8 @@ class RosterWindow:
    2159 2127
                 app.interface.systray.change_status(show)
    
    2160 2128
             self._status_selector.update()
    
    2161 2129
     
    
    2162
    -    def get_status_message(self, show, callback, show_pep=True,
    
    2163
    -                           always_ask=False):
    
    2164
    -        """
    
    2165
    -        Get the status message by:
    
    2166
    -
    
    2167
    -        asking to user if needed depending on ask_on(ff)line_status and
    
    2168
    -            always_ask
    
    2169
    -        show_pep can be False to hide pep things from status message or True
    
    2170
    -        """
    
    2171
    -        empty_pep = {'activity': '',
    
    2172
    -                     'subactivity': '',
    
    2173
    -                     'activity_text': '',
    
    2174
    -                     'mood': '',
    
    2175
    -                     'mood_text': ''}
    
    2176
    -        if not always_ask and ((show == 'online' and not app.config.get(
    
    2177
    -                'ask_online_status')) or (show == 'offline' and not
    
    2178
    -                app.config.get('ask_offline_status'))):
    
    2179
    -            callback('', empty_pep)
    
    2180
    -            return
    
    2181
    -
    
    2182
    -        open_window('StatusChange', callback=callback, show=show,
    
    2183
    -                    show_pep=show_pep)
    
    2184
    -
    
    2185
    -    def change_status(self, widget, account, status):
    
    2186
    -        def _on_response(message, pep_dict):
    
    2187
    -            if message is None:  # None if user canceled
    
    2188
    -                return
    
    2189
    -            self.send_status(account, status, message)
    
    2190
    -            self.send_pep(account, pep_dict)
    
    2191
    -        self.get_status_message(status, _on_response)
    
    2130
    +    def change_status(self, _widget, account, status):
    
    2131
    +        app.interface.change_account_status(account, status=status)
    
    2192 2132
     
    
    2193 2133
         def get_show(self, lcontact):
    
    2194 2134
             prio = lcontact[0].priority
    
    ... ... @@ -2311,7 +2251,7 @@ class RosterWindow:
    2311 2251
                     get_msg = True
    
    2312 2252
                     break
    
    2313 2253
     
    
    2314
    -        def on_continue3(message, pep_dict):
    
    2254
    +        def on_continue3(message):
    
    2315 2255
                 self.quit_on_next_offline = 0
    
    2316 2256
                 accounts_to_disconnect = []
    
    2317 2257
                 for acct in accounts:
    
    ... ... @@ -2326,11 +2266,10 @@ class RosterWindow:
    2326 2266
     
    
    2327 2267
                 for acct in accounts_to_disconnect:
    
    2328 2268
                     self.send_status(acct, 'offline', message)
    
    2329
    -                self.send_pep(acct, pep_dict)
    
    2330 2269
     
    
    2331
    -        def on_continue2(message, pep_dict):
    
    2270
    +        def on_continue2(message):
    
    2332 2271
                 if 'file_transfers' not in app.interface.instances:
    
    2333
    -                on_continue3(message, pep_dict)
    
    2272
    +                on_continue3(message)
    
    2334 2273
                     return
    
    2335 2274
                 # check if there is an active file transfer
    
    2336 2275
                 from gajim.common.modules.bytestream import is_transfer_active
    
    ... ... @@ -2354,12 +2293,11 @@ class RosterWindow:
    2354 2293
                          DialogButton.make('Remove',
    
    2355 2294
                                            text=_('_Quit'),
    
    2356 2295
                                            callback=on_continue3,
    
    2357
    -                                       args=[message,
    
    2358
    -                                             pep_dict])]).show()
    
    2296
    +                                       args=[message])]).show()
    
    2359 2297
                     return
    
    2360
    -            on_continue3(message, pep_dict)
    
    2298
    +            on_continue3(message)
    
    2361 2299
     
    
    2362
    -        def on_continue(message, pep_dict):
    
    2300
    +        def on_continue(message):
    
    2363 2301
                 if message is None:
    
    2364 2302
                     # user pressed Cancel to change status message dialog
    
    2365 2303
                     return
    
    ... ... @@ -2396,15 +2334,17 @@ class RosterWindow:
    2396 2334
                          DialogButton.make('Remove',
    
    2397 2335
                                            text=_('_Quit'),
    
    2398 2336
                                            callback=on_continue2,
    
    2399
    -                                       args=[message,
    
    2400
    -                                             pep_dict])]).show()
    
    2337
    +                                       args=[message])]).show()
    
    2401 2338
                     return
    
    2402
    -            on_continue2(message, pep_dict)
    
    2339
    +            on_continue2(message)
    
    2403 2340
     
    
    2404
    -        if get_msg:
    
    2405
    -            self.get_status_message('offline', on_continue, show_pep=False)
    
    2341
    +        if get_msg and ask_for_status_message('offline'):
    
    2342
    +            open_window('StatusChange',
    
    2343
    +                        status='offline',
    
    2344
    +                        callback=on_continue,
    
    2345
    +                        show_pep=False)
    
    2406 2346
             else:
    
    2407
    -            on_continue('', None)
    
    2347
    +            on_continue('')
    
    2408 2348
     
    
    2409 2349
         def _nec_presence_received(self, obj):
    
    2410 2350
             account = obj.conn.name
    
    ... ... @@ -2925,15 +2865,8 @@ class RosterWindow:
    2925 2865
                 input_str=name,
    
    2926 2866
                 transient_for=self.window).show()
    
    2927 2867
     
    
    2928
    -    def on_change_status_message_activate(self, widget, account):
    
    2929
    -        show = app.connections[account].status
    
    2930
    -        def _on_response(message, pep_dict):
    
    2931
    -            if message is None:  # None if user canceled
    
    2932
    -                return
    
    2933
    -            self.send_status(account, show, message)
    
    2934
    -            self.send_pep(account, pep_dict)
    
    2935
    -        open_window('StatusChange', account=account, callback=_on_response,
    
    2936
    -                    show=show)
    
    2868
    +    def on_change_status_message_activate(self, _widget, account):
    
    2869
    +        app.interface.change_account_status(account)
    
    2937 2870
     
    
    2938 2871
         def on_add_to_roster(self, widget, contact, account):
    
    2939 2872
             AddNewContactWindow(account, contact.jid, contact.name)
    
    ... ... @@ -3029,17 +2962,7 @@ class RosterWindow:
    3029 2962
             # CTRL mask
    
    3030 2963
             if modifier & Gdk.ModifierType.CONTROL_MASK:
    
    3031 2964
                 if keyval == Gdk.KEY_s:  # CTRL + s
    
    3032
    -                show = helpers.get_global_show()
    
    3033
    -                def _on_response(message, pep_dict):
    
    3034
    -                    if message is not None:  # None if user canceled
    
    3035
    -                        for account in app.contacts.get_accounts():
    
    3036
    -                            sync_account = app.config.get_per(
    
    3037
    -                                'accounts', account, 'sync_with_global_status')
    
    3038
    -                            if not sync_account:
    
    3039
    -                                continue
    
    3040
    -                            self.send_status(account, show, message)
    
    3041
    -                            self.send_pep(account, pep_dict)
    
    3042
    -                open_window('StatusChange', callback=_on_response, show=show)
    
    2965
    +                app.interface.change_status()
    
    3043 2966
                     return True
    
    3044 2967
                 if keyval == Gdk.KEY_k:  # CTRL + k
    
    3045 2968
                     self.enable_rfilter('')
    
    ... ... @@ -3079,22 +3002,13 @@ class RosterWindow:
    3079 3002
                     account = model[path][Column.ACCOUNT]
    
    3080 3003
                     if account != 'all':
    
    3081 3004
                         if app.account_is_available(account):
    
    3082
    -                        self.on_change_status_message_activate(widget, account)
    
    3005
    +                        app.interface.change_account_status(account)
    
    3083 3006
                         return True
    
    3007
    +
    
    3084 3008
                     show = helpers.get_global_show()
    
    3085 3009
                     if show == 'offline':
    
    3086 3010
                         return True
    
    3087
    -                def _on_response(message, pep_dict):
    
    3088
    -                    if message is None:  # None if user canceled
    
    3089
    -                        return True
    
    3090
    -                    for acct in app.connections:
    
    3091
    -                        if not app.config.get_per('accounts', acct,
    
    3092
    -                                'sync_with_global_status'):
    
    3093
    -                            continue
    
    3094
    -                        current_show = app.connections[acct].status
    
    3095
    -                        self.send_status(acct, current_show, message)
    
    3096
    -                        self.send_pep(acct, pep_dict)
    
    3097
    -                open_window('StatusChange', callback=_on_response, show=show)
    
    3011
    +                app.interface.change_status()
    
    3098 3012
                 return True
    
    3099 3013
     
    
    3100 3014
             if event.button == 1: # Left click
    
    ... ... @@ -3218,17 +3132,20 @@ class RosterWindow:
    3218 3132
     
    
    3219 3133
         def on_publish_tune_toggled(self, widget, account):
    
    3220 3134
             active = widget.get_active()
    
    3221
    -        app.connections[account].get_module('UserTune').set_enabled(active)
    
    3135
    +        client = app.get_client(account)
    
    3136
    +        client.get_module('UserTune').set_enabled(active)
    
    3222 3137
     
    
    3223 3138
         def on_publish_location_toggled(self, widget, account):
    
    3224 3139
             active = widget.get_active()
    
    3140
    +        client = app.get_client(account)
    
    3225 3141
             app.config.set_per('accounts', account, 'publish_location', active)
    
    3226 3142
             if active:
    
    3227 3143
                 location.enable()
    
    3228 3144
             else:
    
    3229
    -            app.connections[account].get_module('UserLocation').set_location(None)
    
    3145
    +            client = app.get_client(account)
    
    3146
    +            client.set_user_location(None)
    
    3230 3147
     
    
    3231
    -        app.connections[account].get_module('Caps').update_caps()
    
    3148
    +        client.get_module('Caps').update_caps()
    
    3232 3149
     
    
    3233 3150
         def on_add_new_contact(self, widget, account):
    
    3234 3151
             AddNewContactWindow(account)