GoToFlow::setNumSlides() is called each time a comic is opened. So when
e.g. three comics were opened one after another without restarting
YACReader, each of the PictureFlow::centerIndexChanged* signals was
connected to GoToFlow::preload three times, which multiplied the number
of calls to preload() accordingly.
During my testing PictureFlow::centerIndexChanged* signals were never
emitted before the first call to GoToFlow::setNumSlides(), so connecting
in GoToFlow::GoToFlow() should not cause extra calls to preload().
This data member is modified in PageLoader's own thread and accessed
without locking from an external thread in the public busy() function.
Reorder setting working and img in PageLoader::run() to avoid a data
race in PageLoader::result() called from GoToFlow::updateImageData().
Qt documentation recommends calling saveGeometry() in closeEvent().
This commit fixes the following bug on my GNU/Linux with Xfce system:
1. Move the top of the YACReader window to the top of the screen.
2. Restart YACReader (exit and run again).
2. Enter full screen mode.
4. Restart YACReader.
5. Exit full screen mode.
At this point YACReader's title bar is hidden beyond the top of the
screen, i.e. the window has moved up.
closeEvent is accepted by default, so this commit does not change the
application behavior. But Qt documentation recommends not relying on the
default value as subclasses may choose to clear it in their constructor.
Without this commit the horizontal wheel on a two-wheel mouse acts the
same as the vertical wheel in YACReader.
horizontalScroller is used analogously to verticalScroller in
Viewer::scrollTo(). So I made the horizontal wheel work analogously to
the vertical wheel except for moving to the next or previous page.
GoToFlow shared its YACReaderFlow flow object with SlideInitializer
objects it created. GoToFlow modified the flow object in the main thread
and SlideInitializer modified the flow object in its own thread without
any thread synchronization. The only reason this usually worked was the
timing: SlideInitializer finished its work before the next time GoToFlow
heavily accessed the flow object. This was a data race and thus
undefined behavior.
Additionally, this commit eliminates a memory leak:
a new SlideInitializer object was constructed each time a comic was
opened in YACReader. These objects were never destroyed.
SlideInitializer called PictureFlow::triggerRender() from its own
thread. This function restarted triggerTimer, which QTimer's API forbids
doing from another thread. This commit eliminates the following errors
from YACReader's standard output:
QObject::killTimer: Timers cannot be stopped from another thread
QObject::startTimer: Timers cannot be started from another thread
Without this fix YACReader on GNU/Linux often uses an entire CPU core
from launch till exit if hardware acceleration is disabled (#56).
The data race could alternatively be fixed by adding thread
synchronization code into most GoToFlow member functions. But the code
in SlideInitializer::run() is executed only once per opened comic; it is
not slow enough to justify creating a dedicated thread and suffer the
overhead of thread synchronization while the comic is being read.
I have tested several 550 pages long 1 GB comic books.
SlideInitializer::run() took up to 25 milliseconds in the worst case,
but usually 2-4 times less. For smaller 30-page comics it usually takes
less than a millisecond.
Even though mutexGoToFlow was locked in SlideInitializer::run(), there
is no need to lock it in the code moved to GoToFlow::setNumSlides():
this function is called in the main thread like all the other GoToFlow's
member functions that access the flow object. PageLoader does not have
access to the flow object.
* bug: 'else' without braces but several lines indented
* always set previousIndex in Render::updateBuffer()
As discussed in #41, the previous index was meant to be
updated in every case, but the faulty indentation
suggested another behavior.
signal is emitted so it is actually processed and we don't get dangling pointers.
Use modern signal slot syntax so that the compiler and source check tools can
verify we actually fixed the problem.