From fe73e498295b887cbcb1f67df0c5d7c7be5791cb Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 01/10] journal: treat every state but fully-obscured as visible The == comparison read every visibility state backwards, so the chooser's list stopped updating while it was on screen. --- src/jarabe/journal/objectchooser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jarabe/journal/objectchooser.py b/src/jarabe/journal/objectchooser.py index 00ff5f0ec8..084f280d5b 100644 --- a/src/jarabe/journal/objectchooser.py +++ b/src/jarabe/journal/objectchooser.py @@ -150,7 +150,7 @@ def __volume_changed_cb(self, volume_toolbar, mount_point): def __visibility_notify_event_cb(self, window, event): logging.debug('visibility_notify_event_cb %r', self) - visible = event.get_state() == Gdk.VisibilityState.FULLY_OBSCURED + visible = event.get_state() != Gdk.VisibilityState.FULLY_OBSCURED if not self._show_preview: self._list_view.set_is_visible(visible) else: From 1d6a8ffb478391325ec436bca62035dda844cddd Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 02/10] journal: fill only the filter backdrop rectangle cr.paint() ignores the rectangle path and floods the whole surface; cr.fill() honors it. --- src/jarabe/journal/journaltoolbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jarabe/journal/journaltoolbox.py b/src/jarabe/journal/journaltoolbox.py index a71f37b09a..f577d281b5 100644 --- a/src/jarabe/journal/journaltoolbox.py +++ b/src/jarabe/journal/journaltoolbox.py @@ -997,7 +997,7 @@ def do_draw(self, cr): # draw a black background, has been done by the engine before cr.set_source_rgb(0, 0, 0) cr.rectangle(0, 0, allocation.width, allocation.height) - cr.paint() + cr.fill() Gtk.ToolButton.do_draw(self, cr) From 686795fcb0883339112be756d09f88b35a074153 Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 03/10] journal: show participants heading only when buddies exist Solo entries carried an orphan Participants label over nothing. --- src/jarabe/journal/expandedentry.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/jarabe/journal/expandedentry.py b/src/jarabe/journal/expandedentry.py index a8dd21b168..71598a86ff 100644 --- a/src/jarabe/journal/expandedentry.py +++ b/src/jarabe/journal/expandedentry.py @@ -438,10 +438,17 @@ def _format_date(self): return _('No date') def _create_buddy_list(self): - + # No orphan heading: the label appears only when somebody + # actually worked on this together with the child. vbox = Gtk.VBox() vbox.props.spacing = style.DEFAULT_SPACING + buddies = [] + if self._metadata.get('buddies'): + buddies = list(json.loads(self._metadata['buddies']).values()) + if not buddies: + return vbox + text = Gtk.Label() text.set_markup('%s' % ( style.COLOR_BUTTON_GREY.get_html(), _('Participants:'))) @@ -449,10 +456,7 @@ def _create_buddy_list(self): halign.add(text) vbox.pack_start(halign, False, False, 0) - if self._metadata.get('buddies'): - buddies = list(json.loads(self._metadata['buddies']).values()) - vbox.pack_start(BuddyList(buddies), False, False, 0) - return vbox + vbox.pack_start(BuddyList(buddies), False, False, 0) return vbox def _create_scrollable(self, widget, label=None): From 533f7d78d077285a37e8333747800795170d21ba Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 04/10] journal: remove unused select column from the list model Nothing reads COLUMN_SELECT; selection state lives in _selected. --- src/jarabe/journal/listmodel.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jarabe/journal/listmodel.py b/src/jarabe/journal/listmodel.py index ae13164344..b709506be5 100644 --- a/src/jarabe/journal/listmodel.py +++ b/src/jarabe/journal/listmodel.py @@ -54,7 +54,6 @@ class ListModel(GObject.GObject, Gtk.TreeModel, Gtk.TreeDragSource): COLUMN_BUDDY_1 = 9 COLUMN_BUDDY_2 = 10 COLUMN_BUDDY_3 = 11 - COLUMN_SELECT = 12 _COLUMN_TYPES = { COLUMN_UID: str, @@ -69,7 +68,6 @@ class ListModel(GObject.GObject, Gtk.TreeModel, Gtk.TreeDragSource): COLUMN_BUDDY_1: object, COLUMN_BUDDY_3: object, COLUMN_BUDDY_2: object, - COLUMN_SELECT: bool, } _PAGE_SIZE = 10 From db2a6d05575d775bfd5bd7ce2601741814624f28 Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 05/10] journal: tolerate non-string titles in the list model GObject.markup_escape_text raises TypeError on anything that is not a string, taking the whole row render down with it. --- src/jarabe/journal/listmodel.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/jarabe/journal/listmodel.py b/src/jarabe/journal/listmodel.py index b709506be5..6a5aa3bec2 100644 --- a/src/jarabe/journal/listmodel.py +++ b/src/jarabe/journal/listmodel.py @@ -176,8 +176,14 @@ def do_get_value(self, iterator, column): xo_color = misc.get_icon_color(metadata) self._cached_row.append(xo_color) - title = GObject.markup_escape_text(metadata.get('title', - _('Untitled'))) + title_value = metadata.get('title', _('Untitled')) + if not isinstance(title_value, str): + # GObject.markup_escape_text raises TypeError on + # anything that isn't a string. + logging.warning('Content of title for %r is not a string: %r', + metadata['uid'], title_value) + title_value = _('Untitled') + title = GObject.markup_escape_text(title_value) self._cached_row.append('%s' % (title, )) try: From efb3e9d64940ecbc34c933796ec88f3ff5fbf78c Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 06/10] journal: cache a list row only once fully built The cache index was set before the row was built, so an exception mid-build left a half row served from cache on the next read. --- src/jarabe/journal/listmodel.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/jarabe/journal/listmodel.py b/src/jarabe/journal/listmodel.py index 6a5aa3bec2..9af26b5f32 100644 --- a/src/jarabe/journal/listmodel.py +++ b/src/jarabe/journal/listmodel.py @@ -163,18 +163,17 @@ def do_get_value(self, iterator, column): metadata = self._result_set.read() metadata.update(self._updated_entries.get(metadata['uid'], {})) - self._last_requested_index = index - self._cached_row = [] - self._cached_row.append(metadata['uid']) - self._cached_row.append(metadata.get('keep', '0') == '1') - self._cached_row.append(misc.get_icon_name(metadata)) + row = [] + row.append(metadata['uid']) + row.append(metadata.get('keep', '0') == '1') + row.append(misc.get_icon_name(metadata)) if misc.is_activity_bundle(metadata): xo_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(), style.COLOR_TRANSPARENT.get_svg())) else: xo_color = misc.get_icon_color(metadata) - self._cached_row.append(xo_color) + row.append(xo_color) title_value = metadata.get('title', _('Untitled')) if not isinstance(title_value, str): @@ -184,7 +183,7 @@ def do_get_value(self, iterator, column): metadata['uid'], title_value) title_value = _('Untitled') title = GObject.markup_escape_text(title_value) - self._cached_row.append('%s' % (title, )) + row.append('%s' % (title, )) try: timestamp = float(metadata.get('timestamp', 0)) @@ -192,27 +191,27 @@ def do_get_value(self, iterator, column): timestamp_content = _('Unknown') else: timestamp_content = util.timestamp_to_elapsed_string(timestamp) - self._cached_row.append(timestamp_content) + row.append(timestamp_content) try: creation_time = float(metadata.get('creation_time')) except (TypeError, ValueError): - self._cached_row.append(_('Unknown')) + row.append(_('Unknown')) else: - self._cached_row.append( + row.append( util.timestamp_to_elapsed_string(float(creation_time))) try: size = int(metadata.get('filesize')) except (TypeError, ValueError): size = None - self._cached_row.append(util.format_size(size)) + row.append(util.format_size(size)) try: progress = int(float(metadata.get('progress', 100))) except (TypeError, ValueError): progress = 100 - self._cached_row.append(progress) + row.append(progress) buddies = [] if metadata.get('buddies'): @@ -235,11 +234,13 @@ def do_get_value(self, iterator, column): logging.warning('Malformed buddies for %r: %s', metadata['uid'], exception) else: - self._cached_row.append([nick, XoColor(color)]) + row.append([nick, XoColor(color)]) continue - self._cached_row.append(None) + row.append(None) + self._cached_row = row + self._last_requested_index = index return self._cached_row[column] def do_iter_nth_child(self, parent_iter, n): From f3d63591e92eb3144c5be6c50915249407c6de27 Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 07/10] journal: drop the row cache when a row is edited A rename kept serving the pre-edit row for the same index. --- src/jarabe/journal/listmodel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jarabe/journal/listmodel.py b/src/jarabe/journal/listmodel.py index 9af26b5f32..0a9e90ffe8 100644 --- a/src/jarabe/journal/listmodel.py +++ b/src/jarabe/journal/listmodel.py @@ -139,6 +139,9 @@ def set_value(self, iterator, column, value): if column == ListModel.COLUMN_TITLE: metadata['title'] = value self._updated_entries[metadata['uid']] = metadata + # The edit must survive a re-read of this same row: the row + # cache was primed by the read that preceded this write. + self._last_requested_index = None if self._updated_callback is not None: model.updated.disconnect(self._updated_callback) model.write(metadata, update_mtime=False, From 9e6c125ad697e9769b062fd6eb6aa00cbb52f870 Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 08/10] journal: drop duplicate list model import --- src/jarabe/journal/journalactivity.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jarabe/journal/journalactivity.py b/src/jarabe/journal/journalactivity.py index 28c0863d03..8b117a2793 100644 --- a/src/jarabe/journal/journalactivity.py +++ b/src/jarabe/journal/journalactivity.py @@ -51,7 +51,6 @@ from jarabe.journal.journalwindow import JournalWindow from jarabe.journal.bundlelauncher import launch_bundle, get_bundle from jarabe.journal import journalwindow -from jarabe.journal.listmodel import ListModel from jarabe.model import session, shell From 9e7c9683496db01cd3d392127021d31990bab7af Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 09/10] journal: let entry fields keep their keys in detail view Return and the arrow keys resumed the activity or navigated away while the child was typing in a text field. --- src/jarabe/journal/journalactivity.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/jarabe/journal/journalactivity.py b/src/jarabe/journal/journalactivity.py index 8b117a2793..74c87a262e 100644 --- a/src/jarabe/journal/journalactivity.py +++ b/src/jarabe/journal/journalactivity.py @@ -409,6 +409,12 @@ def __key_press_event_cb(self, widget, event): self._main_toolbox.search_entry.grab_focus() elif self._active_view == JournalViews.DETAIL: + # Arrow keys and Return are writing when a text field has + # the keyboard; they only steer the Journal when none does. + focus = self.get_focus() + if isinstance(focus, (Gtk.Entry, Gtk.TextView)): + return False + if keyname == 'Left': path, col = self._list_view.tree_view.get_cursor() self._list_view.tree_view.grab_focus() From 0db9cd9e67969da9b1858ecc81aa2e6305381a85 Mon Sep 17 00:00:00 2001 From: Shubham Sharma Date: Mon, 17 Aug 2026 04:03:47 +0530 Subject: [PATCH 10/10] journal: address the title column by reference get_column(3) breaks the moment columns are added or reordered; the column object is already held. --- src/jarabe/journal/listview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py index 017b94867d..10f28dd8b7 100644 --- a/src/jarabe/journal/listview.py +++ b/src/jarabe/journal/listview.py @@ -773,7 +773,7 @@ def _key_press_event_cb(self, tree_view, event): if self.cell_title.props.editable: self.emit('title-edit-started') - column = self.tree_view.get_column(3) + column = self._title_column tree_view.set_cursor_on_cell(path, column, self.cell_title, start_editing=True)