2017-04-09 13:35:01 +00:00
--[[--
This module manages widgets .
] ]
2014-10-30 18:42:18 +00:00
local Device = require ( " device " )
2013-10-18 20:38:07 +00:00
local Event = require ( " ui/event " )
2014-11-28 20:12:54 +00:00
local Geom = require ( " ui/geometry " )
2016-03-29 06:37:15 +00:00
local dbg = require ( " dbg " )
2016-12-29 08:10:38 +00:00
local logger = require ( " logger " )
2017-04-09 13:35:01 +00:00
local util = require ( " ffi/util " )
2017-06-23 17:04:11 +00:00
local _ = require ( " gettext " )
2017-04-09 13:35:01 +00:00
local Input = Device.input
local Screen = Device.screen
2012-04-22 19:29:48 +00:00
2015-12-26 00:48:40 +00:00
local MILLION = 1000000
2012-04-22 19:29:48 +00:00
-- there is only one instance of this
2013-10-18 20:38:07 +00:00
local UIManager = {
2014-03-13 13:52:43 +00:00
-- trigger a full refresh when counter reaches FULL_REFRESH_COUNT
2016-02-25 08:54:41 +00:00
FULL_REFRESH_COUNT =
G_reader_settings : readSetting ( " full_refresh_count " ) or DRCOUNTMAX ,
2014-03-13 13:52:43 +00:00
refresh_count = 0 ,
2013-03-12 17:18:53 +00:00
2018-01-01 14:40:28 +00:00
-- How long to wait between ZMQ wakeups: 50ms.
ZMQ_TIMEOUT = 50 * 1000 ,
2014-06-26 17:37:33 +00:00
event_handlers = nil ,
2014-03-13 13:52:43 +00:00
_running = true ,
_window_stack = { } ,
2015-12-26 00:48:40 +00:00
_task_queue = { } ,
_task_queue_dirty = false ,
2014-06-23 14:33:11 +00:00
_dirty = { } ,
_zeromqs = { } ,
2014-11-28 20:12:54 +00:00
_refresh_stack = { } ,
_refresh_func_stack = { } ,
2016-11-16 10:49:34 +00:00
_entered_poweroff_stage = false ,
2017-05-16 09:11:11 +00:00
_exit_code = nil ,
2017-06-23 17:04:11 +00:00
event_hook = require ( " ui/hook_container " ) : new ( )
2012-04-22 19:29:48 +00:00
}
2014-06-26 17:37:33 +00:00
function UIManager : init ( )
self.event_handlers = {
__default__ = function ( input_event )
self : sendEvent ( input_event )
end ,
SaveState = function ( )
2017-05-16 09:11:11 +00:00
self : flushSettings ( )
2014-08-26 10:10:26 +00:00
end ,
Power = function ( input_event )
Device : onPowerEvent ( input_event )
end ,
2014-06-26 17:37:33 +00:00
}
2016-11-16 10:49:34 +00:00
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)
2019-02-07 00:14:37 +00:00
if Device : needsScreenRefreshAfterResume ( ) then
Screen : refreshFull ( )
end
2016-11-16 10:49:34 +00:00
UIManager : nextTick ( function ( )
2017-09-04 19:05:05 +00:00
Device : saveSettings ( )
2016-11-16 10:49:34 +00:00
self : broadcastEvent ( Event : new ( " Close " ) )
Device : powerOff ( )
end )
end
2017-05-14 16:43:08 +00:00
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)
2019-02-07 00:14:37 +00:00
if Device : needsScreenRefreshAfterResume ( ) then
Screen : refreshFull ( )
end
2017-05-14 16:43:08 +00:00
UIManager : nextTick ( function ( )
2017-09-04 19:05:05 +00:00
Device : saveSettings ( )
2017-05-14 16:43:08 +00:00
self : broadcastEvent ( Event : new ( " Close " ) )
Device : reboot ( )
end )
end
2018-01-06 12:14:26 +00:00
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
2014-06-26 17:37:33 +00:00
if Device : isKobo ( ) then
2016-03-18 23:33:14 +00:00
-- We do not want auto suspend procedure to waste battery during
-- suspend. So let's unschedule it when suspending, and restart it after
2019-03-26 21:28:27 +00:00
-- resume. Done via the plugin's onSuspend/onResume handlers.
2016-05-02 07:51:58 +00:00
self.event_handlers [ " Suspend " ] = function ( )
2019-03-26 21:28:27 +00:00
-- Ignore the accelerometer (if that's not already the case) while we're alseep
if G_reader_settings : nilOrFalse ( " input_ignore_gsensor " ) then
2019-07-01 15:12:24 +00:00
Device : toggleGSensor ( false )
2019-03-26 21:28:27 +00:00
end
2017-05-16 09:11:11 +00:00
self : _beforeSuspend ( )
2016-05-02 07:51:58 +00:00
Device : onPowerEvent ( " Suspend " )
2014-08-26 10:10:26 +00:00
end
2016-05-02 07:51:58 +00:00
self.event_handlers [ " Resume " ] = function ( )
Device : onPowerEvent ( " Resume " )
2017-05-16 09:11:11 +00:00
self : _afterResume ( )
2019-03-26 21:28:27 +00:00
-- Stop ignoring the accelerometer (unless requested) when we wakeup
if G_reader_settings : nilOrFalse ( " input_ignore_gsensor " ) then
2019-07-01 15:12:24 +00:00
Device : toggleGSensor ( true )
2019-03-26 21:28:27 +00:00
end
2014-06-26 17:37:33 +00:00
end
2016-05-02 07:51:58 +00:00
self.event_handlers [ " PowerPress " ] = function ( )
2016-11-16 10:49:34 +00:00
UIManager : scheduleIn ( 2 , self.poweroff_action )
2016-04-26 22:30:52 +00:00
end
2016-05-02 07:51:58 +00:00
self.event_handlers [ " PowerRelease " ] = function ( )
2016-11-16 10:49:34 +00:00
if not self._entered_poweroff_stage then
UIManager : unschedule ( self.poweroff_action )
2017-05-16 09:11:11 +00:00
self : suspend ( )
2016-04-26 22:30:52 +00:00
end
end
2019-06-28 20:19:25 +00:00
-- Sleep Cover handling
if G_reader_settings : readSetting ( " ignore_power_sleepcover " ) then
-- NOTE: The hardware event itself will wake the kernel up if it's in suspend (:/).
-- Let the unexpected wakeup guard handle that.
self.event_handlers [ " SleepCoverClosed " ] = nil
self.event_handlers [ " SleepCoverOpened " ] = nil
elseif G_reader_settings : readSetting ( " ignore_open_sleepcover " ) then
-- Just ignore wakeup events, and do NOT set is_cover_closed,
-- so device/generic/device will let us use the power button to wake ;).
2016-09-14 05:16:31 +00:00
self.event_handlers [ " SleepCoverClosed " ] = function ( )
2017-05-16 09:11:11 +00:00
self : suspend ( )
2016-09-14 05:16:31 +00:00
end
self.event_handlers [ " SleepCoverOpened " ] = function ( )
Device.is_cover_closed = false
end
2016-09-12 04:38:06 +00:00
else
self.event_handlers [ " SleepCoverClosed " ] = function ( )
2019-06-28 20:19:25 +00:00
Device.is_cover_closed = true
self : suspend ( )
end
self.event_handlers [ " SleepCoverOpened " ] = function ( )
Device.is_cover_closed = false
self : resume ( )
2016-09-12 04:38:06 +00:00
end
end
2014-06-26 17:37:33 +00:00
self.event_handlers [ " Light " ] = function ( )
Device : getPowerDevice ( ) : toggleFrontlight ( )
end
2016-10-22 07:04:37 +00:00
self.event_handlers [ " Charging " ] = function ( )
2017-05-16 09:11:11 +00:00
self : _beforeCharging ( )
2017-03-24 06:36:15 +00:00
if Device.screen_saver_mode then
2017-05-16 09:11:11 +00:00
self : suspend ( )
2017-03-24 06:36:15 +00:00
end
end
self.event_handlers [ " NotCharging " ] = function ( )
2017-05-16 09:11:11 +00:00
-- We need to put the device into suspension, other things need to be done before it.
self : _afterNotCharging ( )
2016-09-20 07:14:14 +00:00
if Device.screen_saver_mode then
2017-05-16 09:11:11 +00:00
self : suspend ( )
2016-09-20 07:14:14 +00:00
end
end
2014-06-26 18:28:57 +00:00
self.event_handlers [ " __default__ " ] = function ( input_event )
2018-03-28 10:57:55 +00:00
-- 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
2014-06-26 18:28:57 +00:00
self : sendEvent ( input_event )
end
end
2014-06-26 17:37:33 +00:00
elseif Device : isKindle ( ) then
self.event_handlers [ " IntoSS " ] = function ( )
2017-05-16 09:11:11 +00:00
self : _beforeSuspend ( )
2014-06-26 17:37:33 +00:00
Device : intoScreenSaver ( )
end
self.event_handlers [ " OutOfSS " ] = function ( )
Device : outofScreenSaver ( )
2017-05-16 09:11:11 +00:00
self : _afterResume ( ) ;
2014-06-26 17:37:33 +00:00
end
self.event_handlers [ " Charging " ] = function ( )
2017-05-16 09:11:11 +00:00
self : _beforeCharging ( )
2014-06-26 17:37:33 +00:00
Device : usbPlugIn ( )
end
self.event_handlers [ " NotCharging " ] = function ( )
Device : usbPlugOut ( )
2017-05-16 09:11:11 +00:00
self : _afterNotCharging ( )
2014-06-21 16:24:37 +00:00
end
2018-09-07 23:37:04 +00:00
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
2018-10-31 22:48:36 +00:00
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 ( )
2018-11-10 12:16:03 +00:00
self : _beforeCharging ( )
2018-10-31 22:48:36 +00:00
if Device.screen_saver_mode then
self : suspend ( )
2018-11-10 12:16:03 +00:00
end
2018-10-31 22:48:36 +00:00
end
self.event_handlers [ " NotCharging " ] = function ( )
2018-11-10 12:16:03 +00:00
self : _afterNotCharging ( )
2018-10-31 22:48:36 +00:00
if Device.screen_saver_mode then
self : suspend ( )
2018-11-10 12:16:03 +00:00
end
2018-10-31 22:48:36 +00:00
end
self.event_handlers [ " UsbPlugIn " ] = function ( )
2018-11-10 12:16:03 +00:00
self : _beforeCharging ( )
2018-10-31 22:48:36 +00:00
if Device.screen_saver_mode then
self : suspend ( )
2018-11-10 12:16:03 +00:00
end
2018-10-31 22:48:36 +00:00
end
self.event_handlers [ " USbPlugOut " ] = function ( )
2018-11-10 12:16:03 +00:00
self : _afterNotCharging ( )
2018-10-31 22:48:36 +00:00
if Device.screen_saver_mode then
self : suspend ( )
2018-11-10 12:16:03 +00:00
end
2018-10-31 22:48:36 +00:00
end
self.event_handlers [ " __default__ " ] = function ( input_event )
2018-11-10 12:16:03 +00:00
-- Same as in Kobo: we want to ignore keys during suspension
2018-10-31 22:48:36 +00:00
if not Device.screen_saver_mode then
self : sendEvent ( input_event )
end
end
2017-06-23 17:04:11 +00:00
elseif Device : isSDL ( ) then
self.event_handlers [ " Suspend " ] = function ( )
self : _beforeSuspend ( )
Device : simulateSuspend ( )
end
self.event_handlers [ " Resume " ] = function ( )
Device : simulateResume ( )
self : _afterResume ( )
end
2014-06-21 16:24:37 +00:00
end
end
2017-04-09 13:35:01 +00:00
--[[--
Registers and shows a widget .
Modal widget should be always on top .
For refreshtype & refreshregion see description of setDirty ( ) .
] ]
---- @param widget a widget object
2018-06-02 16:10:55 +00:00
---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast"
2017-04-09 13:35:01 +00:00
---- @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)
2019-02-07 00:14:37 +00:00
---- @param refreshdither an optional bool
2017-04-09 13:35:01 +00:00
---- @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)
2019-02-07 00:14:37 +00:00
function UIManager : show ( widget , refreshtype , refreshregion , x , y , refreshdither )
2016-08-12 06:05:18 +00:00
if not widget then
2016-12-29 08:10:38 +00:00
logger.dbg ( " widget not exist to be shown " )
2016-08-12 06:05:18 +00:00
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)
2019-02-07 00:14:37 +00:00
logger.dbg ( " show widget: " , widget.id or widget.name or tostring ( widget ) )
2016-08-12 06:05:18 +00:00
2014-09-03 03:13:46 +00:00
self._running = true
2014-10-30 08:01:01 +00:00
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
2017-09-05 07:01:46 +00:00
if widget.modal or not top_window or not top_window.widget . modal then
2014-10-30 08:01:01 +00:00
table.insert ( self._window_stack , i + 1 , window )
break
end
end
2014-03-13 13:52:43 +00:00
-- 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)
2019-02-07 00:14:37 +00:00
self : setDirty ( widget , refreshtype , refreshregion , refreshdither )
2014-03-13 13:52:43 +00:00
-- tell the widget that it is shown now
widget : handleEvent ( Event : new ( " Show " ) )
-- check if this widget disables double tap gesture
2016-06-27 15:00:49 +00:00
if widget.disable_double_tap == false then
Input.disable_double_tap = false
else
2014-03-13 13:52:43 +00:00
Input.disable_double_tap = true
end
2012-04-22 19:29:48 +00:00
end
2017-04-09 13:35:01 +00:00
--[[--
Unregisters a widget .
For refreshtype & refreshregion see description of setDirty ( ) .
] ]
---- @param widget a widget object
2018-06-02 16:10:55 +00:00
---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast"
2017-04-09 13:35:01 +00:00
---- @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)
2019-02-07 00:14:37 +00:00
---- @param refreshdither an optional bool
2017-04-09 13:35:01 +00:00
---- @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)
2019-02-07 00:14:37 +00:00
function UIManager : close ( widget , refreshtype , refreshregion , refreshdither )
2014-11-06 06:00:47 +00:00
if not widget then
2018-06-02 16:10:55 +00:00
logger.dbg ( " widget to be closed does not exist " )
2014-11-06 06:00:47 +00:00
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)
2019-02-07 00:14:37 +00:00
logger.dbg ( " close widget: " , widget.name or widget.id or tostring ( widget ) )
2014-03-13 13:52:43 +00:00
local dirty = false
2017-05-16 09:11:11 +00:00
-- Ensure all the widgets can get onFlushSettings event.
widget : handleEvent ( Event : new ( " FlushSettings " ) )
2016-06-21 08:50:01 +00:00
-- first send close event to widget
widget : handleEvent ( Event : new ( " CloseWidget " ) )
2019-03-02 15:50:07 +00:00
-- make it disabled by default and check if any widget wants it disabled or enabled
2016-07-14 00:53:29 +00:00
Input.disable_double_tap = true
2019-03-02 15:50:07 +00:00
local requested_disable_double_tap = nil
2018-06-02 16:10:55 +00:00
-- then remove all references to that widget on stack and refresh
2014-03-13 13:52:43 +00:00
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)
2019-02-07 00:14:37 +00:00
self._dirty [ self._window_stack [ i ] . widget ] = nil
2014-03-13 13:52:43 +00:00
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)
2019-02-07 00:14:37 +00:00
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
2019-03-02 15:50:07 +00:00
-- 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)
2019-02-07 00:14:37 +00:00
end
2014-03-13 13:52:43 +00:00
end
end
2019-03-02 15:50:07 +00:00
if requested_disable_double_tap ~= nil then
Input.disable_double_tap = requested_disable_double_tap
end
2018-01-16 11:30:23 +00:00
if dirty and not widget.invisible then
2014-03-13 13:52:43 +00:00
-- schedule remaining widgets to be painted
for i = 1 , # self._window_stack do
2014-11-30 22:01:13 +00:00
self : setDirty ( self._window_stack [ i ] . widget )
2014-03-13 13:52:43 +00:00
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)
2019-02-07 00:14:37 +00:00
self : _refresh ( refreshtype , refreshregion , refreshdither )
2014-03-13 13:52:43 +00:00
end
2012-04-22 19:29:48 +00:00
end
2015-12-26 00:48:40 +00:00
-- schedule an execution task, task queue is in ascendant order
2012-04-22 19:29:48 +00:00
function UIManager : schedule ( time , action )
2015-12-26 00:48:40 +00:00
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
2016-04-24 04:16:37 +00:00
-- for fairness, it's better to make p+1 is strictly less than
-- p might want to revisit here in the future
2015-12-26 00:48:40 +00:00
break
end
until e < s
end
table.insert ( self._task_queue , p , { time = time , action = action } )
self._task_queue_dirty = true
2012-04-22 19:29:48 +00:00
end
2016-03-29 06:37:15 +00:00
dbg : guard ( UIManager , ' schedule ' ,
function ( self , time , action )
assert ( time [ 1 ] >= 0 and time [ 2 ] >= 0 , " Only positive time allowed " )
assert ( action ~= nil )
end )
2012-04-22 19:29:48 +00:00
2017-04-09 13:35:01 +00:00
--- Schedules task in a certain amount of seconds (fractions allowed) from now.
2012-04-22 19:29:48 +00:00
function UIManager : scheduleIn ( seconds , action )
2014-03-13 13:52:43 +00:00
local when = { util.gettime ( ) }
local s = math.floor ( seconds )
2015-12-26 00:48:40 +00:00
local usecs = ( seconds - s ) * MILLION
2014-03-13 13:52:43 +00:00
when [ 1 ] = when [ 1 ] + s
when [ 2 ] = when [ 2 ] + usecs
2017-06-14 17:32:16 +00:00
if when [ 2 ] >= MILLION then
2014-03-13 13:52:43 +00:00
when [ 1 ] = when [ 1 ] + 1
2015-12-26 00:48:40 +00:00
when [ 2 ] = when [ 2 ] - MILLION
2014-03-13 13:52:43 +00:00
end
self : schedule ( when , action )
2012-04-22 19:29:48 +00:00
end
2016-03-29 06:37:15 +00:00
dbg : guard ( UIManager , ' scheduleIn ' ,
function ( self , seconds , action )
assert ( seconds >= 0 , " Only positive seconds allowed " )
end )
2012-04-22 19:29:48 +00:00
2016-02-17 06:36:40 +00:00
function UIManager : nextTick ( action )
return self : scheduleIn ( 0 , action )
end
2018-06-02 16:10:55 +00:00
-- 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
--]]
2017-04-09 13:35:01 +00:00
--[[-- 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 )
] ]
2014-11-06 11:59:00 +00:00
function UIManager : unschedule ( action )
2015-12-26 00:48:40 +00:00
for i = # self._task_queue , 1 , - 1 do
2016-03-08 06:52:52 +00:00
if self._task_queue [ i ] . action == action then
2015-12-26 00:48:40 +00:00
table.remove ( self._task_queue , i )
2014-11-06 11:59:00 +00:00
end
end
end
2016-03-29 06:37:15 +00:00
dbg : guard ( UIManager , ' unschedule ' ,
function ( self , action ) assert ( action ~= nil ) end )
2014-11-06 11:59:00 +00:00
2017-04-09 13:35:01 +00:00
--[[--
Registers a widget to be repainted and enqueues a refresh .
2014-11-28 20:12:54 +00:00
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 .
2018-06-02 16:10:55 +00:00
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)
2019-02-07 00:14:37 +00:00
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 ) .
2014-11-28 20:12:54 +00:00
2017-04-09 13:35:01 +00:00
@ usage
2014-11-28 20:12:54 +00:00
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 )
2017-04-09 13:35:01 +00:00
2014-11-28 20:12:54 +00:00
--]]
2017-04-09 13:35:01 +00:00
---- @param widget a widget object
2018-06-02 16:10:55 +00:00
---- @param refreshtype "full", "flashpartial", "flashui", "partial", "ui", "fast"
2017-04-09 13:35:01 +00:00
---- @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)
2019-02-07 00:14:37 +00:00
---- @param refreshdither an optional bool
function UIManager : setDirty ( widget , refreshtype , refreshregion , refreshdither )
2014-08-20 06:45:11 +00:00
if widget then
2014-11-28 20:12:54 +00:00
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)
2019-02-07 00:14:37 +00:00
-- 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
2014-11-28 20:12:54 +00:00
end
2018-01-16 11:30:23 +00:00
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)
2019-02-07 00:14:37 +00:00
-- 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
2014-11-28 20:12:54 +00:00
end
end
-- handle refresh information
if type ( refreshtype ) == " function " then
-- callback, will be issued after painting
table.insert ( self._refresh_func_stack , refreshtype )
2018-06-02 16:10:55 +00:00
if dbg.is_on then
2019-08-23 17:53:53 +00:00
--- @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...
2018-06-02 16:10:55 +00:00
-- 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)
2019-02-07 00:14:37 +00:00
logger.dbg ( " setDirty via a func from widget " , widget and ( widget.name or widget.id or tostring ( widget ) ) or " nil " )
2018-06-02 16:10:55 +00:00
end
2014-11-28 20:12:54 +00:00
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)
2019-02-07 00:14:37 +00:00
self : _refresh ( refreshtype , refreshregion , refreshdither )
2018-06-02 16:10:55 +00:00
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)
2019-02-07 00:14:37 +00:00
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 " " )
2018-06-02 16:10:55 +00:00
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)
2019-02-07 00:14:37 +00:00
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 " " )
2018-06-02 16:10:55 +00:00
end
end
2014-08-20 06:45:11 +00:00
end
2012-04-22 19:29:48 +00:00
end
2016-03-29 06:37:15 +00:00
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)
2019-02-07 00:14:37 +00:00
function ( self , widget , refreshtype , refreshregion , refreshdither )
2016-06-21 08:50:01 +00:00
if not widget or widget == " all " then return end
2016-03-29 06:37:15 +00:00
-- 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
2016-08-12 06:05:18 +00:00
dbg : v ( " INFO: invalid widget for setDirty() " , debug.traceback ( ) )
2016-03-29 06:37:15 +00:00
end
end )
2012-04-22 19:29:48 +00:00
2018-06-02 16:10:55 +00:00
-- 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
2014-06-23 14:33:11 +00:00
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
2017-04-09 13:35:01 +00:00
--- Sets full refresh rate for e-ink screen.
--
-- Also makes the refresh rate persistent in global reader settings.
2014-07-26 14:22:52 +00:00
function UIManager : setRefreshRate ( rate )
2016-12-29 08:10:38 +00:00
logger.dbg ( " set screen full refresh rate " , rate )
2014-07-26 14:22:52 +00:00
self.FULL_REFRESH_COUNT = rate
G_reader_settings : saveSetting ( " full_refresh_count " , rate )
end
2017-04-09 13:35:01 +00:00
--- Gets full refresh rate for e-ink screen.
2014-07-26 14:22:52 +00:00
function UIManager : getRefreshRate ( rate )
return self.FULL_REFRESH_COUNT
end
2017-04-09 13:35:01 +00:00
--- Signals to quit.
2012-04-22 19:29:48 +00:00
function UIManager : quit ( )
2017-05-16 09:11:11 +00:00
if not self._running then return end
2017-04-09 13:35:01 +00:00
logger.info ( " quitting uimanager " )
2015-12-26 00:48:40 +00:00
self._task_queue_dirty = false
2014-03-13 13:52:43 +00:00
self._running = false
2015-03-02 09:15:26 +00:00
self._run_forever = nil
2014-09-03 03:13:46 +00:00
for i = # self._window_stack , 1 , - 1 do
table.remove ( self._window_stack , i )
end
2015-12-26 00:48:40 +00:00
for i = # self._task_queue , 1 , - 1 do
table.remove ( self._task_queue , i )
2014-09-03 03:13:46 +00:00
end
2014-06-23 14:33:11 +00:00
for i = # self._zeromqs , 1 , - 1 do
self._zeromqs [ i ] : stop ( )
table.remove ( self._zeromqs , i )
end
2015-03-02 09:15:26 +00:00
if self.looper then
self.looper : close ( )
self.looper = nil
end
2012-04-22 19:29:48 +00:00
end
2017-04-09 13:35:01 +00:00
--- Transmits an event to an active widget.
2012-04-22 19:29:48 +00:00
function UIManager : sendEvent ( event )
2014-06-07 05:36:58 +00:00
if # self._window_stack == 0 then return end
2016-05-30 04:57:27 +00:00
local top_widget = self._window_stack [ # self._window_stack ]
2014-03-13 13:52:43 +00:00
-- top level widget has first access to the event
2016-05-30 04:57:27 +00:00
if top_widget.widget : handleEvent ( event ) then
2014-03-13 13:52:43 +00:00
return
end
2016-05-30 04:57:27 +00:00
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
2014-03-13 13:52:43 +00:00
end
2016-05-30 04:57:27 +00:00
end
2016-08-18 15:47:51 +00:00
-- if the event is not consumed, active widgets (from top to bottom) can
2016-05-30 04:57:27 +00:00
-- access it. NOTE: _window_stack can shrink on close event
local checked_widgets = { top_widget }
2016-06-11 19:17:18 +00:00
for i = # self._window_stack , 1 , - 1 do
2016-05-30 04:57:27 +00:00
local widget = self._window_stack [ i ]
if checked_widgets [ widget ] == nil then
2016-08-12 06:05:18 +00:00
-- active widgets has precedence to handle this event
-- Note: ReaderUI currently only has one active_widget: readerscreenshot
2016-05-30 04:57:27 +00:00
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
2014-03-13 13:52:43 +00:00
end
2016-08-18 15:47:51 +00:00
if widget.widget . is_always_active then
-- active widgets will handle this event
2018-03-30 10:46:36 +00:00
-- Note: is_always_active widgets currently are widgets that want to show a keyboard
-- and readerconfig
2016-08-18 15:47:51 +00:00
checked_widgets [ widget ] = true
if widget.widget : handleEvent ( event ) then return end
end
2014-03-13 13:52:43 +00:00
end
end
2012-04-22 19:29:48 +00:00
end
2017-04-09 13:35:01 +00:00
--- Transmits an event to all registered widgets.
2016-05-01 12:46:17 +00:00
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
2016-06-27 16:43:23 +00:00
while i <= # self._window_stack do
2016-05-01 12:46:17 +00:00
local prev_widget = self._window_stack [ i ] . widget
self._window_stack [ i ] . widget : handleEvent ( event )
2016-06-19 00:24:38 +00:00
local top_widget = self._window_stack [ i ]
if top_widget == nil then
-- top widget closed itself
break
2016-06-27 16:43:23 +00:00
elseif top_widget.widget == prev_widget then
2016-06-19 00:24:38 +00:00
i = i + 1
2016-05-01 12:46:17 +00:00
end
end
end
2014-11-28 20:12:54 +00:00
function UIManager : _checkTasks ( )
2014-03-13 13:52:43 +00:00
local now = { util.gettime ( ) }
2015-12-26 00:48:40 +00:00
local now_us = now [ 1 ] * MILLION + now [ 2 ]
2014-03-13 13:52:43 +00:00
local wait_until = nil
2015-12-26 00:48:40 +00:00
2016-03-18 23:33:14 +00:00
-- task.action may schedule other events
self._task_queue_dirty = false
2015-12-26 00:48:40 +00:00
while true do
2016-01-03 09:18:54 +00:00
local nu_task = # self._task_queue
if nu_task == 0 then
2015-12-26 00:48:40 +00:00
-- 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 ]
2014-03-13 13:52:43 +00:00
end
2015-12-26 00:48:40 +00:00
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
2014-11-14 08:12:46 +00:00
return wait_until , now
2013-01-05 14:28:14 +00:00
end
2014-11-28 20:12:54 +00:00
-- precedence of refresh modes:
2018-06-02 16:10:55 +00:00
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)
2019-02-07 00:14:37 +00:00
-- 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?).
2014-11-28 20:12:54 +00:00
-- refresh methods in framebuffer implementation
local refresh_methods = {
fast = " refreshFast " ,
ui = " refreshUI " ,
partial = " refreshPartial " ,
2018-06-02 16:10:55 +00:00
flashui = " refreshFlashUI " ,
flashpartial = " refreshFlashPartial " ,
2014-11-28 20:12:54 +00:00
full = " refreshFull " ,
}
--[[
2017-04-09 13:35:01 +00:00
Compares refresh mode .
2014-11-28 20:12:54 +00:00
2017-04-09 13:35:01 +00:00
Will return the mode that takes precedence .
2014-11-28 20:12:54 +00:00
--]]
local function update_mode ( mode1 , mode2 )
if refresh_modes [ mode1 ] > refresh_modes [ mode2 ] then
2018-06-02 16:10:55 +00:00
logger.dbg ( " update_mode: Update refresh mode " , mode2 , " to " , mode1 )
2014-11-28 20:12:54 +00:00
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)
2019-02-07 00:14:37 +00:00
--[[
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
2017-04-09 13:35:01 +00:00
--[[--
Enqueues a refresh .
2014-11-28 20:12:54 +00:00
Widgets call this in their paintTo ( ) method in order to notify
UIManager that a certain part of the screen is to be refreshed .
2017-04-09 13:35:01 +00:00
@ param mode
2018-06-02 16:10:55 +00:00
refresh mode ( " full " , " flashpartial " , " flashui " , " partial " , " ui " , " fast " )
2017-04-09 13:35:01 +00:00
@ 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)
2019-02-07 00:14:37 +00:00
@ param dither
Bool , a hint to request hardware dithering ( if supported )
optional , no dithering requested if not specified or not supported .
2014-11-28 20:12:54 +00:00
--]]
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)
2019-02-07 00:14:37 +00:00
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
2016-12-04 14:17:04 +00:00
if not region and mode == " full " then
self.refresh_count = 0 -- reset counter on explicit full refresh
end
2018-06-02 16:10:55 +00:00
-- 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
2014-12-04 07:46:47 +00:00
-- since _refresh can be called mutiple times via setDirty called in
2018-06-02 16:10:55 +00:00
-- different widgets before a real screen repaint, we should make sure
2014-12-04 07:46:47 +00:00
-- refresh_count is incremented by only once at most for each repaint
2018-06-02 16:10:55 +00:00
-- 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
2014-11-28 20:12:54 +00:00
self.refresh_count = ( self.refresh_count + 1 ) % self.FULL_REFRESH_COUNT
if self.refresh_count == self.FULL_REFRESH_COUNT - 1 then
2018-06-02 16:10:55 +00:00
-- 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 )
2014-11-28 20:12:54 +00:00
end
2014-12-04 07:46:47 +00:00
self.refresh_counted = true
2014-11-28 20:12:54 +00:00
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)
2019-02-07 00:14:37 +00:00
-- if no dithering hint was specified, don't request dithering
dither = dither or false
2018-06-02 16:10:55 +00:00
-- 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).
2014-11-28 20:12:54 +00:00
for i = 1 , # self._refresh_stack do
2018-06-02 16:10:55 +00:00
-- check for collision with refreshes that are already enqueued
2014-11-28 20:12:54 +00:00
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
2016-02-16 07:10:07 +00:00
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)
2019-02-07 00:14:37 +00:00
-- dithering hints are viral, one is enough to infect the whole queue
dither = update_dither ( dither , self._refresh_stack [ i ] . dither )
2018-06-02 16:10:55 +00:00
-- remove colliding refresh
2014-11-28 20:12:54 +00:00
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)
2019-02-07 00:14:37 +00:00
return self : _refresh ( mode , combined , dither )
2014-11-28 20:12:54 +00:00
end
end
2018-06-02 16:10:55 +00:00
-- 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)
2019-02-07 00:14:37 +00:00
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 } )
2014-11-28 20:12:54 +00:00
end
2017-04-09 13:35:01 +00:00
--- Repaints dirty widgets.
2014-11-28 20:12:54 +00:00
function UIManager : _repaint ( )
2014-11-20 19:24:02 +00:00
-- flag in which we will record if we did any repaints at all
-- will trigger a refresh if set.
2014-11-14 08:09:50 +00:00
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)
2019-02-07 00:14:37 +00:00
-- remember if any of our repaints were dithered
local dithered = false
2014-11-20 19:24:02 +00:00
2018-03-17 22:02:32 +00:00
-- 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 ]
2014-11-28 20:12:54 +00:00
-- 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
2018-03-17 22:02:32 +00:00
logger.dbg ( " painting widget: " , widget.widget . name or widget.widget . id or tostring ( widget ) )
2014-11-28 20:12:54 +00:00
widget.widget : paintTo ( Screen.bb , widget.x , widget.y , self._dirty [ widget.widget ] )
2014-11-20 19:24:02 +00:00
2014-11-14 08:09:50 +00:00
-- and remove from list after painting
self._dirty [ widget.widget ] = nil
2014-11-20 19:24:02 +00:00
2014-11-14 08:09:50 +00:00
-- 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)
2019-02-07 00:14:37 +00:00
-- 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
2014-11-14 08:09:50 +00:00
end
end
2014-11-28 20:12:54 +00:00
-- 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)
2019-02-07 00:14:37 +00:00
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
2014-11-28 20:12:54 +00:00
end
self._refresh_func_stack = { }
2016-06-21 08:50:01 +00:00
-- 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
2014-11-28 20:12:54 +00:00
if dirty and # self._refresh_stack == 0 then
2017-09-08 13:30:29 +00:00
logger.dbg ( " no refresh got enqueued. Will do a partial full screen refresh, which might be inefficient " )
2014-11-28 20:12:54 +00:00
self : _refresh ( " partial " )
end
2014-11-20 19:24:02 +00:00
2014-11-28 20:12:54 +00:00
-- execute refreshes:
for _ , refresh in ipairs ( self._refresh_stack ) do
2019-04-18 21:26:53 +00:00
-- Honor dithering hints from *anywhere* in the dirty stack
refresh.dither = update_dither ( refresh.dither , dithered )
-- If HW dithering is disabled, unconditionally drop the dither flag
if not Screen.hw_dithering then
refresh.dither = nil
end
2016-08-12 09:47:35 +00:00
dbg : v ( " triggering refresh " , refresh )
2018-09-08 01:29:55 +00:00
-- 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 ;).
2014-11-28 20:12:54 +00:00
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)
2019-02-07 00:14:37 +00:00
refresh.region . w + 2 , refresh.region . h + 2 ,
refresh.dither )
2014-11-14 08:09:50 +00:00
end
2014-11-28 20:12:54 +00:00
self._refresh_stack = { }
2014-12-04 07:46:47 +00:00
self.refresh_counted = false
2014-11-14 08:09:50 +00:00
end
2016-04-24 04:09:50 +00:00
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)
2019-02-07 00:14:37 +00:00
-- 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
2015-03-21 05:18:34 +00:00
function UIManager : setInputTimeout ( timeout )
self.INPUT_TIMEOUT = timeout or 200 * 1000
end
function UIManager : resetInputTimeout ( )
self.INPUT_TIMEOUT = nil
end
2018-01-01 14:40:28 +00:00
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
2015-03-02 09:15:26 +00:00
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 ( )
2016-03-29 06:37:15 +00:00
--dbg("---------------------------------------------------")
--dbg("exec stack", self._task_queue)
--dbg("window stack", self._window_stack)
--dbg("dirty stack", self._dirty)
--dbg("---------------------------------------------------")
2015-03-02 09:15:26 +00:00
-- stop when we have no window to show
if # self._window_stack == 0 and not self._run_forever then
2016-12-29 08:10:38 +00:00
logger.info ( " no dialog left to show " )
2015-03-02 09:15:26 +00:00
self : quit ( )
return nil
end
2012-04-22 19:29:48 +00:00
2015-03-02 09:15:26 +00:00
self : _repaint ( )
2015-12-26 00:48:40 +00:00
until not self._task_queue_dirty
2015-03-02 09:15:26 +00:00
2018-01-01 14:40:28 +00:00
-- 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 )
2015-03-02 09:15:26 +00:00
end
2012-04-22 19:29:48 +00:00
2018-01-01 14:40:28 +00:00
-- wait for next event
local input_event = Input : waitEvent ( wait_us )
2015-03-02 09:15:26 +00:00
-- delegate input_event to handler
if input_event then
2018-01-01 14:40:28 +00:00
self : handleInputEvent ( input_event )
2014-03-13 13:52:43 +00:00
end
2015-03-02 09:15:26 +00:00
if self.looper then
2016-12-29 08:10:38 +00:00
logger.info ( " handle input in turbo I/O looper " )
2015-03-21 05:18:34 +00:00
self.looper : add_callback ( function ( )
2019-08-23 17:53:53 +00:00
--- @fixme Force close looper when there is unhandled error,
2015-03-21 05:18:34 +00:00
-- 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 )
2015-03-02 09:15:26 +00:00
end
end
2016-08-02 09:21:27 +00:00
function UIManager : onRotation ( )
self : setDirty ( ' all ' , ' full ' )
self : forceRePaint ( )
end
2015-03-02 09:15:26 +00:00
function UIManager : initLooper ( )
2015-06-02 05:07:17 +00:00
if DUSE_TURBO_LIB and not self.looper then
2016-02-16 17:58:24 +00:00
TURBO_SSL = true -- luacheck: ignore
__TURBO_USE_LUASOCKET__ = true -- luacheck: ignore
2015-03-02 09:15:26 +00:00
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
2015-03-20 02:14:13 +00:00
self : initLooper ( )
2015-04-28 03:06:00 +00:00
-- currently there is no Turbo support for Windows
2015-03-20 02:14:13 +00:00
-- use our own main loop
if not self.looper then
while self._running do
self : handleInput ( )
end
2015-03-02 09:15:26 +00:00
else
2015-03-20 02:14:13 +00:00
self.looper : add_callback ( function ( ) self : handleInput ( ) end )
2015-03-02 09:15:26 +00:00
self.looper : start ( )
end
2017-05-16 09:11:11 +00:00
return self._exit_code
2015-03-02 09:15:26 +00:00
end
-- run uimanager forever for testing purpose
function UIManager : runForever ( )
self._run_forever = true
2017-05-16 09:11:11 +00:00
return self : run ( )
2012-04-22 19:29:48 +00:00
end
2013-10-18 20:38:07 +00:00
2017-05-16 09:11:11 +00:00
-- 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 ( )
2018-10-31 22:48:36 +00:00
if Device : isCervantes ( ) or Device : isKobo ( ) or Device : isSDL ( ) or Device : isSonyPRSTUX ( ) then
2017-05-16 09:11:11 +00:00
self.event_handlers [ " Suspend " ] ( )
elseif Device : isKindle ( ) then
2019-03-21 10:52:58 +00:00
Device.powerd : toggleSuspend ( )
2017-05-16 09:11:11 +00:00
end
end
-- Executes all the operations of a resume request. This function usually wakes up the device.
function UIManager : resume ( )
2018-10-31 22:48:36 +00:00
if Device : isCervantes ( ) or Device : isKobo ( ) or Device : isSDL ( ) or Device : isSonyPRSTUX ( ) then
2017-05-16 09:11:11 +00:00
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
2014-06-26 17:37:33 +00:00
UIManager : init ( )
2013-10-18 20:38:07 +00:00
return UIManager