Make jumping to a cfi pseudo synchronous by spinning the event loop while waiting for the scroll to finish

This commit is contained in:
Kovid Goyal 2015-02-01 10:22:17 +05:30
parent c9a0f23173
commit bdf4e01d7a
5 changed files with 38 additions and 16 deletions

Binary file not shown.

View File

@ -530,7 +530,7 @@ class PagedDisplay
# selection # selection
this.scroll_to_xpos(left+5) this.scroll_to_xpos(left+5)
jump_to_cfi: (cfi) -> jump_to_cfi: (cfi, job_id=-1) ->
# Jump to the position indicated by the specified conformal fragment # Jump to the position indicated by the specified conformal fragment
# indicator (requires the cfi.coffee library). When in paged mode, the # indicator (requires the cfi.coffee library). When in paged mode, the
# scroll is performed so that the column containing the position # scroll is performed so that the column containing the position
@ -540,6 +540,8 @@ class PagedDisplay
this.scroll_to_xpos(x) this.scroll_to_xpos(x)
else else
window.scrollTo(0, y) window.scrollTo(0, y)
if window.py_bridge
window.py_bridge.jump_to_cfi_finished(job_id)
) )
current_cfi: () -> current_cfi: () ->

View File

@ -93,6 +93,7 @@ class Document(QWebPage): # {{{
# javascript, get/set the value as: py_bridge.value # javascript, get/set the value as: py_bridge.value
self.bridge_value = None self.bridge_value = None
self.first_load = True self.first_load = True
self.jump_to_cfi_listeners = set()
self.debug_javascript = debug_javascript self.debug_javascript = debug_javascript
self.anchor_positions = {} self.anchor_positions = {}
@ -336,6 +337,11 @@ class Document(QWebPage): # {{{
def debug(self, msg): def debug(self, msg):
prints(unicode(msg)) prints(unicode(msg))
@pyqtSlot(int)
def jump_to_cfi_finished(self, job_id):
for l in self.jump_to_cfi_listeners:
l(job_id)
def reference_mode(self, enable): def reference_mode(self, enable):
self.javascript(('enter' if enable else 'leave')+'_reference_mode()') self.javascript(('enter' if enable else 'leave')+'_reference_mode()')

View File

@ -722,19 +722,12 @@ class EbookViewer(MainWindow):
if self.isFullScreen(): if self.isFullScreen():
self.relayout_fullscreen_labels() self.relayout_fullscreen_labels()
self.view.document.after_resize() self.view.document.after_resize()
# For some reason scroll_fraction returns incorrect results in paged
# mode for some time after a resize is finished. No way of knowing
# exactly how long, so we update it in a second, in the hopes that it
# will be enough *most* of the time.
QTimer.singleShot(1000, self.scroll_after_resize_done)
if not wmc: if not wmc:
pre_footnote_pos = self.pre_footnote_toggle_position() pre_footnote_pos = self.pre_footnote_toggle_position()
if pre_footnote_pos is not None: if pre_footnote_pos is not None:
self.view.document.page_number = pre_footnote_pos self.view.document.page_number = pre_footnote_pos
else: else:
self.view.document.page_position.restore() self.view.document.page_position.restore()
def scroll_after_resize_done(self):
self.update_page_number() self.update_page_number()
if len(self.page_position_on_footnote_toggle) % 2 == 1: if len(self.page_position_on_footnote_toggle) % 2 == 1:
self.page_position_on_footnote_toggle[-1] = self.page_position_on_footnote_toggle[-1]._replace( self.page_position_on_footnote_toggle[-1] = self.page_position_on_footnote_toggle[-1]._replace(

View File

@ -7,12 +7,19 @@ __license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import json import json, time
from PyQt5.Qt import QApplication, QEventLoop
from calibre.constants import DEBUG
class PagePosition(object): class PagePosition(object):
def __init__(self, document): def __init__(self, document):
self.document = document self.document = document
document.jump_to_cfi_listeners.add(self)
self.cfi_job_id = 0
self.pending_scrolls = set()
@property @property
def viewport_cfi(self): def viewport_cfi(self):
@ -30,9 +37,22 @@ class PagePosition(object):
def scroll_to_cfi(self, cfi): def scroll_to_cfi(self, cfi):
if cfi: if cfi:
jid = self.cfi_job_id
self.cfi_job_id += 1
cfi = json.dumps(cfi) cfi = json.dumps(cfi)
self.pending_scrolls.add(jid)
self.document.mainFrame().evaluateJavaScript( self.document.mainFrame().evaluateJavaScript(
'paged_display.jump_to_cfi(%s)'%cfi) 'paged_display.jump_to_cfi(%s, %d)' % (cfi, jid))
# jump_to_cfi is async, so we wait for it to complete
st = time.time()
WAIT = 1 # seconds
while jid in self.pending_scrolls and time.time() - st < WAIT:
QApplication.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers)
time.sleep(0.01)
if jid in self.pending_scrolls:
self.pending_scrolls.discard(jid)
if DEBUG:
print ('jump_to_cfi() failed to complete after %s seconds' % WAIT)
@property @property
def current_pos(self): def current_pos(self):
@ -47,6 +67,9 @@ class PagePosition(object):
def __exit__(self, *args): def __exit__(self, *args):
self.restore() self.restore()
def __call__(self, cfi_job_id):
self.pending_scrolls.discard(cfi_job_id)
def save(self, overwrite=True): def save(self, overwrite=True):
if not overwrite and self._cpos is not None: if not overwrite and self._cpos is not None:
return return
@ -66,5 +89,3 @@ class PagePosition(object):
def set_pos(self, pos): def set_pos(self, pos):
self._cpos = pos self._cpos = pos