Rather than recreating QTimer objects on every update use a single one per context

Also change the timeout to 100ms which is the commonly accepted
threshold for human visual response. And stop the book details panel
debounce timer during shutdown.

The debounce timers in the popups are independent and use only data
local to the popup object so probably dont need to be shutdown.
This commit is contained in:
Kovid Goyal 2024-03-04 21:31:07 +05:30
parent 09cc050c0a
commit 7059a322a0
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 31 additions and 23 deletions

View File

@ -47,6 +47,7 @@ from polyglot.builtins import iteritems, string_or_bytes
del pqc, geometry_for_restore_as_dict del pqc, geometry_for_restore_as_dict
NO_URL_FORMATTING = QUrl.UrlFormattingOption.None_ NO_URL_FORMATTING = QUrl.UrlFormattingOption.None_
BOOK_DETAILS_DISPLAY_DEBOUNCE_DELAY = 100 # 100 ms is threshold for human visual response
class IconResourceManager: class IconResourceManager:

View File

@ -4,7 +4,6 @@
import textwrap import textwrap
from enum import IntEnum from enum import IntEnum
from functools import partial
from qt.core import ( from qt.core import (
QAction, QApplication, QBrush, QCheckBox, QDialog, QDialogButtonBox, QGridLayout, QAction, QApplication, QBrush, QCheckBox, QDialog, QDialogButtonBox, QGridLayout,
@ -16,6 +15,7 @@ from qt.core import (
from calibre import fit_image from calibre import fit_image
from calibre.db.constants import RESOURCE_URL_SCHEME from calibre.db.constants import RESOURCE_URL_SCHEME
from calibre.gui2 import NO_URL_FORMATTING, gprefs from calibre.gui2 import NO_URL_FORMATTING, gprefs
from calibre.gui2 import BOOK_DETAILS_DISPLAY_DEBOUNCE_DELAY
from calibre.gui2.book_details import ( from calibre.gui2.book_details import (
create_open_cover_with_menu, resolved_css, details_context_menu_event, render_html, set_html, create_open_cover_with_menu, resolved_css, details_context_menu_event, render_html, set_html,
) )
@ -24,8 +24,6 @@ from calibre.gui2.widgets import CoverView
from calibre.gui2.widgets2 import Dialog, HTMLDisplay from calibre.gui2.widgets2 import Dialog, HTMLDisplay
from calibre.startup import connect_lambda from calibre.startup import connect_lambda
BOOK_DETAILS_DISPLAY_DELAY = 250 # 250ms is arbitrary
class Cover(CoverView): class Cover(CoverView):
@ -225,7 +223,10 @@ class BookInfo(QDialog):
self.path_to_book = None self.path_to_book = None
self.current_row = None self.current_row = None
self.slave_connected = False self.slave_connected = False
self.slave_debounce_timer = QTimer() self.slave_debounce_timer = t = QTimer(self)
t.setInterval(BOOK_DETAILS_DISPLAY_DEBOUNCE_DELAY)
t.setSingleShot(True)
t.timeout.connect(self._debounce_refresh)
if library_path is not None: if library_path is not None:
self.view = None self.view = None
db = get_gui().library_broker.get_library(library_path) db = get_gui().library_broker.get_library(library_path)
@ -349,13 +350,11 @@ class BookInfo(QDialog):
QTimer.singleShot(1, self.resize_cover) QTimer.singleShot(1, self.resize_cover)
def slave(self, mi): def slave(self, mi):
self.slave_debounce_timer.stop() self._mi_for_debounce = mi
t = self.book_display_info_timer = QTimer() self.slave_debounce_timer.start() # start() will automatically reset the timer if it was already running
t.setSingleShot(True)
t.timeout.connect(partial(self._timed_slave, mi))
t.start(BOOK_DETAILS_DISPLAY_DELAY)
def _timed_slave(self, mi): def _debounce_refresh(self):
mi, self._mi_for_debounce = self._mi_for_debounce, None
self.refresh(mi.row_number, mi) self.refresh(mi.row_number, mi)
def move(self, delta=1): def move(self, delta=1):

View File

@ -18,7 +18,9 @@ from qt.core import (
from calibre import force_unicode from calibre import force_unicode
from calibre.constants import filesystem_encoding, islinux from calibre.constants import filesystem_encoding, islinux
from calibre.gui2 import FunctionDispatcher, error_dialog, gprefs from calibre.gui2 import (
BOOK_DETAILS_DISPLAY_DEBOUNCE_DELAY, FunctionDispatcher, error_dialog, gprefs,
)
from calibre.gui2.dialogs.enum_values_edit import EnumValuesEdit from calibre.gui2.dialogs.enum_values_edit import EnumValuesEdit
from calibre.gui2.gestures import GestureManager from calibre.gui2.gestures import GestureManager
from calibre.gui2.library import DEFAULT_SORT from calibre.gui2.library import DEFAULT_SORT
@ -27,9 +29,9 @@ from calibre.gui2.library.alternate_views import (
) )
from calibre.gui2.library.delegates import ( from calibre.gui2.library.delegates import (
CcBoolDelegate, CcCommentsDelegate, CcDateDelegate, CcEnumDelegate, CcBoolDelegate, CcCommentsDelegate, CcDateDelegate, CcEnumDelegate,
CcLongTextDelegate, CcMarkdownDelegate, CcNumberDelegate, CcSeriesDelegate, CcTemplateDelegate, CcLongTextDelegate, CcMarkdownDelegate, CcNumberDelegate, CcSeriesDelegate,
CcTextDelegate, CompleteDelegate, DateDelegate, LanguagesDelegate, PubDateDelegate, CcTemplateDelegate, CcTextDelegate, CompleteDelegate, DateDelegate,
RatingDelegate, SeriesDelegate, TextDelegate, LanguagesDelegate, PubDateDelegate, RatingDelegate, SeriesDelegate, TextDelegate,
) )
from calibre.gui2.library.models import BooksModel, DeviceBooksModel from calibre.gui2.library.models import BooksModel, DeviceBooksModel
from calibre.gui2.pin_columns import PinTableView from calibre.gui2.pin_columns import PinTableView
@ -1615,16 +1617,20 @@ class BooksView(QTableView): # {{{
self._model.search_done.connect(self.alternate_views.restore_current_book_state) self._model.search_done.connect(self.alternate_views.restore_current_book_state)
def connect_to_book_display(self, bd): def connect_to_book_display(self, bd):
self.connect_to_book_display_timer = QTimer() self.book_display_callback = bd
self._model.new_bookdisplay_data.connect(partial(self._timed_connect_to_book_display, bd)) self.connect_to_book_display_timer = t = QTimer(self)
def _timed_connect_to_book_display(self, bd, data):
self.connect_to_book_display_timer.stop()
t = self.connect_to_book_display_timer = QTimer()
t.setSingleShot(True) t.setSingleShot(True)
t.timeout.connect(partial(bd, data)) t.timeout.connect(self._debounce_book_display)
from calibre.gui2.dialogs.book_info import BOOK_DETAILS_DISPLAY_DELAY t.setInterval(BOOK_DETAILS_DISPLAY_DEBOUNCE_DELAY)
t.start(BOOK_DETAILS_DISPLAY_DELAY) self._model.new_bookdisplay_data.connect(self._timed_connect_to_book_display)
def _timed_connect_to_book_display(self, data):
self._book_display_data = data
self.connect_to_book_display_timer.start()
def _debounce_book_display(self):
data, self._book_display_data = self._book_display_data, None
self.book_display_callback(data)
def search_done(self, ok): def search_done(self, ok):
self._search_done(self, ok) self._search_done(self, ok)

View File

@ -1191,6 +1191,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
def shutdown(self, write_settings=True): def shutdown(self, write_settings=True):
self.shutting_down = True self.shutting_down = True
if hasattr(self.library_view, 'connect_to_book_display_timer'):
self.library_view.connect_to_book_display_timer.stop()
self.shutdown_started.emit() self.shutdown_started.emit()
self.show_shutdown_message() self.show_shutdown_message()
self.server_change_notification_timer.stop() self.server_change_notification_timer.stop()