Commit abdca0ea authored by Philipp Hörist's avatar Philipp Hörist
Browse files

Fix TextView scrolling

Fixes #8813
parent 25e123a3
......@@ -305,13 +305,9 @@ def __init__(self, type_id, parent_win, widget_name, contact, acct,
'conversation_scrolledwindow')
self.conv_scrolledwindow.add(self.conv_textview.tv)
widget = self.conv_scrolledwindow.get_vadjustment()
id_ = widget.connect('value-changed',
self.on_conversation_vadjustment_value_changed)
self.handlers[id_] = widget
id_ = widget.connect('changed',
self.on_conversation_vadjustment_changed)
self.handlers[id_] = widget
self.was_at_the_end = True
self.correcting = False
self.last_sent_msg = None
......@@ -965,7 +961,7 @@ def print_conversation_line(self, text, kind, name, tim,
full_jid = self.get_full_jid()
textview = self.conv_textview
end = False
if self.was_at_the_end or kind == 'outgoing':
if self.conv_textview.autoscroll or kind == 'outgoing':
end = True
if other_tags_for_name is None:
......@@ -1201,7 +1197,7 @@ def set_control_active(self, state):
if state:
self.set_emoticon_popover()
jid = self.contact.jid
if self.was_at_the_end:
if self.conv_textview.autoscroll:
# we are at the end
type_ = ['printed_' + self.type_id]
if self.type_id == message_control.TYPE_GC:
......@@ -1221,21 +1217,14 @@ def set_control_active(self, state):
else:
self.send_chatstate('inactive', self.contact)
def scroll_to_end_iter(self):
self.conv_textview.scroll_to_end_iter()
return False
def scroll_to_end(self, force=False):
self.conv_textview.scroll_to_end(force)
def on_conversation_vadjustment_changed(self, adjustment):
# used to stay at the end of the textview when we shrink conversation
# textview.
if self.was_at_the_end:
self.scroll_to_end_iter()
self.was_at_the_end = (adjustment.get_upper() - adjustment.get_value()\
- adjustment.get_page_size()) < 18
def on_conversation_vadjustment_value_changed(self, adjustment):
self.was_at_the_end = (adjustment.get_upper() - adjustment.get_value() \
- adjustment.get_page_size()) < 18
def _on_edge_reached(self, scrolledwindow, pos):
if pos != Gtk.PositionType.BOTTOM:
return
# Remove all events and set autoscroll True
self.conv_textview.autoscroll = True
if self.resource:
jid = self.contact.get_full_jid()
else:
......@@ -1252,8 +1241,7 @@ def on_conversation_vadjustment_value_changed(self, adjustment):
return
if not self.parent_win:
return
if self.conv_textview.at_the_end() and \
self.parent_win.get_active_control() == self and \
if self.parent_win.get_active_control() == self and \
self.parent_win.window.is_active():
# we are at the end
if self.type_id == message_control.TYPE_GC:
......@@ -1264,6 +1252,18 @@ def on_conversation_vadjustment_value_changed(self, adjustment):
# There were events to remove
self.redraw_after_event_removed(jid)
def _on_scroll(self, widget, event):
# On scrolliung UP disable autoscroll
has_direction, direction = event.get_scroll_direction()
if has_direction and direction == Gdk.ScrollDirection.UP:
# Check if we have a Scrollbar
adjustment = self.conv_scrolledwindow.get_vadjustment()
if adjustment.get_upper() != adjustment.get_page_size():
self.conv_textview.autoscroll = False
def on_conversation_vadjustment_changed(self, adjustment):
self.scroll_to_end()
def redraw_after_event_removed(self, jid):
"""
We just removed a 'printed_*' event, redraw contact in roster or
......@@ -1344,7 +1344,7 @@ def widget_set_visible(self, widget, state):
"""
# make the last message visible, when changing to "full view"
if not state:
GLib.idle_add(self.conv_textview.scroll_to_end_iter)
self.scroll_to_end()
widget.set_no_show_all(state)
if state:
......
......@@ -206,7 +206,7 @@ def __init__(self, account, used_in_history_window = False):
self.last_sent_message_id = None
# last_received_message_id[name] = (msg_stanza_id, line_start_mark)
self.last_received_message_id = {}
self.autoscroll = True
# connect signals
id_ = self.tv.connect('populate_popup', self.on_textview_populate_popup)
self.handlers[id_] = self.tv
......@@ -370,16 +370,9 @@ def update_tags(self):
self.tv.tagXMPP.set_property('foreground', color)
self.tv.tagSthAtSth.set_property('foreground', color)
def at_the_end(self):
return gtkgui_helpers.at_the_end(self.tv.get_parent())
def scroll_to_end_iter(self):
buffer_ = self.tv.get_buffer()
end_iter = buffer_.get_end_iter()
if not end_iter:
return False
self.tv.scroll_to_iter(end_iter, 0, False, 1, 1)
return False # when called in an idle_add, just do it once
def scroll_to_end(self, force=False):
if self.autoscroll or force:
gtkgui_helpers.scroll_to_end(self.tv.get_parent())
def correct_message(self, correct_id, kind, name):
allowed = True
......@@ -449,7 +442,7 @@ def show_xep0184_ack(self, id_):
buffer_.end_user_action()
del self.xep0184_marks[id_]
def show_focus_out_line(self, scroll=True):
def show_focus_out_line(self):
if not self.allow_focus_out_line:
# if room did not receive focus-in from the last time we added
# --- line then do not readd
......@@ -505,11 +498,7 @@ def show_focus_out_line(self, scroll=True):
buffer_.get_end_iter(), left_gravity=True)
buffer_.end_user_action()
if scroll:
# scroll to the end (via idle in case the scrollbar has
# appeared)
GLib.idle_add(self.scroll_to_end_iter)
self.scroll_to_end()
def clear(self, tv = None):
"""
......@@ -1231,9 +1220,9 @@ def print_conversation_line(self, text, jid, kind, name, tim,
self.last_sent_message_id = (msg_stanza_id, new_mark)
if not insert_mark:
if self.at_the_end() or kind == 'outgoing':
if self.autoscroll or kind == 'outgoing':
# we are at the end or we are sending something
GLib.idle_add(self.scroll_to_end_iter)
self.scroll_to_end(force=True)
self.just_cleared = False
buffer_.end_user_action()
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<!-- Generated with glade 3.21.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="adjustment1">
......@@ -594,6 +594,8 @@
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="overlay_scrolling">False</property>
<signal name="edge-reached" handler="_on_edge_reached" swapped="no"/>
<signal name="scroll-event" handler="_on_scroll" swapped="no"/>
<child>
<placeholder/>
</child>
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<!-- Generated with glade 3.21.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkMenu" id="formattings_menu">
......@@ -187,6 +187,8 @@
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="overlay_scrolling">False</property>
<signal name="edge-reached" handler="_on_edge_reached" swapped="no"/>
<signal name="scroll-event" handler="_on_scroll" swapped="no"/>
<child>
<placeholder/>
</child>
......
......@@ -1380,8 +1380,7 @@ def check_and_possibly_add_focus_out_line(self):
# we have full focus (we are reading it!)
return
at_the_end = self.conv_textview.at_the_end()
self.conv_textview.show_focus_out_line(scroll=at_the_end)
self.conv_textview.show_focus_out_line()
def needs_visual_notification(self, text):
"""
......
......@@ -1814,8 +1814,8 @@ def handle_event(self, account, fjid, type_):
w.window.present()
# Using isinstance here because we want to catch all derived types
if isinstance(ctrl, ChatControlBase):
tv = ctrl.conv_textview
tv.scroll_to_end_iter()
ctrl.scroll_to_end()
def join_gc_minimal(self, account, room_jid, password=None):
if account is not None:
......
......@@ -292,16 +292,10 @@ def new_tab(self, control):
self._controls[control.account][fjid] = control
if self.get_num_controls() == 2:
# is first conversation_textview scrolled down ?
scrolled = False
first_widget = self.notebook.get_nth_page(0)
ctrl = self._widget_to_control(first_widget)
conv_textview = ctrl.conv_textview
if conv_textview.at_the_end():
scrolled = True
self.notebook.set_show_tabs(True)
if scrolled:
GLib.idle_add(conv_textview.scroll_to_end_iter)
ctrl.scroll_to_end()
# Add notebook page and connect up to the tab's close button
xml = gtkgui_helpers.get_gtk_builder('message_window.ui', 'chat_tab_ebox')
......
......@@ -2723,7 +2723,7 @@ def _nec_decrypted_message_received(self, obj):
xep0184_id=xep0184_id, additional_data=obj.additional_data)
if obj.msg_log_id:
pw = obj.session.control.parent_win
end = obj.session.control.was_at_the_end
end = obj.session.control.conv_textview.autoscroll
if not pw or (pw.get_active_control() and obj.session.control \
== pw.get_active_control() and pw.is_active() and end):
app.logger.set_read_messages([obj.msg_log_id])
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment