Philipp Hörist pushed to branch mainwindow at gajim / gajim
Commits:
-
abc60184
by lovetox at 2021-02-05T16:40:23+01:00
6 changed files:
- gajim/common/modules/chatstates.py
- gajim/groupchat_control.py
- gajim/gtk/chat_list.py
- gajim/gtk/chat_list_stack.py
- gajim/gtk/main.py
- gajim/gtk/util.py
Changes:
| ... | ... | @@ -135,6 +135,7 @@ def _presence_received(self, |
| 135 | 135 |
app.nec.push_outgoing_event(
|
| 136 | 136 |
NetworkEvent('chatstate-received',
|
| 137 | 137 |
account=self._account,
|
| 138 |
+ jid=contact.jid,
|
|
| 138 | 139 |
contact=contact))
|
| 139 | 140 |
|
| 140 | 141 |
def _process_chatstate(self, _con, _stanza, properties):
|
| ... | ... | @@ -163,6 +164,7 @@ def _process_chatstate(self, _con, _stanza, properties): |
| 163 | 164 |
app.nec.push_outgoing_event(
|
| 164 | 165 |
NetworkEvent('chatstate-received',
|
| 165 | 166 |
account=self._account,
|
| 167 |
+ jid=contact.jid,
|
|
| 166 | 168 |
contact=contact))
|
| 167 | 169 |
|
| 168 | 170 |
@ensure_enabled
|
| ... | ... | @@ -963,7 +963,7 @@ def check_focus_out_line(self): |
| 963 | 963 |
- remove previous line first
|
| 964 | 964 |
"""
|
| 965 | 965 |
|
| 966 |
- if app.window.is_chat_focused(self.account, self.room_jid):
|
|
| 966 |
+ if app.window.is_chat_active(self.account, self.room_jid):
|
|
| 967 | 967 |
return
|
| 968 | 968 |
|
| 969 | 969 |
self.conv_textview.show_focus_out_line()
|
| ... | ... | @@ -37,6 +37,9 @@ def __init__(self, workspace_id): |
| 37 | 37 |
|
| 38 | 38 |
self.show_all()
|
| 39 | 39 |
|
| 40 |
+ def is_visible(self):
|
|
| 41 |
+ return self.get_parent().get_property('child-widget') == self
|
|
| 42 |
+ |
|
| 40 | 43 |
def _on_destroy(self):
|
| 41 | 44 |
GLib.source_remove(self._timer_id)
|
| 42 | 45 |
|
| ... | ... | @@ -101,12 +104,11 @@ def remove_chat(self, account, jid): |
| 101 | 104 |
self.remove(row)
|
| 102 | 105 |
row.destroy()
|
| 103 | 106 |
|
| 104 |
- def get_active_chat(self):
|
|
| 107 |
+ def get_selected_chat(self):
|
|
| 105 | 108 |
row = self.get_selected_row()
|
| 106 | 109 |
if row is None:
|
| 107 | 110 |
return None
|
| 108 |
- |
|
| 109 |
- return (row.account, row.jid)
|
|
| 111 |
+ return row
|
|
| 110 | 112 |
|
| 111 | 113 |
def contains_chat(self, account, jid):
|
| 112 | 114 |
return self._chats.get((account, jid)) is not None
|
| ... | ... | @@ -132,9 +134,7 @@ def _on_message_received(self, event): |
| 132 | 134 |
return
|
| 133 | 135 |
|
| 134 | 136 |
row = self._chats.get((event.account, event.jid))
|
| 135 |
- if not (row.is_selected() and
|
|
| 136 |
- self.get_toplevel().get_property('has-toplevel-focus')):
|
|
| 137 |
- row.add_unread()
|
|
| 137 |
+ row.add_unread()
|
|
| 138 | 138 |
row.set_last_message_text('Me', event.msgtxt)
|
| 139 | 139 |
|
| 140 | 140 |
|
| ... | ... | @@ -218,6 +218,11 @@ def __init__(self, workspace_id, account, jid, type_): |
| 218 | 218 |
|
| 219 | 219 |
self.show_all()
|
| 220 | 220 |
|
| 221 |
+ @property
|
|
| 222 |
+ def is_active(self):
|
|
| 223 |
+ return (self.is_selected() and
|
|
| 224 |
+ self.get_toplevel().get_property('is-active'))
|
|
| 225 |
+ |
|
| 221 | 226 |
def _on_state_flags_changed(self, _listboxrow, *args):
|
| 222 | 227 |
state = self.get_state_flags()
|
| 223 | 228 |
if (state & Gtk.StateFlags.PRELIGHT) != 0:
|
| ... | ... | @@ -233,10 +238,20 @@ def update_time(self): |
| 233 | 238 |
self._ui.timestamp_label.set_text(
|
| 234 | 239 |
get_uf_relative_time(self._timestamp))
|
| 235 | 240 |
|
| 241 |
+ def _update_unread(self):
|
|
| 242 |
+ print('Update unread', self.account, self.jid, self._unread_count)
|
|
| 243 |
+ self._ui.unread_label.set_text(str(self._unread_count))
|
|
| 244 |
+ self._ui.unread_label.set_visible(bool(self._unread_count))
|
|
| 245 |
+ |
|
| 236 | 246 |
def add_unread(self):
|
| 247 |
+ if self.is_active:
|
|
| 248 |
+ return
|
|
| 237 | 249 |
self._unread_count += 1
|
| 238 |
- self._ui.unread_label.set_text(str(self._unread_count))
|
|
| 239 |
- self._ui.unread_label.show()
|
|
| 250 |
+ self._update_unread()
|
|
| 251 |
+ |
|
| 252 |
+ def reset_unread(self):
|
|
| 253 |
+ self._unread_count = 0
|
|
| 254 |
+ self._update_unread()
|
|
| 240 | 255 |
|
| 241 | 256 |
def set_last_message_text(self, nickname, text):
|
| 242 | 257 |
self._ui.message_label.set_text(text)
|
| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 |
|
| 13 | 13 |
|
| 14 | 14 |
class ChatListStack(Gtk.Stack):
|
| 15 |
- def __init__(self, ui, chat_stack):
|
|
| 15 |
+ def __init__(self, main_window, ui, chat_stack):
|
|
| 16 | 16 |
Gtk.Stack.__init__(self)
|
| 17 | 17 |
self.set_hexpand(True)
|
| 18 | 18 |
self.set_vexpand(True)
|
| ... | ... | @@ -28,19 +28,30 @@ def __init__(self, ui, chat_stack): |
| 28 | 28 |
self._ui.search_entry.connect(
|
| 29 | 29 |
'search-changed', self._on_search_changed)
|
| 30 | 30 |
|
| 31 |
- def get_active_chat(self):
|
|
| 31 |
+ main_window.connect('notify::is-active', self._on_window_active)
|
|
| 32 |
+ |
|
| 33 |
+ def _on_window_active(self, window, _param):
|
|
| 34 |
+ is_active = window.get_property('is-active')
|
|
| 35 |
+ if is_active:
|
|
| 36 |
+ chat = self.get_selected_chat()
|
|
| 37 |
+ if chat is not None:
|
|
| 38 |
+ chat.reset_unread()
|
|
| 39 |
+ |
|
| 40 |
+ def get_selected_chat(self):
|
|
| 32 | 41 |
workspace_id = self.get_visible_child_name()
|
| 33 | 42 |
if workspace_id == 'empty':
|
| 34 | 43 |
return None
|
| 35 | 44 |
|
| 36 | 45 |
chat_list = self._chat_lists[workspace_id]
|
| 37 |
- return chat_list.get_active_chat()
|
|
| 46 |
+ return chat_list.get_selected_chat()
|
|
| 38 | 47 |
|
| 39 | 48 |
def is_chat_active(self, account, jid):
|
| 40 |
- active = self.get_active_chat()
|
|
| 41 |
- if active is None:
|
|
| 49 |
+ chat = self.get_selected_chat()
|
|
| 50 |
+ if chat is None:
|
|
| 42 | 51 |
return False
|
| 43 |
- return active == (account, jid)
|
|
| 52 |
+ if chat.account != account or chat.jid != jid:
|
|
| 53 |
+ return False
|
|
| 54 |
+ return chat.is_active
|
|
| 44 | 55 |
|
| 45 | 56 |
def _on_search_changed(self, search_entry):
|
| 46 | 57 |
chat_list = self.get_visible_child()
|
| ... | ... | @@ -67,7 +78,10 @@ def _on_row_selected(self, _chat_list, row): |
| 67 | 78 |
if row is None:
|
| 68 | 79 |
self._chat_stack.clear()
|
| 69 | 80 |
return
|
| 81 |
+ |
|
| 70 | 82 |
self._chat_stack.show_chat(row.account, row.jid)
|
| 83 |
+ if row.is_active:
|
|
| 84 |
+ row.reset_unread()
|
|
| 71 | 85 |
|
| 72 | 86 |
def show_chat_list(self, workspace_id):
|
| 73 | 87 |
current_workspace_id = self.get_visible_child_name()
|
| ... | ... | @@ -45,7 +45,7 @@ def __init__(self): |
| 45 | 45 |
self.add(self._ui.main_grid)
|
| 46 | 46 |
|
| 47 | 47 |
self._chat_stack = ChatStack()
|
| 48 |
- self._chat_list_stack = ChatListStack(self._ui, self._chat_stack)
|
|
| 48 |
+ self._chat_list_stack = ChatListStack(self, self._ui, self._chat_stack)
|
|
| 49 | 49 |
self._ui.chat_list_scrolled.add(self._chat_list_stack)
|
| 50 | 50 |
|
| 51 | 51 |
self._account_side_bar = AccountSideBar()
|
| ... | ... | @@ -158,10 +158,7 @@ def get_workspace_bar(self): |
| 158 | 158 |
def get_active_workspace(self):
|
| 159 | 159 |
return self._workspace_side_bar.get_active_workspace()
|
| 160 | 160 |
|
| 161 |
- def get_active_chat(self):
|
|
| 162 |
- return self._chat_list_stack.get_active_chat()
|
|
| 163 |
- |
|
| 164 |
- def is_chat_focused(self, account, jid):
|
|
| 161 |
+ def is_chat_active(self, account, jid):
|
|
| 165 | 162 |
if not self.get_property('has-toplevel-focus'):
|
| 166 | 163 |
return False
|
| 167 | 164 |
return self._chat_list_stack.is_chat_active(account, jid)
|
| ... | ... | @@ -856,3 +856,36 @@ def _destroy(*args): |
| 856 | 856 |
|
| 857 | 857 |
def check_finalize(obj, name):
|
| 858 | 858 |
weakref.finalize(obj, print, f'{name} has been finalized')
|
| 859 |
+ |
|
| 860 |
+ |
|
| 861 |
+def _connect_destroy(sender, func, detailed_signal, handler, *args, **kwargs):
|
|
| 862 |
+ """Connect a bound method to a foreign object signal and disconnect
|
|
| 863 |
+ if the object the method is bound to emits destroy (Gtk.Widget subclass).
|
|
| 864 |
+ Also works if the handler is a nested function in a method and
|
|
| 865 |
+ references the method's bound object.
|
|
| 866 |
+ This solves the problem that the sender holds a strong reference
|
|
| 867 |
+ to the bound method and the bound to object doesn't get GCed.
|
|
| 868 |
+ """
|
|
| 869 |
+ |
|
| 870 |
+ if hasattr(handler, "__self__"):
|
|
| 871 |
+ obj = handler.__self__
|
|
| 872 |
+ else:
|
|
| 873 |
+ # XXX: get the "self" var of the enclosing scope.
|
|
| 874 |
+ # Used for nested functions which ref the object but aren't methods.
|
|
| 875 |
+ # In case they don't ref "self" normal connect() should be used anyway.
|
|
| 876 |
+ index = handler.__code__.co_freevars.index("self")
|
|
| 877 |
+ obj = handler.__closure__[index].cell_contents
|
|
| 878 |
+ |
|
| 879 |
+ assert obj is not sender
|
|
| 880 |
+ |
|
| 881 |
+ handler_id = func(detailed_signal, handler, *args, **kwargs)
|
|
| 882 |
+ |
|
| 883 |
+ def disconnect_cb(*args):
|
|
| 884 |
+ sender.disconnect(handler_id)
|
|
| 885 |
+ |
|
| 886 |
+ obj.connect('destroy', disconnect_cb)
|
|
| 887 |
+ return handler_id
|
|
| 888 |
+ |
|
| 889 |
+ |
|
| 890 |
+def connect_destroy(sender, *args, **kwargs):
|
|
| 891 |
+ return _connect_destroy(sender, sender.connect, *args, **kwargs)
|