--[[--
This module manages widgets .
] ]
local Device = require ( " device " )
local Event = require ( " ui/event " )
local Geom = require ( " ui/geometry " )
local dbg = require ( " dbg " )
local logger = require ( " logger " )
local util = require ( " ffi/util " )
local _ = require ( " gettext " )
local Input = Device.input
local Screen = Device.screen
local MILLION = 1000000
-- there is only one instance of this
local UIManager = {
-- trigger a full refresh when counter reaches FULL_REFRESH_COUNT
FULL_REFRESH_COUNT =
G_reader_settings : readSetting ( " full_refresh_count " ) or DRCOUNTMAX ,
refresh_count = 0 ,
-- How long to wait between ZMQ wakeups: 50ms.
ZMQ_TIMEOUT = 50 * 1000 ,
event_handlers = nil ,
_running = true ,
_window_stack = { } ,
_task_queue = { } ,
_task_queue_dirty = false ,
_dirty = { } ,
_zeromqs = { } ,
_refresh_stack = { } ,
_refresh_func_stack = { } ,
_entered_poweroff_stage = false ,
_exit_code = nil ,
event_hook = require ( " ui/hook_container " ) : new ( )
}
function UIManager : init ( )
self.event_handlers = {
__default__ = function ( input_event )
self : sendEvent ( input_event )
end ,
SaveState = function ( )
self : flushSettings ( )
end ,
Power = function ( input_event )
Device : onPowerEvent ( input_event )
end ,
}
self.poweroff_action = function ( )
self._entered_poweroff_stage = true ;
Screen : setRotationMode ( 0 )
require ( " ui/screensaver " ) : show ( " poweroff " , _ ( " Powered off " ) )
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
if Device : needsScreenRefreshAfterResume ( ) then
Screen : refreshFull ( )
end
UIManager : nextTick ( function ( )
Device : saveSettings ( )
self : broadcastEvent ( Event : new ( " Close " ) )
Device : powerOff ( )
end )
end
self.reboot_action = function ( )
self._entered_poweroff_stage = true ;
Screen : setRotationMode ( 0 )
require ( " ui/screensaver " ) : show ( " reboot " , _ ( " Rebooting... " ) )
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
if Device : needsScreenRefreshAfterResume ( ) then
Screen : refreshFull ( )
end
UIManager : nextTick ( function ( )
Device : saveSettings ( )
self : broadcastEvent ( Event : new ( " Close " ) )
Device : reboot ( )
end )
end
if Device : isPocketBook ( ) then
self.event_handlers [ " Suspend " ] = function ( )
self : _beforeSuspend ( )
Device : onPowerEvent ( " Power " )
end
self.event_handlers [ " Resume " ] = function ( )
Device : onPowerEvent ( " Power " )
self : _afterResume ( )
end
end
if Device : isKobo ( ) then
-- We do not want auto suspend procedure to waste battery during
-- suspend. So let's unschedule it when suspending, and restart it after
-- resume. Done via the plugin's onSuspend/onResume handlers.
self.event_handlers [ " Suspend " ] = function ( )
-- Ignore the accelerometer (if that's not already the case) while we're alseep
if G_reader_settings : nilOrFalse ( " input_ignore_gsensor " ) then
Device : toggleGSensor ( )
end
self : _beforeSuspend ( )
Device : onPowerEvent ( " Suspend " )
end
self.event_handlers [ " Resume " ] = function ( )
Device : onPowerEvent ( " Resume " )
self : _afterResume ( )
-- Stop ignoring the accelerometer (unless requested) when we wakeup
if G_reader_settings : nilOrFalse ( " input_ignore_gsensor " ) then
Device : toggleGSensor ( )
end
end
self.event_handlers [ " PowerPress " ] = function ( )
UIManager : scheduleIn ( 2 , self.poweroff_action )
end
self.event_handlers [ " PowerRelease " ] = function ( )
if not self._entered_poweroff_stage then
UIManager : unschedule ( self.poweroff_action )
self : suspend ( )
end
end
if not G_reader_settings : readSetting ( " ignore_power_sleepcover " ) then
self.event_handlers [ " SleepCoverClosed " ] = function ( )
Device.is_cover_closed = true
self : suspend ( )
end
self.event_handlers [ " SleepCoverOpened " ] = function ( )
Device.is_cover_closed = false
self : resume ( )
end
else
-- Closing/opening the cover will still wake up the device, so we
-- need to put it back to sleep if we are in screen saver mode
self.event_handlers [ " SleepCoverClosed " ] = function ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " SleepCoverOpened " ] = self.event_handlers [ " SleepCoverClosed " ]
end
self.event_handlers [ " Light " ] = function ( )
Device : getPowerDevice ( ) : toggleFrontlight ( )
end
self.event_handlers [ " Charging " ] = function ( )
self : _beforeCharging ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " NotCharging " ] = function ( )
-- We need to put the device into suspension, other things need to be done before it.
self : _afterNotCharging ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " __default__ " ] = function ( input_event )
-- Suspension in Kobo can be interrupted by screen updates. We ignore user touch input
-- in screen_saver_mode so screen updates won't be triggered in suspend mode.
-- We should not call self:suspend() in screen_saver_mode lest we stay on forever
-- trying to reschedule suspend. Other systems take care of unintended wake-up.
if not Device.screen_saver_mode then
self : sendEvent ( input_event )
end
end
elseif Device : isKindle ( ) then
self.event_handlers [ " IntoSS " ] = function ( )
self : _beforeSuspend ( )
Device : intoScreenSaver ( )
end
self.event_handlers [ " OutOfSS " ] = function ( )
Device : outofScreenSaver ( )
self : _afterResume ( ) ;
end
self.event_handlers [ " Charging " ] = function ( )
self : _beforeCharging ( )
Device : usbPlugIn ( )
end
self.event_handlers [ " NotCharging " ] = function ( )
Device : usbPlugOut ( )
self : _afterNotCharging ( )
end
elseif Device : isSonyPRSTUX ( ) then
self.event_handlers [ " PowerPress " ] = function ( )
UIManager : scheduleIn ( 2 , self.poweroff_action )
end
self.event_handlers [ " PowerRelease " ] = function ( )
if not self._entered_poweroff_stage then
UIManager : unschedule ( self.poweroff_action )
self : _beforeSuspend ( )
Device : intoScreenSaver ( )
Device : suspend ( )
end
end
self.event_handlers [ " Suspend " ] = self.event_handlers [ " PowerRelease " ]
self.event_handlers [ " Resume " ] = function ( )
Device : resume ( )
Device : outofScreenSaver ( )
self : _afterResume ( )
end
self.event_handlers [ " __default__ " ] = function ( input_event )
-- Same as in Kobo: we want to ignore keys during suspension
if not Device.screen_saver_mode then
self : sendEvent ( input_event )
end
end
elseif Device : isCervantes ( ) then
self.event_handlers [ " Suspend " ] = function ( )
self : _beforeSuspend ( )
Device : onPowerEvent ( " Suspend " )
end
self.event_handlers [ " Resume " ] = function ( )
Device : onPowerEvent ( " Resume " )
self : _afterResume ( )
end
self.event_handlers [ " PowerPress " ] = function ( )
UIManager : scheduleIn ( 2 , self.poweroff_action )
end
self.event_handlers [ " PowerRelease " ] = function ( )
if not self._entered_poweroff_stage then
UIManager : unschedule ( self.poweroff_action )
self : suspend ( )
end
end
self.event_handlers [ " Charging " ] = function ( )
self : _beforeCharging ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " NotCharging " ] = function ( )
self : _afterNotCharging ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " UsbPlugIn " ] = function ( )
self : _beforeCharging ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " USbPlugOut " ] = function ( )
self : _afterNotCharging ( )
if Device.screen_saver_mode then
self : suspend ( )
end
end
self.event_handlers [ " __default__ " ] = function ( input_event )
-- Same as in Kobo: we want to ignore keys during suspension
if not Device.screen_saver_mode then
self : sendEvent ( input_event )
end
end
elseif Device : isSDL ( ) then
self.event_handlers [ " Suspend " ] = function ( )
self : _beforeSuspend ( )
Device : simulateSuspend ( )
end
self.event_handlers [ " Resume " ] = function ( )
Device : simulateResume ( )
self : _afterResume ( )
end
end
end
--[[--
Registers and shows a widget .
Modal widget should be always on top .
For refreshtype & refreshregion see description of setDirty ( ) .
] ]
---- @param widget a widget object
---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast"
---- @param refreshregion a Geom object
---- @int x
---- @int y
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
---- @param refreshdither an optional bool
---- @see setDirty
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
function UIManager : show ( widget , refreshtype , refreshregion , x , y , refreshdither )
if not widget then
logger.dbg ( " widget not exist to be shown " )
return
end
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
logger.dbg ( " show widget: " , widget.id or widget.name or tostring ( widget ) )
self._running = true
local window = { x = x or 0 , y = y or 0 , widget = widget }
-- put this window on top of the toppest non-modal window
for i = # self._window_stack , 0 , - 1 do
local top_window = self._window_stack [ i ]
-- skip modal window
if widget.modal or not top_window or not top_window.widget . modal then
table.insert ( self._window_stack , i + 1 , window )
break
end
end
-- and schedule it to be painted
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
self : setDirty ( widget , refreshtype , refreshregion , refreshdither )
-- tell the widget that it is shown now
widget : handleEvent ( Event : new ( " Show " ) )
-- check if this widget disables double tap gesture
if widget.disable_double_tap == false then
Input.disable_double_tap = false
else
Input.disable_double_tap = true
end
end
--[[--
Unregisters a widget .
For refreshtype & refreshregion see description of setDirty ( ) .
] ]
---- @param widget a widget object
---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast"
---- @param refreshregion a Geom object
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
---- @param refreshdither an optional bool
---- @see setDirty
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
function UIManager : close ( widget , refreshtype , refreshregion , refreshdither )
if not widget then
logger.dbg ( " widget to be closed does not exist " )
return
end
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
logger.dbg ( " close widget: " , widget.name or widget.id or tostring ( widget ) )
local dirty = false
-- Ensure all the widgets can get onFlushSettings event.
widget : handleEvent ( Event : new ( " FlushSettings " ) )
-- first send close event to widget
widget : handleEvent ( Event : new ( " CloseWidget " ) )
-- make it disabled by default and check if any widget wants it disabled or enabled
Input.disable_double_tap = true
local requested_disable_double_tap = nil
-- then remove all references to that widget on stack and refresh
for i = # self._window_stack , 1 , - 1 do
if self._window_stack [ i ] . widget == widget then
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
self._dirty [ self._window_stack [ i ] . widget ] = nil
table.remove ( self._window_stack , i )
dirty = true
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
else
-- If anything else on the stack was dithered, honor the hint
if self._window_stack [ i ] . widget.dithered then
refreshdither = true
logger.dbg ( " Lower widget " , self._window_stack [ i ] . widget.name or self._window_stack [ i ] . widget.id or tostring ( self._window_stack [ i ] . widget ) , " was dithered, honoring the dithering hint " )
end
-- Set double tap to how the topmost specifying widget wants it
if requested_disable_double_tap == nil and self._window_stack [ i ] . widget.disable_double_tap ~= nil then
requested_disable_double_tap = self._window_stack [ i ] . widget.disable_double_tap
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
end
end
end
if requested_disable_double_tap ~= nil then
Input.disable_double_tap = requested_disable_double_tap
end
if dirty and not widget.invisible then
-- schedule remaining widgets to be painted
for i = 1 , # self._window_stack do
self : setDirty ( self._window_stack [ i ] . widget )
end
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
self : _refresh ( refreshtype , refreshregion , refreshdither )
end
end
-- schedule an execution task, task queue is in ascendant order
function UIManager : schedule ( time , action )
local p , s , e = 1 , 1 , # self._task_queue
if e ~= 0 then
local us = time [ 1 ] * MILLION + time [ 2 ]
-- do a binary insert
repeat
p = math.floor ( s + ( e - s ) / 2 )
local ptime = self._task_queue [ p ] . time
local ptus = ptime [ 1 ] * MILLION + ptime [ 2 ]
if us > ptus then
if s == e then
p = e + 1
break
elseif s + 1 == e then
s = e
else
s = p
end
elseif us < ptus then
e = p
if s == e then
break
end
else
-- for fairness, it's better to make p+1 is strictly less than
-- p might want to revisit here in the future
break
end
until e < s
end
table.insert ( self._task_queue , p , { time = time , action = action } )
self._task_queue_dirty = true
end
dbg : guard ( UIManager , ' schedule ' ,
function ( self , time , action )
assert ( time [ 1 ] >= 0 and time [ 2 ] >= 0 , " Only positive time allowed " )
assert ( action ~= nil )
end )
--- Schedules task in a certain amount of seconds (fractions allowed) from now.
function UIManager : scheduleIn ( seconds , action )
local when = { util.gettime ( ) }
local s = math.floor ( seconds )
local usecs = ( seconds - s ) * MILLION
when [ 1 ] = when [ 1 ] + s
when [ 2 ] = when [ 2 ] + usecs
if when [ 2 ] >= MILLION then
when [ 1 ] = when [ 1 ] + 1
when [ 2 ] = when [ 2 ] - MILLION
end
self : schedule ( when , action )
end
dbg : guard ( UIManager , ' scheduleIn ' ,
function ( self , seconds , action )
assert ( seconds >= 0 , " Only positive seconds allowed " )
end )
function UIManager : nextTick ( action )
return self : scheduleIn ( 0 , action )
end
-- Useful to run UI callbacks ASAP without skipping repaints
function UIManager : tickAfterNext ( action )
return self : nextTick ( function ( ) self : nextTick ( action ) end )
end
--[[
-- NOTE: This appears to work *nearly* just as well, but does sometimes go too fast (might depend on kernel HZ & NO_HZ settings?)
function UIManager : tickAfterNext ( action )
return self : scheduleIn ( 0.001 , action )
end
--]]
--[[-- Unschedules an execution task.
In order to unschedule anonymous functions , store a reference .
@ usage
self.anonymousFunction = function ( ) self : regularFunction ( ) end
UIManager : scheduleIn ( 10 , self.anonymousFunction )
UIManager : unschedule ( self.anonymousFunction )
] ]
function UIManager : unschedule ( action )
for i = # self._task_queue , 1 , - 1 do
if self._task_queue [ i ] . action == action then
table.remove ( self._task_queue , i )
end
end
end
dbg : guard ( UIManager , ' unschedule ' ,
function ( self , action ) assert ( action ~= nil ) end )
--[[--
Registers a widget to be repainted and enqueues a refresh .
the second parameter ( refreshtype ) can either specify a refreshtype
( optionally in combination with a refreshregion - which is suggested )
or a function that returns refreshtype AND refreshregion and is called
after painting the widget .
Here ' s a quick rundown of what each refreshtype should be used for:
full : high - fidelity flashing refresh ( f.g . , large images ) .
Highest quality , but highest latency .
Don ' t abuse if you only want a flash (in this case, prefer flashpartial or flashui).
partial : medium fidelity refresh ( f.g . , text on a white background ) .
Can be promoted to flashing after FULL_REFRESH_COUNT refreshes .
Don ' t abuse to avoid spurious flashes.
ui : medium fidelity refresh ( f.g . , mixed content ) .
Should apply to most UI elements .
fast : low fidelity refresh ( f.g . , monochrome content ) .
Should apply to most highlighting effects achieved through inversion .
Note that if your highlighted element contains text ,
you might want to keep the unhighlight refresh as " ui " instead , for crisper text .
( Or optimize that refresh away entirely , if you can get away with it ) .
flashui : like ui , but flashing .
Can be used when showing a UI element for the first time , to avoid ghosting .
flashpartial : like partial , but flashing ( and not counting towards flashing promotions ) .
Can be used when closing an UI element , to avoid ghosting .
You can even drop the region in these cases , to ensure a fullscreen flash .
NOTE : On REAGL devices , " flashpartial " will NOT actually flash ( by design ) .
As such , even onClose , you might prefer " flashui " in some rare instances .
NOTE : You ' ll notice a trend on UI elements that are usually shown *over* some kind of text
of using " ui " onShow & onUpdate , but " partial " onClose .
This is by design : " partial " is what the reader uses , as it ' s tailor-made for pure text
over a white background , so this ensures we resume the usual flow of the reader .
The same dynamic is true for their flashing counterparts , in the rare instances we enforce flashes .
Any kind of " partial " refresh * will * count towards a flashing promotion after FULL_REFRESH_COUNT refreshes ,
so making sure your stuff only applies to the proper region is key to avoiding spurious large black flashes .
That said , depending on your use case , using " ui " onClose can be a perfectly valid decision , and will ensure
never seeing a flash because of that widget .
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
The final parameter ( refreshdither ) is an optional hint for devices with hardware dithering support that this repaint
could benefit from dithering ( i.e . , it contains an image ) .
@ usage
UIManager : setDirty ( self.widget , " partial " )
UIManager : setDirty ( self.widget , " partial " , Geom : new { x = 10 , y = 10 , w = 100 , h = 50 } )
UIManager : setDirty ( self.widget , function ( ) return " ui " , self.someelement . dimen end )
--]]
---- @param widget a widget object
---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast"
---- @param refreshregion a Geom object
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
---- @param refreshdither an optional bool
function UIManager : setDirty ( widget , refreshtype , refreshregion , refreshdither )
if widget then
if widget == " all " then
-- special case: set all top-level widgets as being "dirty".
for i = 1 , # self._window_stack do
self._dirty [ self._window_stack [ i ] . widget ] = true
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- If any of 'em were dithered, honor their dithering hint
if self._window_stack [ i ] . widget.dithered then
-- NOTE: That works when refreshtype is NOT a function,
-- which is why _repaint does another pass of this check ;).
refreshdither = true
end
end
elseif not widget.invisible then
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- We only ever check the dirty flag on top-level widgets, so only set it there!
-- NOTE: Enable verbose debug to catch misbehaving widgets via our post-guard.
for i = 1 , # self._window_stack do
if self._window_stack [ i ] . widget == widget then
self._dirty [ widget ] = true
end
end
-- Again, if it's flagged as dithered, honor that
if widget.dithered then
refreshdither = true
end
end
end
-- handle refresh information
if type ( refreshtype ) == " function " then
-- callback, will be issued after painting
table.insert ( self._refresh_func_stack , refreshtype )
if dbg.is_on then
-- FIXME: We can't consume the return values of refreshtype by running it, because for a reason that is beyond me (scoping? gc?), that renders it useless later, meaning we then enqueue refreshes with bogus arguments...
-- Thankfully, we can track them in _refresh()'s logging very soon after that...
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
logger.dbg ( " setDirty via a func from widget " , widget and ( widget.name or widget.id or tostring ( widget ) ) or " nil " )
end
else
-- otherwise, enqueue refresh
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
self : _refresh ( refreshtype , refreshregion , refreshdither )
if dbg.is_on then
if refreshregion then
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
logger.dbg ( " setDirty " , refreshtype and refreshtype or " nil " , " from widget " , widget and ( widget.name or widget.id or tostring ( widget ) ) or " nil " , " w/ region " , refreshregion.x , refreshregion.y , refreshregion.w , refreshregion.h , refreshdither and " AND w/ HW dithering " or " " )
else
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
logger.dbg ( " setDirty " , refreshtype and refreshtype or " nil " , " from widget " , widget and ( widget.name or widget.id or tostring ( widget ) ) or " nil " , " w/ NO region " , refreshdither and " AND w/ HW dithering " or " " )
end
end
end
end
dbg : guard ( UIManager , ' setDirty ' ,
nil ,
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
function ( self , widget , refreshtype , refreshregion , refreshdither )
if not widget or widget == " all " then return end
-- when debugging, we check if we get handed a valid widget,
-- which would be a dialog that was previously passed via show()
local found = false
for i = 1 , # self._window_stack do
if self._window_stack [ i ] . widget == widget then found = true end
end
if not found then
dbg : v ( " INFO: invalid widget for setDirty() " , debug.traceback ( ) )
end
end )
-- Clear the full repaint & refreshes queues.
-- NOTE: Beware! This doesn't take any prisonners!
-- You shouldn't have to resort to this unless in very specific circumstances!
-- plugins/coverbrowser.koplugin/covermenu.lua building a franken-menu out of buttondialogtitle & buttondialog
-- and wanting to avoid inheriting their original paint/refresh cycle being a prime example.
function UIManager : clearRenderStack ( )
logger.dbg ( " clearRenderStack: Clearing the full render stack! " )
self._dirty = { }
self._refresh_func_stack = { }
self._refresh_stack = { }
end
function UIManager : insertZMQ ( zeromq )
table.insert ( self._zeromqs , zeromq )
return zeromq
end
function UIManager : removeZMQ ( zeromq )
for i = # self._zeromqs , 1 , - 1 do
if self._zeromqs [ i ] == zeromq then
table.remove ( self._zeromqs , i )
end
end
end
--- Sets full refresh rate for e-ink screen.
--
-- Also makes the refresh rate persistent in global reader settings.
function UIManager : setRefreshRate ( rate )
logger.dbg ( " set screen full refresh rate " , rate )
self.FULL_REFRESH_COUNT = rate
G_reader_settings : saveSetting ( " full_refresh_count " , rate )
end
--- Gets full refresh rate for e-ink screen.
function UIManager : getRefreshRate ( rate )
return self.FULL_REFRESH_COUNT
end
--- Signals to quit.
function UIManager : quit ( )
if not self._running then return end
logger.info ( " quitting uimanager " )
self._task_queue_dirty = false
self._running = false
self._run_forever = nil
for i = # self._window_stack , 1 , - 1 do
table.remove ( self._window_stack , i )
end
for i = # self._task_queue , 1 , - 1 do
table.remove ( self._task_queue , i )
end
for i = # self._zeromqs , 1 , - 1 do
self._zeromqs [ i ] : stop ( )
table.remove ( self._zeromqs , i )
end
if self.looper then
self.looper : close ( )
self.looper = nil
end
end
--- Transmits an event to an active widget.
function UIManager : sendEvent ( event )
if # self._window_stack == 0 then return end
local top_widget = self._window_stack [ # self._window_stack ]
-- top level widget has first access to the event
if top_widget.widget : handleEvent ( event ) then
return
end
if top_widget.widget . active_widgets then
for _ , active_widget in ipairs ( top_widget.widget . active_widgets ) do
if active_widget : handleEvent ( event ) then return end
end
end
-- if the event is not consumed, active widgets (from top to bottom) can
-- access it. NOTE: _window_stack can shrink on close event
local checked_widgets = { top_widget }
for i = # self._window_stack , 1 , - 1 do
local widget = self._window_stack [ i ]
if checked_widgets [ widget ] == nil then
-- active widgets has precedence to handle this event
-- Note: ReaderUI currently only has one active_widget: readerscreenshot
if widget.widget . active_widgets then
checked_widgets [ widget ] = true
for _ , active_widget in ipairs ( widget.widget . active_widgets ) do
if active_widget : handleEvent ( event ) then return end
end
end
if widget.widget . is_always_active then
-- active widgets will handle this event
-- Note: is_always_active widgets currently are widgets that want to show a keyboard
-- and readerconfig
checked_widgets [ widget ] = true
if widget.widget : handleEvent ( event ) then return end
end
end
end
end
--- Transmits an event to all registered widgets.
function UIManager : broadcastEvent ( event )
-- the widget's event handler might close widgets in which case
-- a simple iterator like ipairs would skip over some entries
local i = 1
while i <= # self._window_stack do
local prev_widget = self._window_stack [ i ] . widget
self._window_stack [ i ] . widget : handleEvent ( event )
local top_widget = self._window_stack [ i ]
if top_widget == nil then
-- top widget closed itself
break
elseif top_widget.widget == prev_widget then
i = i + 1
end
end
end
function UIManager : _checkTasks ( )
local now = { util.gettime ( ) }
local now_us = now [ 1 ] * MILLION + now [ 2 ]
local wait_until = nil
-- task.action may schedule other events
self._task_queue_dirty = false
while true do
local nu_task = # self._task_queue
if nu_task == 0 then
-- all tasks checked
break
end
local task = self._task_queue [ 1 ]
local task_us = 0
if task.time ~= nil then
task_us = task.time [ 1 ] * MILLION + task.time [ 2 ]
end
if task_us <= now_us then
-- remove from table
table.remove ( self._task_queue , 1 )
-- task is pending to be executed right now. do it.
-- NOTE: be careful that task.action() might modify
-- _task_queue here. So need to avoid race condition
task.action ( )
else
-- queue is sorted in ascendant order, safe to assume all items
-- are future tasks for now
wait_until = task.time
break
end
end
return wait_until , now
end
-- precedence of refresh modes:
local refresh_modes = { fast = 1 , ui = 2 , partial = 3 , flashui = 4 , flashpartial = 5 , full = 6 }
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- NOTE: We might want to introduce a "force_fast" that points to fast, but has the highest priority,
-- for the few cases where we might *really* want to enforce fast (for stuff like panning or skimming?).
-- refresh methods in framebuffer implementation
local refresh_methods = {
fast = " refreshFast " ,
ui = " refreshUI " ,
partial = " refreshPartial " ,
flashui = " refreshFlashUI " ,
flashpartial = " refreshFlashPartial " ,
full = " refreshFull " ,
}
--[[
Compares refresh mode .
Will return the mode that takes precedence .
--]]
local function update_mode ( mode1 , mode2 )
if refresh_modes [ mode1 ] > refresh_modes [ mode2 ] then
logger.dbg ( " update_mode: Update refresh mode " , mode2 , " to " , mode1 )
return mode1
else
return mode2
end
end
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
--[[
Compares dither hints .
Dither always wins .
--]]
local function update_dither ( dither1 , dither2 )
if dither1 and not dither2 then
logger.dbg ( " update_dither: Update dither hint " , dither2 , " to " , dither1 )
return dither1
else
return dither2
end
end
--[[--
Enqueues a refresh .
Widgets call this in their paintTo ( ) method in order to notify
UIManager that a certain part of the screen is to be refreshed .
@ param mode
refresh mode ( " full " , " flashpartial " , " flashui " , " partial " , " ui " , " fast " )
@ param region
Rect ( ) that specifies the region to be updated
optional , update will affect whole screen if not specified .
Note that this should be the exception .
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
@ param dither
Bool , a hint to request hardware dithering ( if supported )
optional , no dithering requested if not specified or not supported .
--]]
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
function UIManager : _refresh ( mode , region , dither )
if not mode then
-- If we're trying to float a dither hint up from a lower widget after a close, mode might be nil...
-- So use the lowest priority refresh mode (short of fast, because that'd do half-toning).
if dither then
mode = " ui "
else
return
end
end
if not region and mode == " full " then
self.refresh_count = 0 -- reset counter on explicit full refresh
end
-- Handle downgrading flashing modes to non-flashing modes, according to user settings.
-- NOTE: Do it before "full" promotion and collision checks/update_mode.
if G_reader_settings : isTrue ( " avoid_flashing_ui " ) then
if mode == " flashui " then
mode = " ui "
logger.dbg ( " _refresh: downgraded flashui refresh to " , mode )
elseif mode == " flashpartial " then
mode = " partial "
logger.dbg ( " _refresh: downgraded flashpartial refresh to " , mode )
elseif mode == " partial " and region then
mode = " ui "
logger.dbg ( " _refresh: downgraded regional partial refresh to " , mode )
end
end
-- special case: "partial" refreshes
-- will get promoted every self.FULL_REFRESH_COUNT refreshes
-- since _refresh can be called mutiple times via setDirty called in
-- different widgets before a real screen repaint, we should make sure
-- refresh_count is incremented by only once at most for each repaint
-- NOTE: Ideally, we'd only check for "partial"" w/ no region set (that neatly narrows it down to just the reader).
-- In practice, we also want to promote refreshes in a few other places, except purely text-poor UI elements.
-- (Putting "ui" in that list is problematic with a number of UI elements, most notably, ReaderHighlight,
-- because it is implemented as "ui" over the full viewport, since we can't devise a proper bounding box).
-- So we settle for only "partial", but treating full-screen ones slightly differently.
if mode == " partial " and not self.refresh_counted then
self.refresh_count = ( self.refresh_count + 1 ) % self.FULL_REFRESH_COUNT
if self.refresh_count == self.FULL_REFRESH_COUNT - 1 then
-- NOTE: Promote to "full" if no region (reader), to "flashui" otherwise (UI)
if region then
mode = " flashui "
else
mode = " full "
end
logger.dbg ( " _refresh: promote refresh to " , mode )
end
self.refresh_counted = true
end
-- if no region is specified, define default region
region = region or Geom : new { w = Screen : getWidth ( ) , h = Screen : getHeight ( ) }
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- if no dithering hint was specified, don't request dithering
dither = dither or false
-- NOTE: While, ideally, we shouldn't merge refreshes w/ different waveform modes,
-- this allows us to optimize away a number of quirks of our rendering stack
-- (f.g., multiple setDirty calls queued when showing/closing a widget because of update mechanisms),
-- as well as a few actually effective merges
-- (f.g., the disappearance of a selection HL with the following menu update).
for i = 1 , # self._refresh_stack do
-- check for collision with refreshes that are already enqueued
if region : intersectWith ( self._refresh_stack [ i ] . region ) then
-- combine both refreshes' regions
local combined = region : combine ( self._refresh_stack [ i ] . region )
-- update the mode, if needed
mode = update_mode ( mode , self._refresh_stack [ i ] . mode )
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- dithering hints are viral, one is enough to infect the whole queue
dither = update_dither ( dither , self._refresh_stack [ i ] . dither )
-- remove colliding refresh
table.remove ( self._refresh_stack , i )
-- and try again with combined data
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
return self : _refresh ( mode , combined , dither )
end
end
-- if we've stopped hitting collisions, enqueue the refresh
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
logger.dbg ( " _refresh: Enqueued " , mode , " update for region " , region.x , region.y , region.w , region.h , dither and " w/ HW dithering " or " " )
table.insert ( self._refresh_stack , { mode = mode , region = region , dither = dither } )
end
--- Repaints dirty widgets.
function UIManager : _repaint ( )
-- flag in which we will record if we did any repaints at all
-- will trigger a refresh if set.
local dirty = false
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- remember if any of our repaints were dithered
local dithered = false
-- We don't need to call paintTo() on widgets that are under
-- a widget that covers the full screen
local start_idx = 1
for i = # self._window_stack , 1 , - 1 do
if self._window_stack [ i ] . widget.covers_fullscreen then
start_idx = i
if i > 1 then
logger.dbg ( " not painting " , i - 1 , " covered widget(s) " )
end
break
end
end
for i = start_idx , # self._window_stack do
local widget = self._window_stack [ i ]
-- paint if current widget or any widget underneath is dirty
if dirty or self._dirty [ widget.widget ] then
-- pass hint to widget that we got when setting widget dirty
-- the widget can use this to decide which parts should be refreshed
logger.dbg ( " painting widget: " , widget.widget . name or widget.widget . id or tostring ( widget ) )
widget.widget : paintTo ( Screen.bb , widget.x , widget.y , self._dirty [ widget.widget ] )
-- and remove from list after painting
self._dirty [ widget.widget ] = nil
-- trigger repaint
dirty = true
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- if any of 'em were dithered, we'll want to dither the final refresh
if widget.widget . dithered then
logger.dbg ( " _repaint: it was dithered, infecting the refresh queue " )
dithered = true
end
end
end
-- execute pending refresh functions
for _ , refreshfunc in ipairs ( self._refresh_func_stack ) do
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
local refreshtype , region , dither = refreshfunc ( )
-- honor dithering hints from *anywhere* in the dirty stack
dither = update_dither ( dither , dithered )
if refreshtype then self : _refresh ( refreshtype , region , dither ) end
end
self._refresh_func_stack = { }
-- we should have at least one refresh if we did repaint. If we don't, we
-- add one now and log a warning if we are debugging
if dirty and # self._refresh_stack == 0 then
logger.dbg ( " no refresh got enqueued. Will do a partial full screen refresh, which might be inefficient " )
self : _refresh ( " partial " )
end
-- execute refreshes:
for _ , refresh in ipairs ( self._refresh_stack ) do
dbg : v ( " triggering refresh " , refresh )
-- NOTE: We overshoot by 1px to account for potential off-by-ones.
-- This may not strictly be needed anymore, and is blatantly unneeded for full-screen updates,
-- but checkBounds & getPhysicalRect will sanitize that in mxc_update @ ffi/framebuffer_mxcfb ;).
Screen [ refresh_methods [ refresh.mode ] ] ( Screen ,
refresh.region . x - 1 , refresh.region . y - 1 ,
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
refresh.region . w + 2 , refresh.region . h + 2 ,
refresh.dither )
end
self._refresh_stack = { }
self.refresh_counted = false
end
function UIManager : forceRePaint ( )
self : _repaint ( )
end
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
6 years ago
-- Used to repaint a specific sub-widget that isn't on the _window_stack itself
-- Useful to avoid repainting a complex widget when we just want to invert an icon, for instance.
-- No safety checks on x & y *by design*. I want this to blow up if used wrong.
function UIManager : widgetRepaint ( widget , x , y )
if not widget then return end
logger.dbg ( " Explicit widgetRepaint: " , widget.name or widget.id or tostring ( widget ) , " @ ( " , x , " , " , y , " ) " )
widget : paintTo ( Screen.bb , x , y )
end
function UIManager : setInputTimeout ( timeout )
self.INPUT_TIMEOUT = timeout or 200 * 1000
end
function UIManager : resetInputTimeout ( )
self.INPUT_TIMEOUT = nil
end
function UIManager : handleInputEvent ( input_event )
if input_event.handler ~= " onInputError " then
self.event_hook : execute ( " InputEvent " , input_event )
end
local handler = self.event_handlers [ input_event ]
if handler then
handler ( input_event )
else
self.event_handlers [ " __default__ " ] ( input_event )
end
end
-- Process all pending events on all registered ZMQs.
function UIManager : processZMQs ( )
for _ , zeromq in ipairs ( self._zeromqs ) do
for input_event in zeromq.waitEvent , zeromq do
self : handleInputEvent ( input_event )
end
end
end
function UIManager : handleInput ( )
local wait_until , now
-- run this in a loop, so that paints can trigger events
-- that will be honored when calculating the time to wait
-- for input events:
repeat
wait_until , now = self : _checkTasks ( )
--dbg("---------------------------------------------------")
--dbg("exec stack", self._task_queue)
--dbg("window stack", self._window_stack)
--dbg("dirty stack", self._dirty)
--dbg("---------------------------------------------------")
-- stop when we have no window to show
if # self._window_stack == 0 and not self._run_forever then
logger.info ( " no dialog left to show " )
self : quit ( )
return nil
end
self : _repaint ( )
until not self._task_queue_dirty
-- run ZMQs if any
self : processZMQs ( )
-- Figure out how long to wait.
-- Default to INPUT_TIMEOUT (which may be nil, i.e. block until an event happens).
local wait_us = self.INPUT_TIMEOUT
-- If there's a timed event pending, that puts an upper bound on how long to wait.
if wait_until then
wait_us = math.min (
wait_us or math.huge ,
( wait_until [ 1 ] - now [ 1 ] ) * MILLION
+ ( wait_until [ 2 ] - now [ 2 ] ) )
end
-- If we have any ZMQs registered, ZMQ_TIMEOUT is another upper bound.
if # self._zeromqs > 0 then
wait_us = math.min ( wait_us or math.huge , self.ZMQ_TIMEOUT )
end
-- wait for next event
local input_event = Input : waitEvent ( wait_us )
-- delegate input_event to handler
if input_event then
self : handleInputEvent ( input_event )
end
if self.looper then
logger.info ( " handle input in turbo I/O looper " )
self.looper : add_callback ( function ( )
-- FIXME: force close looper when there is unhandled error,
-- otherwise the looper will hang. Any better solution?
xpcall ( function ( ) self : handleInput ( ) end , function ( err )
io.stderr : write ( err .. " \n " )
io.stderr : write ( debug.traceback ( ) .. " \n " )
io.stderr : flush ( )
self.looper : close ( )
os.exit ( 1 )
end )
end )
end
end
function UIManager : onRotation ( )
self : setDirty ( ' all ' , ' full ' )
self : forceRePaint ( )
end
function UIManager : initLooper ( )
if DUSE_TURBO_LIB and not self.looper then
TURBO_SSL = true -- luacheck: ignore
__TURBO_USE_LUASOCKET__ = true -- luacheck: ignore
local turbo = require ( " turbo " )
self.looper = turbo.ioloop . instance ( )
end
end
-- this is the main loop of the UI controller
-- it is intended to manage input events and delegate
-- them to dialogs
function UIManager : run ( )
self._running = true
self : initLooper ( )
-- currently there is no Turbo support for Windows
-- use our own main loop
if not self.looper then
while self._running do
self : handleInput ( )
end
else
self.looper : add_callback ( function ( ) self : handleInput ( ) end )
self.looper : start ( )
end
return self._exit_code
end
-- run uimanager forever for testing purpose
function UIManager : runForever ( )
self._run_forever = true
return self : run ( )
end
-- The common operations should be performed before suspending the device. Ditto.
function UIManager : _beforeSuspend ( )
self : flushSettings ( )
self : broadcastEvent ( Event : new ( " Suspend " ) )
end
-- The common operations should be performed after resuming the device. Ditto.
function UIManager : _afterResume ( )
self : broadcastEvent ( Event : new ( " Resume " ) )
end
function UIManager : _beforeCharging ( )
self : broadcastEvent ( Event : new ( " Charging " ) )
end
function UIManager : _afterNotCharging ( )
self : broadcastEvent ( Event : new ( " NotCharging " ) )
end
-- Executes all the operations of a suspending request. This function usually puts the device into
-- suspension.
function UIManager : suspend ( )
if Device : isCervantes ( ) or Device : isKobo ( ) or Device : isSDL ( ) or Device : isSonyPRSTUX ( ) then
self.event_handlers [ " Suspend " ] ( )
elseif Device : isKindle ( ) then
Device.powerd : toggleSuspend ( )
end
end
-- Executes all the operations of a resume request. This function usually wakes up the device.
function UIManager : resume ( )
if Device : isCervantes ( ) or Device : isKobo ( ) or Device : isSDL ( ) or Device : isSonyPRSTUX ( ) then
self.event_handlers [ " Resume " ] ( )
elseif Device : isKindle ( ) then
self.event_handlers [ " OutOfSS " ] ( )
end
end
function UIManager : flushSettings ( )
self : broadcastEvent ( Event : new ( " FlushSettings " ) )
end
function UIManager : restartKOReader ( )
self : quit ( )
-- This is just a magic number to indicate the restart request for shell scripts.
self._exit_code = 85
end
UIManager : init ( )
return UIManager