mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
[feat] Replace TimeVal (RIP) with time, fixed point time seconds (#8999)
This commit is contained in:
@@ -16,7 +16,7 @@ memory_confirm_box = nil,
|
||||
|
||||
function ReaderDeviceStatus:init()
|
||||
if Device:hasBattery() then
|
||||
self.battery_interval = G_reader_settings:readSetting("device_status_battery_interval", 10)
|
||||
self.battery_interval_m = G_reader_settings:readSetting("device_status_battery_interval_minutes", 10)
|
||||
self.battery_threshold = G_reader_settings:readSetting("device_status_battery_threshold", 20)
|
||||
self.battery_threshold_high = G_reader_settings:readSetting("device_status_battery_threshold_high", 100)
|
||||
self.checkLowBatteryLevel = function()
|
||||
@@ -45,13 +45,13 @@ function ReaderDeviceStatus:init()
|
||||
UIManager:show(self.battery_confirm_box)
|
||||
end
|
||||
end
|
||||
UIManager:scheduleIn(self.battery_interval * 60, self.checkLowBatteryLevel)
|
||||
UIManager:scheduleIn(self.battery_interval_m * 60, self.checkLowBatteryLevel)
|
||||
end
|
||||
self:startBatteryChecker()
|
||||
end
|
||||
|
||||
if not Device:isAndroid() then
|
||||
self.memory_interval = G_reader_settings:readSetting("device_status_memory_interval", 5)
|
||||
self.memory_interval_m = G_reader_settings:readSetting("device_status_memory_interval_minutes", 5)
|
||||
self.memory_threshold = G_reader_settings:readSetting("device_status_memory_threshold", 100)
|
||||
self.checkHighMemoryUsage = function()
|
||||
local statm = io.open("/proc/self/statm", "r")
|
||||
@@ -103,7 +103,7 @@ function ReaderDeviceStatus:init()
|
||||
end
|
||||
end
|
||||
end
|
||||
UIManager:scheduleIn(self.memory_interval * 60, self.checkHighMemoryUsage)
|
||||
UIManager:scheduleIn(self.memory_interval_m * 60, self.checkHighMemoryUsage)
|
||||
end
|
||||
self:startMemoryChecker()
|
||||
end
|
||||
@@ -136,7 +136,7 @@ function ReaderDeviceStatus:addToMainMenu(menu_items)
|
||||
table.insert(menu_items.device_status_alarm.sub_item_table,
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Check interval: %1 min"), self.battery_interval)
|
||||
return T(_("Check interval: %1 min"), self.battery_interval_m)
|
||||
end,
|
||||
enabled_func = function()
|
||||
return G_reader_settings:isTrue("device_status_battery_alarm")
|
||||
@@ -144,18 +144,18 @@ function ReaderDeviceStatus:addToMainMenu(menu_items)
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
UIManager:show(SpinWidget:new{
|
||||
value = self.battery_interval,
|
||||
value = self.battery_interval_m,
|
||||
value_min = 1,
|
||||
value_max = 60,
|
||||
default_value = 10,
|
||||
value_hold_step = 5,
|
||||
title_text = _("Battery check interval"),
|
||||
callback = function(spin)
|
||||
self.battery_interval = spin.value
|
||||
G_reader_settings:saveSetting("device_status_battery_interval", self.battery_interval)
|
||||
self.battery_interval_m = spin.value
|
||||
G_reader_settings:saveSetting("device_status_battery_interval_minutes", self.battery_interval_m)
|
||||
touchmenu_instance:updateItems()
|
||||
powerd:setDismissBatteryStatus(false)
|
||||
UIManager:scheduleIn(self.battery_interval * 60, self.checkLowBatteryLevel)
|
||||
UIManager:scheduleIn(self.battery_interval_m * 60, self.checkLowBatteryLevel)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
@@ -228,7 +228,7 @@ High level threshold is checked when the device is charging.]]),
|
||||
table.insert(menu_items.device_status_alarm.sub_item_table,
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Check interval: %1 min"), self.memory_interval)
|
||||
return T(_("Check interval: %1 min"), self.memory_interval_m)
|
||||
end,
|
||||
enabled_func = function()
|
||||
return G_reader_settings:isTrue("device_status_memory_alarm")
|
||||
@@ -236,17 +236,17 @@ High level threshold is checked when the device is charging.]]),
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
UIManager:show(SpinWidget:new{
|
||||
value = self.memory_interval,
|
||||
value = self.memory_interval_m,
|
||||
value_min = 1,
|
||||
value_max = 60,
|
||||
default_value = 5,
|
||||
value_hold_step = 5,
|
||||
title_text = _("Memory check interval"),
|
||||
callback = function(spin)
|
||||
self.memory_interval = spin.value
|
||||
G_reader_settings:saveSetting("device_status_memory_interval", self.memory_interval)
|
||||
self.memory_interval_m = spin.value
|
||||
G_reader_settings:saveSetting("device_status_memory_interval_minutes", self.memory_interval_m)
|
||||
touchmenu_instance:updateItems()
|
||||
UIManager:scheduleIn(self.memory_interval * 60, self.checkHighMemoryUsage)
|
||||
UIManager:scheduleIn(self.memory_interval_m * 60, self.checkHighMemoryUsage)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
|
||||
@@ -13,11 +13,11 @@ local LuaData = require("luadata")
|
||||
local MultiConfirmBox = require("ui/widget/multiconfirmbox")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local SortWidget = require("ui/widget/sortwidget")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local Trapper = require("ui/trapper")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local T = ffiUtil.template
|
||||
@@ -111,7 +111,7 @@ function ReaderDictionary:init()
|
||||
-- Allow quick interruption or dismiss of search result window
|
||||
-- with tap if done before this delay. After this delay, the
|
||||
-- result window is shown and dismiss prevented for a few 100ms
|
||||
self.quick_dismiss_before_delay = TimeVal:new{ sec = 3, usec = 0 }
|
||||
self.quick_dismiss_before_delay = time.s(3)
|
||||
|
||||
-- Gather info about available dictionaries
|
||||
if not available_ifos then
|
||||
@@ -931,9 +931,10 @@ function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, boxes,
|
||||
|
||||
self:showLookupInfo(word, self.lookup_msg_delay)
|
||||
|
||||
self._lookup_start_tv = UIManager:getTime()
|
||||
self._lookup_start_time = UIManager:getTime()
|
||||
local results = self:startSdcv(word, dict_names, fuzzy_search)
|
||||
if results and results.lookup_cancelled and TimeVal:now() - self._lookup_start_tv <= self.quick_dismiss_before_delay then
|
||||
if results and results.lookup_cancelled
|
||||
and (time.now() - self._lookup_start_time) <= self.quick_dismiss_before_delay then
|
||||
-- If interrupted quickly just after launch, don't display anything
|
||||
-- (this might help avoiding refreshes and the need to dismiss
|
||||
-- after accidental long-press when holding a device).
|
||||
@@ -991,7 +992,8 @@ function ReaderDictionary:showDict(word, results, boxes, link)
|
||||
self:dismissLookupInfo()
|
||||
if results and results[1] then
|
||||
UIManager:show(self.dict_window)
|
||||
if not results.lookup_cancelled and self._lookup_start_tv and TimeVal:now() - self._lookup_start_tv > self.quick_dismiss_before_delay then
|
||||
if not results.lookup_cancelled and self._lookup_start_time
|
||||
and (time.now() - self._lookup_start_time) > self.quick_dismiss_before_delay then
|
||||
-- If the search took more than a few seconds to be done, discard
|
||||
-- queued and coming up events to avoid a voluntary dismissal
|
||||
-- (because the user felt the result would not come) to kill the
|
||||
|
||||
@@ -7,7 +7,6 @@ local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Notification = require("ui/widget/notification")
|
||||
local TextViewer = require("ui/widget/textviewer")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local Translator = require("ui/translator")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local dbg = require("dbg")
|
||||
@@ -15,6 +14,7 @@ local logger = require("logger")
|
||||
local util = require("util")
|
||||
local Size = require("ui/size")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local C_ = _.pgettext
|
||||
local T = require("ffi/util").template
|
||||
@@ -51,7 +51,7 @@ function ReaderHighlight:init()
|
||||
self._start_indicator_highlight = false
|
||||
self._current_indicator_pos = nil
|
||||
self._previous_indicator_pos = nil
|
||||
self._last_indicator_move_args = {dx = 0, dy = 0, distance = 0, time = TimeVal:now()}
|
||||
self._last_indicator_move_args = {dx = 0, dy = 0, distance = 0, time = time:now()}
|
||||
|
||||
if Device:hasDPad() then
|
||||
-- Used for text selection with dpad/keys
|
||||
@@ -897,9 +897,9 @@ dbg:guard(ReaderHighlight, "onShowHighlightMenu",
|
||||
|
||||
function ReaderHighlight:_resetHoldTimer(clear)
|
||||
if clear then
|
||||
self.hold_last_tv = nil
|
||||
self.hold_last_time = nil
|
||||
else
|
||||
self.hold_last_tv = UIManager:getTime()
|
||||
self.hold_last_time = UIManager:getTime()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1423,14 +1423,14 @@ function ReaderHighlight:onHoldRelease()
|
||||
end
|
||||
|
||||
local long_final_hold = false
|
||||
if self.hold_last_tv then
|
||||
local hold_duration = TimeVal:now() - self.hold_last_tv
|
||||
local long_hold_threshold = G_reader_settings:readSetting("highlight_long_hold_threshold", 3)
|
||||
if hold_duration > TimeVal:new{ sec = long_hold_threshold, usec = 0 } then
|
||||
if self.hold_last_time then
|
||||
local hold_duration = time.now() - self.hold_last_time
|
||||
local long_hold_threshold_s = G_reader_settings:readSetting("highlight_long_hold_threshold", 3) -- seconds
|
||||
if hold_duration > time.s(long_hold_threshold_s) then
|
||||
-- We stayed 3 seconds before release without updating selection
|
||||
long_final_hold = true
|
||||
end
|
||||
self.hold_last_tv = nil
|
||||
self.hold_last_time = nil
|
||||
end
|
||||
if self.is_word_selection then -- single-word selection
|
||||
if long_final_hold or G_reader_settings:isTrue("highlight_action_on_single_word") then
|
||||
@@ -1947,14 +1947,14 @@ function ReaderHighlight:onMoveHighlightIndicator(args)
|
||||
rect.x = rect.x + quick_move_distance_dx * dx
|
||||
rect.y = rect.y + quick_move_distance_dy * dy
|
||||
else
|
||||
local now = TimeVal:now()
|
||||
local now = time:now()
|
||||
if dx == self._last_indicator_move_args.dx and dy == self._last_indicator_move_args.dy then
|
||||
local diff = now - self._last_indicator_move_args.time
|
||||
-- if press same arrow key in 1 second, speed up
|
||||
-- double press: 4 single move distances, usually move to next word or line
|
||||
-- triple press: 16 single distances, usually skip several words or lines
|
||||
-- quadruple press: 54 single distances, almost move to screen edge
|
||||
if diff < TimeVal:new{ sec = 1, usec = 0 } then
|
||||
if diff < time.s(1) then
|
||||
move_distance = self._last_indicator_move_args.distance * 4
|
||||
end
|
||||
end
|
||||
@@ -1998,7 +1998,7 @@ function ReaderHighlight:_createHighlightGesture(gesture)
|
||||
return {
|
||||
ges = gesture,
|
||||
pos = point,
|
||||
time = TimeVal:realtime(),
|
||||
time = time.realtime(),
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -5,16 +5,15 @@ local Geom = require("ui/geometry")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Math = require("optmath")
|
||||
local ReaderZooming = require("apps/reader/modules/readerzooming")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local bit = require("bit")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local Input = Device.input
|
||||
local Screen = Device.screen
|
||||
|
||||
|
||||
local function copyPageState(page_state)
|
||||
return {
|
||||
page = page_state.page,
|
||||
@@ -98,7 +97,7 @@ function ReaderPaging:init()
|
||||
{"0"}, doc = "go to end", event = "GotoPercent", args = 100,
|
||||
}
|
||||
end
|
||||
self.pan_interval = TimeVal:new{ usec = 1000000 / self.pan_rate }
|
||||
self.pan_interval = time.s(1 / self.pan_rate)
|
||||
self.number_of_pages = self.ui.document.info.number_of_pages
|
||||
end
|
||||
|
||||
@@ -321,9 +320,9 @@ function ReaderPaging:bookmarkFlipping(flipping_page, flipping_ges)
|
||||
UIManager:setDirty(self.view.dialog, "partial")
|
||||
end
|
||||
|
||||
function ReaderPaging:onScrollSettingsUpdated(scroll_method, inertial_scroll_enabled, scroll_activation_delay)
|
||||
function ReaderPaging:onScrollSettingsUpdated(scroll_method, inertial_scroll_enabled, scroll_activation_delay_ms)
|
||||
self.scroll_method = scroll_method
|
||||
self.scroll_activation_delay = TimeVal:new{ usec = scroll_activation_delay * 1000 }
|
||||
self.scroll_activation_delay = time.ms(scroll_activation_delay_ms)
|
||||
if inertial_scroll_enabled then
|
||||
self.ui.scrolling:setInertialScrollCallbacks(
|
||||
function(distance) -- do_scroll_callback
|
||||
@@ -408,7 +407,7 @@ function ReaderPaging:onPan(_, ges)
|
||||
self._pan_has_scrolled = false
|
||||
self._pan_prev_relative_y = 0
|
||||
self._pan_to_scroll_later = 0
|
||||
self._pan_real_last_time = TimeVal.zero
|
||||
self._pan_real_last_time = 0
|
||||
if ges.mousewheel_direction then
|
||||
self._pan_activation_time = false
|
||||
else
|
||||
|
||||
@@ -7,10 +7,10 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local ProgressWidget = require("ui/widget/progresswidget")
|
||||
local ReaderPanning = require("apps/reader/modules/readerpanning")
|
||||
local Size = require("ui/size")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local bit = require("bit")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
@@ -112,7 +112,7 @@ function ReaderRolling:init()
|
||||
{"0"}, doc = "go to end", event = "GotoPercent", args = 100,
|
||||
}
|
||||
end
|
||||
self.pan_interval = TimeVal:new{ usec = 1000000 / self.pan_rate }
|
||||
self.pan_interval = time.s(1 / self.pan_rate)
|
||||
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.rendering_hash = self.ui.document:getDocumentRenderingHash()
|
||||
@@ -403,9 +403,9 @@ function ReaderRolling:getLastPercent()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderRolling:onScrollSettingsUpdated(scroll_method, inertial_scroll_enabled, scroll_activation_delay)
|
||||
function ReaderRolling:onScrollSettingsUpdated(scroll_method, inertial_scroll_enabled, scroll_activation_delay_ms)
|
||||
self.scroll_method = scroll_method
|
||||
self.scroll_activation_delay = TimeVal:new{ usec = scroll_activation_delay * 1000 }
|
||||
self.scroll_activation_delay = time.ms(scroll_activation_delay_ms)
|
||||
if inertial_scroll_enabled then
|
||||
self.ui.scrolling:setInertialScrollCallbacks(
|
||||
function(distance) -- do_scroll_callback
|
||||
@@ -478,7 +478,7 @@ function ReaderRolling:onPan(_, ges)
|
||||
self._pan_has_scrolled = false
|
||||
self._pan_prev_relative_y = 0
|
||||
self._pan_to_scroll_later = 0
|
||||
self._pan_real_last_time = TimeVal.zero
|
||||
self._pan_real_last_time = 0
|
||||
if ges.mousewheel_direction then
|
||||
self._pan_activation_time = false
|
||||
else
|
||||
@@ -1173,8 +1173,8 @@ function ReaderRolling:handleEngineCallback(ev, ...)
|
||||
-- ignore other events
|
||||
end
|
||||
|
||||
local ENGINE_PROGRESS_INITIAL_DELAY = TimeVal:new{ sec = 2, usec = 0 }
|
||||
local ENGINE_PROGRESS_UPDATE_DELAY = TimeVal:new{ sec = 0, usec = 500000 }
|
||||
local ENGINE_PROGRESS_INITIAL_DELAY = time.s(2)
|
||||
local ENGINE_PROGRESS_UPDATE_DELAY = time.ms(500)
|
||||
|
||||
function ReaderRolling:showEngineProgress(percent)
|
||||
if G_reader_settings and G_reader_settings:isFalse("cre_show_progress") then
|
||||
@@ -1186,7 +1186,7 @@ function ReaderRolling:showEngineProgress(percent)
|
||||
end
|
||||
|
||||
if percent then
|
||||
local now = TimeVal:now()
|
||||
local now = time.now()
|
||||
if self.engine_progress_update_not_before and now < self.engine_progress_update_not_before then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
local Screen = Device.screen
|
||||
@@ -22,7 +22,7 @@ local ReaderScrolling = InputContainer:new{
|
||||
SCROLL_METHOD_ON_RELEASE = SCROLL_METHOD_ON_RELEASE,
|
||||
|
||||
scroll_method = SCROLL_METHOD_CLASSIC,
|
||||
scroll_activation_delay = 0, -- 0 ms
|
||||
scroll_activation_delay_ms = 0, -- 0 ms
|
||||
inertial_scroll = false,
|
||||
|
||||
pan_rate = 30, -- default 30 ops, will be adjusted in readerui
|
||||
@@ -30,7 +30,7 @@ local ReaderScrolling = InputContainer:new{
|
||||
-- go at ending scrolling soon when we reach steps smaller than this
|
||||
end_scroll_dist = Screen:scaleBySize(10),
|
||||
-- no inertial scrolling if 300ms pause without any movement before release
|
||||
pause_before_release_cancel_duration = TimeVal:new{ sec = 0, usec = 300000 },
|
||||
pause_before_release_cancel_duration = time.ms(300),
|
||||
|
||||
-- Callbacks to be updated by readerrolling or readerpaging
|
||||
_do_scroll_callback = function(distance) return false end,
|
||||
@@ -66,14 +66,14 @@ function ReaderScrolling:init()
|
||||
-- we miss a first touch event.
|
||||
-- We can keep it obsolete, which will result in a long
|
||||
-- duration and a small/zero velocity that won't hurt.
|
||||
self._last_manual_scroll_timev = TimeVal.zero
|
||||
self._last_manual_scroll_timev = 0
|
||||
self:_setupAction()
|
||||
end
|
||||
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderScrolling:getDefaultScrollActivationDelay()
|
||||
function ReaderScrolling:getDefaultScrollActivationDelay_ms()
|
||||
if (self.ui.gestures and self.ui.gestures.multiswipes_enabled)
|
||||
or G_reader_settings:readSetting("activate_menu") ~= "tap" then
|
||||
-- If swipes to show menu or multiswipes are enabled, higher default
|
||||
@@ -143,11 +143,11 @@ This is interesting on eInk if you only pan to better adjust page vertical posit
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Activation delay: %1 ms"), self.scroll_activation_delay)
|
||||
return T(_("Activation delay: %1 ms"), self.scroll_activation_delay_ms)
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
local scroll_activation_delay_default = self:getDefaultScrollActivationDelay()
|
||||
local scroll_activation_delay_default_ms = self:getDefaultScrollActivationDelay_ms()
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local widget = SpinWidget:new{
|
||||
title_text = _("Scroll activation delay"),
|
||||
@@ -155,17 +155,17 @@ This is interesting on eInk if you only pan to better adjust page vertical posit
|
||||
A delay can be used to avoid scrolling when swipes or multiswipes are intended.
|
||||
|
||||
The delay value is in milliseconds and can range from 0 to 2000 (2 seconds).
|
||||
Default value: %1 ms]]), scroll_activation_delay_default),
|
||||
Default value: %1 ms]]), scroll_activation_delay_default_ms),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = self.scroll_activation_delay,
|
||||
value = self.scroll_activation_delay_ms,
|
||||
value_min = 0,
|
||||
value_max = 2000,
|
||||
value_step = 100,
|
||||
value_hold_step = 500,
|
||||
ok_text = _("Set delay"),
|
||||
default_value = scroll_activation_delay_default,
|
||||
default_value = scroll_activation_delay_default_ms,
|
||||
callback = function(spin)
|
||||
self.scroll_activation_delay = spin.value
|
||||
self.scroll_activation_delay_ms = spin.value
|
||||
self:applyScrollSettings()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end
|
||||
@@ -195,18 +195,18 @@ end
|
||||
|
||||
function ReaderScrolling:onReaderReady()
|
||||
-- We don't know if the gestures plugin is loaded in :init(), but we know it here
|
||||
self.scroll_activation_delay = G_reader_settings:readSetting("scroll_activation_delay")
|
||||
or self:getDefaultScrollActivationDelay()
|
||||
self.scroll_activation_delay_ms = G_reader_settings:readSetting("scroll_activation_delay")
|
||||
or self:getDefaultScrollActivationDelay_ms()
|
||||
self:applyScrollSettings()
|
||||
end
|
||||
|
||||
function ReaderScrolling:applyScrollSettings()
|
||||
G_reader_settings:saveSetting("scroll_method", self.scroll_method)
|
||||
G_reader_settings:saveSetting("inertial_scroll", self.inertial_scroll)
|
||||
if self.scroll_activation_delay == self:getDefaultScrollActivationDelay() then
|
||||
if self.scroll_activation_delay_ms == self:getDefaultScrollActivationDelay_ms() then
|
||||
G_reader_settings:delSetting("scroll_activation_delay")
|
||||
else
|
||||
G_reader_settings:saveSetting("scroll_activation_delay", self.scroll_activation_delay)
|
||||
G_reader_settings:saveSetting("scroll_activation_delay", self.scroll_activation_delay_ms)
|
||||
end
|
||||
if self.scroll_method == self.SCROLL_METHOD_CLASSIC then
|
||||
self._inertial_scroll_enabled = self.inertial_scroll
|
||||
@@ -215,7 +215,7 @@ function ReaderScrolling:applyScrollSettings()
|
||||
end
|
||||
self:setupTouchZones()
|
||||
self.ui:handleEvent(Event:new("ScrollSettingsUpdated", self.scroll_method,
|
||||
self._inertial_scroll_enabled, self.scroll_activation_delay))
|
||||
self._inertial_scroll_enabled, self.scroll_activation_delay_ms))
|
||||
end
|
||||
|
||||
function ReaderScrolling:setupTouchZones()
|
||||
@@ -339,14 +339,14 @@ function ReaderScrolling:_setupAction()
|
||||
self._last_manual_scroll_dy = 0
|
||||
return false
|
||||
end
|
||||
if self._last_manual_scroll_duration:isZero() or self._last_manual_scroll_dy == 0 then
|
||||
if self._last_manual_scroll_duration == 0 or self._last_manual_scroll_dy == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Initial velocity is the one of the last pan scroll given to accountManualScroll()
|
||||
local delay = self._last_manual_scroll_duration:tousecs()
|
||||
if delay < 1 then delay = 1 end -- safety check
|
||||
self._velocity = self._last_manual_scroll_dy * 1000000 / delay
|
||||
local delay_us = time.to_us(self._last_manual_scroll_duration)
|
||||
if delay_us < 1 then delay_us = 1 end -- safety check
|
||||
self._velocity = self._last_manual_scroll_dy * time.s(1 / delay_us)
|
||||
self._last_manual_scroll_dy = 0
|
||||
|
||||
self._inertial_scroll_action_scheduled = true
|
||||
|
||||
@@ -314,15 +314,15 @@ function ReaderThumbnail:startTileGeneration(request)
|
||||
local scale_factor = math.min(request.width / bb:getWidth(), request.height / bb:getHeight())
|
||||
local target_w = math.floor(bb:getWidth() * scale_factor)
|
||||
local target_h = math.floor(bb:getHeight() * scale_factor)
|
||||
-- local TimeVal = require("ui/timeval")
|
||||
-- local start_tv = TimeVal:now()
|
||||
-- local time = require("ui/time")
|
||||
-- local start_time = time.now()
|
||||
local tile = TileCacheItem:new{
|
||||
bb = RenderImage:scaleBlitBuffer(bb, target_w, target_h, true),
|
||||
pageno = request.page,
|
||||
}
|
||||
tile.size = tonumber(tile.bb.stride) * tile.bb.h
|
||||
-- logger.info("tile size", tile.bb.w, tile.bb.h, "=>", tile.size)
|
||||
-- logger.info(string.format(" scaling took %.3f seconds, %d bpp", TimeVal:getDuration(start_tv), tile.bb:getBpp()))
|
||||
-- logger.info(string.format(" scaling took %.3f seconds, %d bpp", time.to_s(time.since(start_time)), tile.bb:getBpp()))
|
||||
-- bb:free() -- no need to spend time freeing, we're dying soon anyway!
|
||||
|
||||
ffiutil.writeToFD(child_write_fd, self.codec.serialize(tile:totable()), true)
|
||||
@@ -343,8 +343,8 @@ function ReaderThumbnail:checkTileGeneration(request)
|
||||
local subprocess_done = ffiutil.isSubProcessDone(pid)
|
||||
logger.dbg("subprocess_done:", subprocess_done, " stuff_to_read:", stuff_to_read)
|
||||
if stuff_to_read then
|
||||
-- local TimeVal = require("ui/timeval")
|
||||
-- local start_tv = TimeVal:now()
|
||||
-- local time = require("ui/time")
|
||||
-- local start_time = time.now()
|
||||
local result, err = self.codec.deserialize(ffiutil.readAllFromFD(parent_read_fd))
|
||||
if result then
|
||||
local tile = TileCacheItem:new{}
|
||||
@@ -361,7 +361,7 @@ function ReaderThumbnail:checkTileGeneration(request)
|
||||
request.when_generated_callback(nil, request.batch_id, true)
|
||||
end
|
||||
end
|
||||
-- logger.info(string.format(" parsing result from subprocess took %.3f seconds", TimeVal:getDuration(start_tv)))
|
||||
-- logger.info(string.format(" parsing result from subprocess took %.3f seconds", time.to_s(time.since(start_time))))
|
||||
if not subprocess_done then
|
||||
table.insert(pids_to_collect, pid)
|
||||
return false, true
|
||||
|
||||
@@ -14,12 +14,12 @@ local OverlapGroup = require("ui/widget/overlapgroup")
|
||||
local ReaderDogear = require("apps/reader/modules/readerdogear")
|
||||
local ReaderFlipping = require("apps/reader/modules/readerflipping")
|
||||
local ReaderFooter = require("apps/reader/modules/readerfooter")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local dbg = require("dbg")
|
||||
local logger = require("logger")
|
||||
local optionsutil = require("ui/data/optionsutil")
|
||||
local Size = require("ui/size")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
@@ -76,7 +76,7 @@ local ReaderView = OverlapGroup:extend{
|
||||
-- in flipping state
|
||||
flipping_visible = false,
|
||||
-- to ensure periodic flush of settings
|
||||
settings_last_save_btv = nil,
|
||||
settings_last_save_time = nil,
|
||||
-- might be directly updated by readerpaging/readerrolling when
|
||||
-- they handle some panning/scrolling, to request "fast" refreshes
|
||||
currently_scrolling = false,
|
||||
@@ -1038,17 +1038,17 @@ end
|
||||
|
||||
function ReaderView:onReaderReady()
|
||||
self.ui.doc_settings:delSetting("docsettings_reset_done")
|
||||
self.settings_last_save_btv = UIManager:getElapsedTimeSinceBoot()
|
||||
self.settings_last_save_time = UIManager:getElapsedTimeSinceBoot()
|
||||
end
|
||||
|
||||
function ReaderView:onResume()
|
||||
-- As settings were saved on suspend, reset this on resume,
|
||||
-- as there's no need for a possibly immediate save.
|
||||
self.settings_last_save_btv = UIManager:getElapsedTimeSinceBoot()
|
||||
self.settings_last_save_time = UIManager:getElapsedTimeSinceBoot()
|
||||
end
|
||||
|
||||
function ReaderView:checkAutoSaveSettings()
|
||||
if not self.settings_last_save_btv then -- reader not yet ready
|
||||
if not self.settings_last_save_time then -- reader not yet ready
|
||||
return
|
||||
end
|
||||
if G_reader_settings:nilOrFalse("auto_save_settings_interval_minutes") then
|
||||
@@ -1056,11 +1056,11 @@ function ReaderView:checkAutoSaveSettings()
|
||||
return
|
||||
end
|
||||
|
||||
local interval = G_reader_settings:readSetting("auto_save_settings_interval_minutes")
|
||||
interval = TimeVal:new{ sec = interval*60, usec = 0 }
|
||||
local now_btv = UIManager:getElapsedTimeSinceBoot()
|
||||
if now_btv - self.settings_last_save_btv >= interval then
|
||||
self.settings_last_save_btv = now_btv
|
||||
local interval_m = G_reader_settings:readSetting("auto_save_settings_interval_minutes")
|
||||
local interval = time.s(interval_m * 60)
|
||||
local now = UIManager:getElapsedTimeSinceBoot()
|
||||
if now - self.settings_last_save_time >= interval then
|
||||
self.settings_last_save_time = now
|
||||
-- I/O, delay until after the pageturn
|
||||
UIManager:tickAfterNext(function()
|
||||
self.ui:saveSettings()
|
||||
|
||||
@@ -56,11 +56,11 @@ local ReaderWikipedia = require("apps/reader/modules/readerwikipedia")
|
||||
local ReaderZooming = require("apps/reader/modules/readerzooming")
|
||||
local Screenshoter = require("ui/widget/screenshoter")
|
||||
local SettingsMigration = require("ui/data/settings_migration")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local Screen = require("device").screen
|
||||
@@ -290,19 +290,19 @@ function ReaderUI:init()
|
||||
end
|
||||
-- make sure we render document first before calling any callback
|
||||
self:registerPostInitCallback(function()
|
||||
local start_tv = TimeVal:now()
|
||||
local start_time = time.now()
|
||||
if not self.document:loadDocument() then
|
||||
self:dealWithLoadDocumentFailure()
|
||||
end
|
||||
logger.dbg(string.format(" loading took %.3f seconds", TimeVal:getDuration(start_tv)))
|
||||
logger.dbg(string.format(" loading took %.3f seconds", time.to_s(time.since(start_time))))
|
||||
|
||||
-- used to read additional settings after the document has been
|
||||
-- loaded (but not rendered yet)
|
||||
self:handleEvent(Event:new("PreRenderDocument", self.doc_settings))
|
||||
|
||||
start_tv = TimeVal:now()
|
||||
start_time = time.now()
|
||||
self.document:render()
|
||||
logger.dbg(string.format(" rendering took %.3f seconds", TimeVal:getDuration(start_tv)))
|
||||
logger.dbg(string.format(" rendering took %.3f seconds", time.to_s(time.since(start_time))))
|
||||
|
||||
-- Uncomment to output the built DOM (for debugging)
|
||||
-- logger.dbg(self.document:getHTMLFromXPointer(".0", 0x6830))
|
||||
|
||||
@@ -6,7 +6,6 @@ This module defines stubs for common methods.
|
||||
|
||||
local DataStorage = require("datastorage")
|
||||
local Geom = require("ui/geometry")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
@@ -71,10 +70,10 @@ local Device = {
|
||||
canSuspend = yes,
|
||||
canStandby = no,
|
||||
canPowerSaveWhileCharging = no,
|
||||
total_standby_tv = TimeVal.zero, -- total time spent in standby
|
||||
last_standby_tv = TimeVal.zero,
|
||||
total_suspend_tv = TimeVal.zero, -- total time spent in suspend
|
||||
last_suspend_tv = TimeVal.zero,
|
||||
total_standby_time = 0, -- total time spent in standby
|
||||
last_standby_time = 0,
|
||||
total_suspend_time = 0, -- total time spent in suspend
|
||||
last_suspend_time = 0,
|
||||
canReboot = no,
|
||||
canPowerOff = no,
|
||||
canAssociateFileExtensions = no,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
local UIManager -- will be updated when available
|
||||
local Math = require("optmath")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local BasePowerD = {
|
||||
fl_min = 0, -- min frontlight intensity
|
||||
fl_max = 10, -- max frontlight intensity
|
||||
@@ -13,8 +13,8 @@ local BasePowerD = {
|
||||
aux_batt_capacity = 0, -- auxiliary battery capacity
|
||||
device = nil, -- device object
|
||||
|
||||
last_capacity_pull_time = TimeVal:new{ sec = -61, usec = 0}, -- timestamp of last pull
|
||||
last_aux_capacity_pull_time = TimeVal:new{ sec = -61, usec = 0}, -- timestamp of last pull
|
||||
last_capacity_pull_time = time.s(-61), -- timestamp of last pull
|
||||
last_aux_capacity_pull_time = time.s(-61), -- timestamp of last pull
|
||||
|
||||
is_fl_on = false, -- whether the frontlight is on
|
||||
}
|
||||
@@ -216,17 +216,17 @@ end
|
||||
function BasePowerD:getCapacity()
|
||||
-- BasePowerD is loaded before UIManager.
|
||||
-- Nothing *currently* calls this before UIManager is actually loaded, but future-proof this anyway.
|
||||
local now_btv
|
||||
local now
|
||||
if UIManager then
|
||||
now_btv = UIManager:getElapsedTimeSinceBoot()
|
||||
now = UIManager:getElapsedTimeSinceBoot()
|
||||
else
|
||||
-- Add time the device was in standby and suspend
|
||||
now_btv = TimeVal:now() + self.device.total_standby_tv + self.device.total_suspend_tv
|
||||
now = time.now() + self.device.total_standby_time + self.device.total_suspend_time
|
||||
end
|
||||
|
||||
if (now_btv - self.last_capacity_pull_time):tonumber() >= 60 then
|
||||
if now - self.last_capacity_pull_time >= time.s(60) then
|
||||
self.batt_capacity = self:getCapacityHW()
|
||||
self.last_capacity_pull_time = now_btv
|
||||
self.last_capacity_pull_time = now
|
||||
end
|
||||
return self.batt_capacity
|
||||
end
|
||||
@@ -240,29 +240,29 @@ function BasePowerD:isCharged()
|
||||
end
|
||||
|
||||
function BasePowerD:getAuxCapacity()
|
||||
local now_btv
|
||||
local now
|
||||
|
||||
if UIManager then
|
||||
now_btv = UIManager:getElapsedTimeSinceBoot()
|
||||
now = UIManager:getElapsedTimeSinceBoot()
|
||||
else
|
||||
-- Add time the device was in standby and suspend
|
||||
now_btv = TimeVal:now() + self.device.total_standby_tv + self.device.total_suspend_tv
|
||||
now = time.now() + self.device.total_standby_time + self.device.total_suspend_time
|
||||
end
|
||||
|
||||
if (now_btv - self.last_aux_capacity_pull_time):tonumber() >= 60 then
|
||||
if now - self.last_aux_capacity_pull_time >= time.s(60) then
|
||||
local aux_batt_capa = self:getAuxCapacityHW()
|
||||
-- If the read failed, don't update our cache, and retry next time.
|
||||
if aux_batt_capa then
|
||||
self.aux_batt_capacity = aux_batt_capa
|
||||
self.last_aux_capacity_pull_time = now_btv
|
||||
self.last_aux_capacity_pull_time = now
|
||||
end
|
||||
end
|
||||
return self.aux_batt_capacity
|
||||
end
|
||||
|
||||
function BasePowerD:invalidateCapacityCache()
|
||||
self.last_capacity_pull_time = TimeVal:new{ sec = -61, usec = 0}
|
||||
self.last_aux_capacity_pull_time = TimeVal:new{ sec = -61, usec = 0}
|
||||
self.last_capacity_pull_time = time.s(-61)
|
||||
self.last_aux_capacity_pull_time = self.last_capacity_pull_time
|
||||
end
|
||||
|
||||
function BasePowerD:isAuxCharging()
|
||||
|
||||
@@ -33,7 +33,7 @@ a touch event should have following format:
|
||||
id = 46,
|
||||
x = 0,
|
||||
y = 1,
|
||||
timev = TimeVal:new{...},
|
||||
timev = time.s(123.23),
|
||||
}
|
||||
|
||||
Don't confuse `tev` with raw evs from kernel, `tev` is built according to ev.
|
||||
@@ -43,8 +43,8 @@ detection result when you feed a touch release event to it.
|
||||
--]]
|
||||
|
||||
local Geom = require("ui/geometry")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
|
||||
-- We're going to need some clockid_t constants
|
||||
@@ -52,33 +52,22 @@ local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
require("ffi/posix_h")
|
||||
|
||||
-- default values (all the time parameters are in microseconds)
|
||||
local TAP_INTERVAL = 0 * 1000
|
||||
local DOUBLE_TAP_INTERVAL = 300 * 1000
|
||||
local TWO_FINGER_TAP_DURATION = 300 * 1000
|
||||
local HOLD_INTERVAL = 500 * 1000
|
||||
local SWIPE_INTERVAL = 900 * 1000
|
||||
-- current values
|
||||
local ges_tap_interval = G_reader_settings:readSetting("ges_tap_interval") or TAP_INTERVAL
|
||||
ges_tap_interval = TimeVal:new{ usec = ges_tap_interval }
|
||||
local ges_double_tap_interval = G_reader_settings:readSetting("ges_double_tap_interval") or DOUBLE_TAP_INTERVAL
|
||||
ges_double_tap_interval = TimeVal:new{ usec = ges_double_tap_interval }
|
||||
local ges_two_finger_tap_duration = G_reader_settings:readSetting("ges_two_finger_tap_duration") or TWO_FINGER_TAP_DURATION
|
||||
ges_two_finger_tap_duration = TimeVal:new{ usec = ges_two_finger_tap_duration }
|
||||
local ges_hold_interval = G_reader_settings:readSetting("ges_hold_interval") or HOLD_INTERVAL
|
||||
ges_hold_interval = TimeVal:new{ usec = ges_hold_interval }
|
||||
local ges_swipe_interval = G_reader_settings:readSetting("ges_swipe_interval") or SWIPE_INTERVAL
|
||||
ges_swipe_interval = TimeVal:new{ usec = ges_swipe_interval }
|
||||
-- default values (time parameters are in milliseconds (ms))
|
||||
local TAP_INTERVAL_MS = 0
|
||||
local DOUBLE_TAP_INTERVAL_MS = 300
|
||||
local TWO_FINGER_TAP_DURATION_MS = 300
|
||||
local HOLD_INTERVAL_MS = 500
|
||||
local SWIPE_INTERVAL_MS = 900
|
||||
|
||||
local GestureDetector = {
|
||||
-- must be initialized with the Input singleton class
|
||||
input = nil,
|
||||
-- default values (accessed for display by plugins/gestures.koplugin)
|
||||
TAP_INTERVAL = TAP_INTERVAL,
|
||||
DOUBLE_TAP_INTERVAL = DOUBLE_TAP_INTERVAL,
|
||||
TWO_FINGER_TAP_DURATION = TWO_FINGER_TAP_DURATION,
|
||||
HOLD_INTERVAL = HOLD_INTERVAL,
|
||||
SWIPE_INTERVAL = SWIPE_INTERVAL,
|
||||
TAP_INTERVAL_MS = TAP_INTERVAL_MS,
|
||||
DOUBLE_TAP_INTERVAL_MS = DOUBLE_TAP_INTERVAL_MS,
|
||||
TWO_FINGER_TAP_DURATION_MS = TWO_FINGER_TAP_DURATION_MS,
|
||||
HOLD_INTERVAL_MS = HOLD_INTERVAL_MS,
|
||||
SWIPE_INTERVAL_MS = SWIPE_INTERVAL_MS,
|
||||
-- pinch/spread direction table
|
||||
DIRECTION_TABLE = {
|
||||
east = "horizontal",
|
||||
@@ -106,6 +95,14 @@ local GestureDetector = {
|
||||
last_taps = {},
|
||||
-- for timestamp clocksource detection
|
||||
clock_id = nil,
|
||||
-- current values
|
||||
ges_tap_interval = time.ms(G_reader_settings:readSetting("ges_tap_interval_ms") or TAP_INTERVAL_MS),
|
||||
ges_double_tap_interval = time.ms(G_reader_settings:readSetting("ges_double_tap_interval_ms")
|
||||
or DOUBLE_TAP_INTERVAL_MS),
|
||||
ges_two_finger_tap_duration = time.ms(G_reader_settings:readSetting("ges_two_finger_tap_duration_ms")
|
||||
or TWO_FINGER_TAP_DURATION_MS),
|
||||
ges_hold_interval = time.ms(G_reader_settings:readSetting("ges_hold_interval_ms") or HOLD_INTERVAL_MS),
|
||||
ges_swipe_interval = time.ms(G_reader_settings:readSetting("ges_swipe_interval_ms") or SWIPE_INTERVAL_MS),
|
||||
}
|
||||
|
||||
function GestureDetector:new(o)
|
||||
@@ -167,38 +164,38 @@ tap2 is the later tap
|
||||
function GestureDetector:isTapBounce(tap1, tap2, interval)
|
||||
-- NOTE: If time went backwards, make the delta infinite to avoid misdetections,
|
||||
-- as we can no longer compute a sensible value...
|
||||
local tv_diff = tap2.timev - tap1.timev
|
||||
if not tv_diff:isPositive() then
|
||||
tv_diff = TimeVal.huge
|
||||
local time_diff = tap2.timev - tap1.timev
|
||||
if time_diff < 0 then
|
||||
time_diff = time.huge
|
||||
end
|
||||
return (
|
||||
math.abs(tap1.x - tap2.x) < self.SINGLE_TAP_BOUNCE_DISTANCE and
|
||||
math.abs(tap1.y - tap2.y) < self.SINGLE_TAP_BOUNCE_DISTANCE and
|
||||
tv_diff < interval
|
||||
time_diff < interval
|
||||
)
|
||||
end
|
||||
|
||||
function GestureDetector:isDoubleTap(tap1, tap2)
|
||||
local tv_diff = tap2.timev - tap1.timev
|
||||
if not tv_diff:isPositive() then
|
||||
tv_diff = TimeVal.huge
|
||||
local time_diff = tap2.timev - tap1.timev
|
||||
if time_diff < 0 then
|
||||
time_diff = time.huge
|
||||
end
|
||||
return (
|
||||
math.abs(tap1.x - tap2.x) < self.DOUBLE_TAP_DISTANCE and
|
||||
math.abs(tap1.y - tap2.y) < self.DOUBLE_TAP_DISTANCE and
|
||||
tv_diff < ges_double_tap_interval
|
||||
time_diff < self.ges_double_tap_interval
|
||||
)
|
||||
end
|
||||
|
||||
-- Takes TimeVals as input, not a tev
|
||||
function GestureDetector:isHold(t1, t2)
|
||||
local tv_diff = t2 - t1
|
||||
if not tv_diff:isPositive() then
|
||||
tv_diff = TimeVal.zero
|
||||
-- Takes times as input, not a tev
|
||||
function GestureDetector:isHold(time1, time2)
|
||||
local time_diff = time2 - time1
|
||||
if time_diff < 0 then
|
||||
time_diff = 0
|
||||
end
|
||||
-- NOTE: We cheat by not checking a distance because we're only checking that in tapState,
|
||||
-- which already ensures a stationary finger, by elimination ;).
|
||||
return tv_diff >= ges_hold_interval
|
||||
return time_diff >= self.ges_hold_interval
|
||||
end
|
||||
|
||||
function GestureDetector:isTwoFingerTap()
|
||||
@@ -212,21 +209,21 @@ function GestureDetector:isTwoFingerTap()
|
||||
local x_diff1 = math.abs(self.last_tevs[s2].x - self.first_tevs[s2].x)
|
||||
local y_diff0 = math.abs(self.last_tevs[s1].y - self.first_tevs[s1].y)
|
||||
local y_diff1 = math.abs(self.last_tevs[s2].y - self.first_tevs[s2].y)
|
||||
local tv_diff0 = self.last_tevs[s1].timev - self.first_tevs[s1].timev
|
||||
if not tv_diff0:isPositive() then
|
||||
tv_diff0 = TimeVal.huge
|
||||
local time_diff0 = self.last_tevs[s1].timev - self.first_tevs[s1].timev
|
||||
if time_diff0 < 0 then
|
||||
time_diff0 = time.huge
|
||||
end
|
||||
local tv_diff1 = self.last_tevs[s2].timev - self.first_tevs[s2].timev
|
||||
if not tv_diff1:isPositive() then
|
||||
tv_diff1 = TimeVal.huge
|
||||
local time_diff1 = self.last_tevs[s2].timev - self.first_tevs[s2].timev
|
||||
if time_diff1 < 0 then
|
||||
time_diff1 = time.huge
|
||||
end
|
||||
return (
|
||||
x_diff0 < self.TWO_FINGER_TAP_REGION and
|
||||
x_diff1 < self.TWO_FINGER_TAP_REGION and
|
||||
y_diff0 < self.TWO_FINGER_TAP_REGION and
|
||||
y_diff1 < self.TWO_FINGER_TAP_REGION and
|
||||
tv_diff0 < ges_two_finger_tap_duration and
|
||||
tv_diff1 < ges_two_finger_tap_duration
|
||||
time_diff0 < self.ges_two_finger_tap_duration and
|
||||
time_diff1 < self.ges_two_finger_tap_duration
|
||||
)
|
||||
end
|
||||
|
||||
@@ -264,11 +261,11 @@ end
|
||||
|
||||
function GestureDetector:isSwipe(slot)
|
||||
if not self.first_tevs[slot] or not self.last_tevs[slot] then return end
|
||||
local tv_diff = self.last_tevs[slot].timev - self.first_tevs[slot].timev
|
||||
if not tv_diff:isPositive() then
|
||||
tv_diff = TimeVal.huge
|
||||
local time_diff = self.last_tevs[slot].timev - self.first_tevs[slot].timev
|
||||
if time_diff < 0 then
|
||||
time_diff = time.huge
|
||||
end
|
||||
if tv_diff < ges_swipe_interval then
|
||||
if time_diff < self.ges_swipe_interval then
|
||||
local x_diff = self.last_tevs[slot].x - self.first_tevs[slot].x
|
||||
local y_diff = self.last_tevs[slot].y - self.first_tevs[slot].y
|
||||
if x_diff ~= 0 or y_diff ~= 0 then
|
||||
@@ -307,34 +304,6 @@ function GestureDetector:clearState(slot)
|
||||
self.input:clearTimeout(slot, "hold")
|
||||
end
|
||||
|
||||
function GestureDetector:setNewInterval(type, interval)
|
||||
if type == "ges_tap_interval" then
|
||||
ges_tap_interval = TimeVal:new{ usec = interval }
|
||||
elseif type == "ges_double_tap_interval" then
|
||||
ges_double_tap_interval = TimeVal:new{ usec = interval }
|
||||
elseif type == "ges_two_finger_tap_duration" then
|
||||
ges_two_finger_tap_duration = TimeVal:new{ usec = interval }
|
||||
elseif type == "ges_hold_interval" then
|
||||
ges_hold_interval = TimeVal:new{ usec = interval }
|
||||
elseif type == "ges_swipe_interval" then
|
||||
ges_swipe_interval = TimeVal:new{ usec = interval }
|
||||
end
|
||||
end
|
||||
|
||||
function GestureDetector:getInterval(type)
|
||||
if type == "ges_tap_interval" then
|
||||
return ges_tap_interval:tousecs()
|
||||
elseif type == "ges_double_tap_interval" then
|
||||
return ges_double_tap_interval:tousecs()
|
||||
elseif type == "ges_two_finger_tap_duration" then
|
||||
return ges_two_finger_tap_duration:tousecs()
|
||||
elseif type == "ges_hold_interval" then
|
||||
return ges_hold_interval:tousecs()
|
||||
elseif type == "ges_swipe_interval" then
|
||||
return ges_swipe_interval:tousecs()
|
||||
end
|
||||
end
|
||||
|
||||
function GestureDetector:clearStates()
|
||||
for k, _ in pairs(self.states) do
|
||||
self:clearState(k)
|
||||
@@ -371,10 +340,10 @@ Attempts to figure out which clock source tap events are using...
|
||||
function GestureDetector:probeClockSource(timev)
|
||||
-- We'll check if that timestamp is +/- 2.5s away from the three potential clock sources supported by evdev.
|
||||
-- We have bigger issues than this if we're parsing events more than 3s late ;).
|
||||
local threshold = TimeVal:new{ sec = 2, usec = 500000 }
|
||||
local threshold = time.s(2) + time.ms(500)
|
||||
|
||||
-- Start w/ REALTIME, because it's the easiest to detect ;).
|
||||
local realtime = TimeVal:realtime_coarse()
|
||||
local realtime = time.realtime_coarse()
|
||||
-- clock-threshold <= timev <= clock+threshold
|
||||
if timev >= realtime - threshold and timev <= realtime + threshold then
|
||||
self.clock_id = C.CLOCK_REALTIME
|
||||
@@ -383,7 +352,7 @@ function GestureDetector:probeClockSource(timev)
|
||||
end
|
||||
|
||||
-- Then MONOTONIC, as it's (hopefully) more common than BOOTTIME (and also guaranteed to be an usable clock source)
|
||||
local monotonic = TimeVal:monotonic_coarse()
|
||||
local monotonic = time.monotonic_coarse()
|
||||
if timev >= monotonic - threshold and timev <= monotonic + threshold then
|
||||
self.clock_id = C.CLOCK_MONOTONIC
|
||||
logger.info("GestureDetector:probeClockSource: Touch event timestamps appear to use CLOCK_MONOTONIC")
|
||||
@@ -391,9 +360,9 @@ function GestureDetector:probeClockSource(timev)
|
||||
end
|
||||
|
||||
-- Finally, BOOTTIME
|
||||
local boottime = TimeVal:boottime()
|
||||
local boottime = time.boottime()
|
||||
-- NOTE: It was implemented in Linux 2.6.39, so, reject 0, which would mean it's unsupported...
|
||||
if not boottime:isZero() and timev >= boottime - threshold and timev <= boottime + threshold then
|
||||
if not boottime == 0 and timev >= boottime - threshold and timev <= boottime + threshold then
|
||||
self.clock_id = C.CLOCK_BOOTTIME
|
||||
logger.info("GestureDetector:probeClockSource: Touch event timestamps appear to use CLOCK_BOOTTIME")
|
||||
return
|
||||
@@ -403,10 +372,10 @@ function GestureDetector:probeClockSource(timev)
|
||||
self.clock_id = -1
|
||||
logger.info("GestureDetector:probeClockSource: Touch event clock source detection was inconclusive")
|
||||
-- Print all all the gory details in debug mode when this happens...
|
||||
logger.dbg("Input frame :", timev:tonumber())
|
||||
logger.dbg("CLOCK_REALTIME :", realtime:tonumber())
|
||||
logger.dbg("CLOCK_MONOTONIC:", monotonic:tonumber())
|
||||
logger.dbg("CLOCK_BOOTTIME :", boottime:tonumber())
|
||||
logger.dbg("Input frame :", time.format_time(timev))
|
||||
logger.dbg("CLOCK_REALTIME :", time.format_time(realtime))
|
||||
logger.dbg("CLOCK_MONOTONIC:", time.format_time(monotonic))
|
||||
logger.dbg("CLOCK_BOOTTIME :", time.format_time(boottime))
|
||||
end
|
||||
|
||||
function GestureDetector:getClockSource()
|
||||
@@ -498,10 +467,10 @@ function GestureDetector:handleDoubleTap(tev)
|
||||
}
|
||||
|
||||
-- Tap interval / bounce detection may be tweaked by widget (i.e. VirtualKeyboard)
|
||||
local tap_interval = self.input.tap_interval_override or ges_tap_interval
|
||||
local tap_interval = self.input.tap_interval_override or self.ges_tap_interval
|
||||
-- We do tap bounce detection even when double tap is enabled (so, double tap
|
||||
-- is triggered when: ges_tap_interval <= delay < ges_double_tap_interval)
|
||||
if not tap_interval:isZero() and self.last_taps[slot] ~= nil and self:isTapBounce(self.last_taps[slot], cur_tap, tap_interval) then
|
||||
if tap_interval ~= 0 and self.last_taps[slot] ~= nil and self:isTapBounce(self.last_taps[slot], cur_tap, tap_interval) then
|
||||
logger.dbg("tap bounce detected in slot", slot, ": ignored")
|
||||
-- Simply ignore it, and clear state as this is the end of a touch event
|
||||
-- (this doesn't clear self.last_taps[slot], so a 3rd tap can be detected
|
||||
@@ -547,7 +516,7 @@ function GestureDetector:handleDoubleTap(tev)
|
||||
logger.dbg("single tap detected in slot", slot, ges_ev.pos)
|
||||
return ges_ev
|
||||
end
|
||||
end, tev.timev, ges_double_tap_interval)
|
||||
end, tev.timev, self.ges_double_tap_interval)
|
||||
-- we are already at the end of touch event
|
||||
-- so reset the state
|
||||
self:clearState(slot)
|
||||
@@ -573,7 +542,7 @@ function GestureDetector:handleNonTap(tev)
|
||||
self.pending_hold_timer[slot] = nil
|
||||
return self:switchState("holdState", tev, true)
|
||||
end
|
||||
end, tev.timev, ges_hold_interval)
|
||||
end, tev.timev, self.ges_hold_interval)
|
||||
return {
|
||||
ges = "touch",
|
||||
pos = Geom:new{
|
||||
|
||||
@@ -7,10 +7,10 @@ local DEBUG = require("dbg")
|
||||
local Event = require("ui/event")
|
||||
local GestureDetector = require("device/gesturedetector")
|
||||
local Key = require("device/key")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local framebuffer = require("ffi/framebuffer")
|
||||
local input = require("ffi/input")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
|
||||
-- We're going to need a few <linux/input.h> constants...
|
||||
@@ -372,7 +372,7 @@ function Input:setTimeout(slot, ges, cb, origin, delay)
|
||||
if input.setTimer then
|
||||
-- If GestureDetector's clock source probing was inconclusive, do this on the UI timescale instead.
|
||||
if clock_id == -1 then
|
||||
deadline = TimeVal:now() + delay
|
||||
deadline = time.now() + delay
|
||||
clock_id = C.CLOCK_MONOTONIC
|
||||
else
|
||||
deadline = origin + delay
|
||||
@@ -380,7 +380,8 @@ function Input:setTimeout(slot, ges, cb, origin, delay)
|
||||
-- What this does is essentially to ask the kernel to wake us up when the timer expires,
|
||||
-- instead of ensuring that ourselves via a polling timeout.
|
||||
-- This ensures perfect accuracy, and allows it to be computed in the event's own timescale.
|
||||
timerfd = input.setTimer(clock_id, deadline.sec, deadline.usec)
|
||||
local sec, usec = time.split_s_us(deadline)
|
||||
timerfd = input.setTimer(clock_id, sec, usec)
|
||||
end
|
||||
if timerfd then
|
||||
-- It worked, tweak the table a bit to make it clear the deadline will be handled by the kernel
|
||||
@@ -395,7 +396,7 @@ function Input:setTimeout(slot, ges, cb, origin, delay)
|
||||
else
|
||||
-- Otherwise, fudge it by using a current timestamp in the UI's timescale (MONOTONIC).
|
||||
-- This isn't the end of the world in practice (c.f., #7415).
|
||||
deadline = TimeVal:now() + delay
|
||||
deadline = time.now() + delay
|
||||
end
|
||||
item.deadline = deadline
|
||||
end
|
||||
@@ -709,10 +710,8 @@ function Input:handleTouchEv(ev)
|
||||
end
|
||||
elseif ev.type == C.EV_SYN then
|
||||
if ev.code == C.SYN_REPORT then
|
||||
-- Promote our event's time table to a real TimeVal
|
||||
setmetatable(ev.time, TimeVal)
|
||||
for _, MTSlot in ipairs(self.MTSlots) do
|
||||
self:setMtSlot(MTSlot.slot, "timev", ev.time)
|
||||
self:setMtSlot(MTSlot.slot, "timev", time.timeval(ev.time))
|
||||
end
|
||||
-- feed ev in all slots to state machine
|
||||
local touch_ges = self.gesture_detector:feedEvent(self.MTSlots)
|
||||
@@ -773,9 +772,8 @@ function Input:handleTouchEvPhoenix(ev)
|
||||
end
|
||||
elseif ev.type == C.EV_SYN then
|
||||
if ev.code == C.SYN_REPORT then
|
||||
setmetatable(ev.time, TimeVal)
|
||||
for _, MTSlot in ipairs(self.MTSlots) do
|
||||
self:setMtSlot(MTSlot.slot, "timev", ev.time)
|
||||
self:setMtSlot(MTSlot.slot, "timev", time.timeval(ev.time))
|
||||
end
|
||||
-- feed ev in all slots to state machine
|
||||
local touch_ges = self.gesture_detector:feedEvent(self.MTSlots)
|
||||
@@ -809,9 +807,8 @@ function Input:handleTouchEvLegacy(ev)
|
||||
end
|
||||
elseif ev.type == C.EV_SYN then
|
||||
if ev.code == C.SYN_REPORT then
|
||||
setmetatable(ev.time, TimeVal)
|
||||
for _, MTSlot in ipairs(self.MTSlots) do
|
||||
self:setMtSlot(MTSlot.slot, "timev", ev.time)
|
||||
self:setMtSlot(MTSlot.slot, "timev", time.timeval(ev.time))
|
||||
end
|
||||
|
||||
-- feed ev in all slots to state machine
|
||||
@@ -1022,8 +1019,8 @@ end
|
||||
|
||||
|
||||
--- Main event handling.
|
||||
-- `now` corresponds to UIManager:getTime() (a TimeVal), and it's just been updated by UIManager.
|
||||
-- `deadline` (a TimeVal) is the absolute deadline imposed by UIManager:handleInput() (a.k.a., our main event loop ^^):
|
||||
-- `now` corresponds to UIManager:getTime() (an fts time), and it's just been updated by UIManager.
|
||||
-- `deadline` (an fts time) is the absolute deadline imposed by UIManager:handleInput() (a.k.a., our main event loop ^^):
|
||||
-- it's either nil (meaning block forever waiting for input), or the earliest UIManager deadline (in most cases, that's the next scheduled task,
|
||||
-- in much less common cases, that's the earliest of UIManager.INPUT_TIMEOUT (currently, only KOSync ever sets it) or UIManager.ZMQ_TIMEOUT if there are pending ZMQs).
|
||||
function Input:waitEvent(now, deadline)
|
||||
@@ -1073,18 +1070,19 @@ function Input:waitEvent(now, deadline)
|
||||
if poll_deadline then
|
||||
-- If we haven't hit that deadline yet, poll until it expires, otherwise,
|
||||
-- have select return immediately so that we trip a timeout.
|
||||
now = now or TimeVal:now()
|
||||
now = now or time.now()
|
||||
if poll_deadline > now then
|
||||
-- Deadline hasn't been blown yet, honor it.
|
||||
poll_timeout = poll_deadline - now
|
||||
else
|
||||
-- We've already blown the deadline: make select return immediately (most likely straight to timeout)
|
||||
poll_timeout = TimeVal.zero
|
||||
poll_timeout = 0
|
||||
end
|
||||
end
|
||||
|
||||
local timerfd
|
||||
ok, ev, timerfd = input.waitForEvent(poll_timeout and poll_timeout.sec, poll_timeout and poll_timeout.usec)
|
||||
local sec, usec = time.split_s_us(poll_timeout)
|
||||
ok, ev, timerfd = input.waitForEvent(sec, usec)
|
||||
-- We got an actual input event, go and process it
|
||||
if ok then break end
|
||||
|
||||
@@ -1102,7 +1100,7 @@ function Input:waitEvent(now, deadline)
|
||||
-- We're only guaranteed to have blown the timer's deadline
|
||||
-- when our actual select deadline *was* the timer's!
|
||||
consume_callback = true
|
||||
elseif TimeVal:now() >= self.timer_callbacks[1].deadline then
|
||||
elseif time.now() >= self.timer_callbacks[1].deadline then
|
||||
-- But if it was a task deadline instead, we to have to check the timer's against the current time,
|
||||
-- to double-check whether we blew it or not.
|
||||
consume_callback = true
|
||||
@@ -1144,17 +1142,18 @@ function Input:waitEvent(now, deadline)
|
||||
-- If UIManager put us on deadline, enforce it, otherwise, block forever.
|
||||
if deadline then
|
||||
-- Convert that absolute deadline to value relative to *now*, as we may loop multiple times between UI ticks.
|
||||
now = now or TimeVal:now()
|
||||
now = now or time.now()
|
||||
if deadline > now then
|
||||
-- Deadline hasn't been blown yet, honor it.
|
||||
poll_timeout = deadline - now
|
||||
else
|
||||
-- Deadline has been blown: make select return immediately.
|
||||
poll_timeout = TimeVal.zero
|
||||
poll_timeout = 0
|
||||
end
|
||||
end
|
||||
|
||||
ok, ev = input.waitForEvent(poll_timeout and poll_timeout.sec, poll_timeout and poll_timeout.usec)
|
||||
local sec, usec = time.split_s_us(poll_timeout)
|
||||
ok, ev = input.waitForEvent(sec, usec)
|
||||
end -- if #timer_callbacks > 0
|
||||
|
||||
-- Handle errors
|
||||
|
||||
@@ -824,14 +824,14 @@ function Kobo:standby(max_duration)
|
||||
self.wakeup_mgr:addTask(max_duration, standby_alarm)
|
||||
end
|
||||
|
||||
local TimeVal = require("ui/timeval")
|
||||
local time = require("ui/time")
|
||||
logger.info("Kobo standby: asking to enter standby . . .")
|
||||
local standby_time_tv = TimeVal:boottime_or_realtime_coarse()
|
||||
local standby_time = time.boottime_or_realtime_coarse()
|
||||
|
||||
local ret = writeToSys("standby", "/sys/power/state")
|
||||
|
||||
self.last_standby_tv = TimeVal:boottime_or_realtime_coarse() - standby_time_tv
|
||||
self.total_standby_tv = self.total_standby_tv + self.last_standby_tv
|
||||
self.last_standby_time = time.boottime_or_realtime_coarse() - standby_time
|
||||
self.total_standby_time = self.total_standby_time + self.last_standby_time
|
||||
|
||||
if ret then
|
||||
logger.info("Kobo standby: zZz zZz zZz zZz... And woke up!")
|
||||
@@ -925,16 +925,16 @@ function Kobo:suspend()
|
||||
end
|
||||
--]]
|
||||
|
||||
local TimeVal = require("ui/timeval")
|
||||
local time = require("ui/time")
|
||||
logger.info("Kobo suspend: asking for a suspend to RAM . . .")
|
||||
local suspend_time_tv = TimeVal:boottime_or_realtime_coarse()
|
||||
local suspend_time = time.boottime_or_realtime_coarse()
|
||||
|
||||
ret = writeToSys("mem", "/sys/power/state")
|
||||
|
||||
-- NOTE: At this point, we *should* be in suspend to RAM, as such,
|
||||
-- execution should only resume on wakeup...
|
||||
self.last_suspend_tv = TimeVal:boottime_or_realtime_coarse() - suspend_time_tv
|
||||
self.total_suspend_tv = self.total_suspend_tv + self.last_suspend_tv
|
||||
self.last_suspend_time = time.boottime_or_realtime_coarse() - suspend_time
|
||||
self.total_suspend_time = self.total_suspend_time + self.last_suspend_time
|
||||
|
||||
if ret then
|
||||
logger.info("Kobo suspend: ZzZ ZzZ ZzZ... And woke up!")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
local Generic = require("device/generic/device") -- <= look at this file!
|
||||
local TimeVal = require("ui/timeval")
|
||||
local PluginShare = require("pluginshare")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
require("ffi/linux_input_h")
|
||||
@@ -95,7 +95,7 @@ function Remarkable2:adjustTouchEvent(ev, by)
|
||||
-- Inject CLOCK_MONOTONIC timestamps at the end of every input frame in order to have consistent gesture detection across input devices.
|
||||
-- c.f., #7536
|
||||
if ev.type == C.EV_SYN and ev.code == C.SYN_REPORT then
|
||||
ev.time = TimeVal:now()
|
||||
ev.time = time.now()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -168,7 +168,6 @@ function Device:init()
|
||||
event_map = require("device/sdl/event_map_sdl2"),
|
||||
handleSdlEv = function(device_input, ev)
|
||||
local Geom = require("ui/geometry")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
|
||||
-- SDL events can remain cdata but are almost completely transparent
|
||||
@@ -192,8 +191,6 @@ function Device:init()
|
||||
w = 0, h = 0,
|
||||
}
|
||||
|
||||
setmetatable(ev.time, TimeVal)
|
||||
|
||||
local fake_ges = {
|
||||
ges = "pan",
|
||||
distance = 200,
|
||||
|
||||
@@ -6,13 +6,13 @@ local FontList = require("fontlist")
|
||||
local Geom = require("ui/geometry")
|
||||
local RenderImage = require("ui/renderimage")
|
||||
local Screen = require("device").screen
|
||||
local TimeVal = require("ui/timeval")
|
||||
local buffer = require("string.buffer")
|
||||
local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local lru = require("ffi/lru")
|
||||
local time = require("ui/time")
|
||||
|
||||
-- engine can be initialized only once, on first document opened
|
||||
local engine_initialized = false
|
||||
@@ -694,16 +694,16 @@ function CreDocument:drawCurrentView(target, x, y, rect, pos)
|
||||
-- We also honor the current smooth scaling setting,
|
||||
-- as well as the global SW dithering setting.
|
||||
|
||||
--local start_tv = TimeVal:now()
|
||||
--local start_time = time.now()
|
||||
self._drawn_images_count, self._drawn_images_surface_ratio =
|
||||
self._document:drawCurrentPage(self.buffer, self.render_color, Screen.night_mode and self._nightmode_images, self._smooth_scaling, Screen.sw_dithering)
|
||||
--local end_tv = TimeVal:now()
|
||||
--print(string.format("CreDocument:drawCurrentView: Rendering took %9.3f ms", (end_tv - start_tv):tomsecs()))
|
||||
--local end_time = time.now()
|
||||
--print(string.format("CreDocument:drawCurrentView: Rendering took %9.3f ms", time.to_ms(end_time - start_time))
|
||||
|
||||
--start_tv = TimeVal:now()
|
||||
--start = time.now()
|
||||
target:blitFrom(self.buffer, x, y, 0, 0, rect.w, rect.h)
|
||||
--end_tv = TimeVal:now()
|
||||
--print(string.format("CreDocument:drawCurrentView: Blitting took %9.3f ms", (end_tv - start_tv):tomsecs()))
|
||||
--end_time = time.now()
|
||||
--print(string.format("CreDocument:drawCurrentView: Blitting took %9.3f ms", time.to_ms(end_time - start_time))
|
||||
end
|
||||
|
||||
function CreDocument:drawCurrentViewByPos(target, x, y, rect, pos)
|
||||
@@ -1457,10 +1457,10 @@ function CreDocument:setupCallCache()
|
||||
-- cache statistics
|
||||
self._call_cache_stats = {}
|
||||
now = function()
|
||||
return TimeVal:now()
|
||||
return time.now()
|
||||
end
|
||||
addStatMiss = function(name, starttime, not_cached)
|
||||
local duration = TimeVal:getDuration(starttime)
|
||||
local duration = time.since(starttime)
|
||||
if not self._call_cache_stats[name] then
|
||||
self._call_cache_stats[name] = {0, 0.0, 1, duration, not_cached}
|
||||
else
|
||||
@@ -1470,7 +1470,7 @@ function CreDocument:setupCallCache()
|
||||
end
|
||||
end
|
||||
addStatHit = function(name, starttime)
|
||||
local duration = TimeVal:getDuration(starttime)
|
||||
local duration = time.since(starttime)
|
||||
if not self._call_cache_stats[name] then
|
||||
self._call_cache_stats[name] = {1, duration, 0, 0.0}
|
||||
else
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
-- able to get there easily.
|
||||
--------
|
||||
|
||||
local TimeVal = require("ui/timeval")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local N_ = _.ngettext
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local K = require("frontend/ui/data/keyboardlayouts/ja_keyboard_keys")
|
||||
|
||||
local DEFAULT_KEITAI_TAP_INTERVAL = 2
|
||||
local DEFAULT_KEITAI_TAP_INTERVAL_S = 2
|
||||
|
||||
-- "Keitai input" is an input mode similar to T9 mobile input, where you tap a
|
||||
-- key to cycle through several candidate characters. The tap interval is how
|
||||
@@ -28,16 +28,16 @@ local DEFAULT_KEITAI_TAP_INTERVAL = 2
|
||||
-- information.
|
||||
|
||||
local function getKeitaiTapInterval()
|
||||
return G_reader_settings:readSetting("keyboard_japanese_keitai_tap_interval") or DEFAULT_KEITAI_TAP_INTERVAL
|
||||
return time.s(G_reader_settings:readSetting("keyboard_japanese_keitai_tap_interval", DEFAULT_KEITAI_TAP_INTERVAL_S))
|
||||
end
|
||||
|
||||
local function setKeitaiTapInterval(interval)
|
||||
G_reader_settings:saveSetting("keyboard_japanese_keitai_tap_interval", interval)
|
||||
G_reader_settings:saveSetting("keyboard_japanese_keitai_tap_interval", time.to_s(interval))
|
||||
end
|
||||
|
||||
local function exitKeitaiMode(inputbox)
|
||||
logger.dbg("ja_kbd: clearing keitai window last tap tv")
|
||||
inputbox._ja_last_tap_tv = nil
|
||||
inputbox._ja_last_tap_time = nil
|
||||
end
|
||||
|
||||
local function wrappedAddChars(inputbox, char)
|
||||
@@ -48,10 +48,10 @@ local function wrappedAddChars(inputbox, char)
|
||||
-- For keitai buttons, are we still in the tap interval?
|
||||
local within_tap_window
|
||||
if keitai_cycle then
|
||||
if inputbox._ja_last_tap_tv then
|
||||
within_tap_window = TimeVal:getDuration(inputbox._ja_last_tap_tv) < getKeitaiTapInterval()
|
||||
if inputbox._ja_last_tap_time then
|
||||
within_tap_window = time.since(inputbox._ja_last_tap_time) < getKeitaiTapInterval()
|
||||
end
|
||||
inputbox._ja_last_tap_tv = TimeVal:now()
|
||||
inputbox._ja_last_tap_time = time.now()
|
||||
else
|
||||
-- This is a non-keitai or non-tap key, so break out of keitai window.
|
||||
exitKeitaiMode(inputbox)
|
||||
@@ -113,7 +113,7 @@ local function wrapInputBox(inputbox)
|
||||
for _, wrapper in ipairs(wrappers) do
|
||||
wrapper:revert()
|
||||
end
|
||||
inputbox._ja_last_tap_tv = nil
|
||||
inputbox._ja_last_tap_time = nil
|
||||
inputbox._ja_wrapped = nil
|
||||
end
|
||||
end
|
||||
@@ -127,7 +127,7 @@ local function genMenuItems(self)
|
||||
local interval = getKeitaiTapInterval()
|
||||
if interval ~= 0 then
|
||||
-- @translators Keitai input is a kind of Japanese keyboard input mode (similar to T9 keypad input). See <https://en.wikipedia.org/wiki/Japanese_input_method#Mobile_phones> for more information.
|
||||
return T(N_("Keitai tap interval: %1 second", "Keitai tap interval: %1 seconds", interval), interval)
|
||||
return T(N_("Keitai tap interval: %1 second", "Keitai tap interval: %1 seconds", time.to_s(interval)), time.to_s(interval))
|
||||
else
|
||||
-- @translators Flick and keitai are kinds of Japanese keyboard input modes. See <https://en.wikipedia.org/wiki/Japanese_input_method#Mobile_phones> for more information.
|
||||
return _("Keitai input: disabled (flick-only input)")
|
||||
@@ -146,14 +146,14 @@ How long to wait (in seconds) for the next tap when in keitai input mode before
|
||||
|
||||
If set to 0, keitai input is disabled entirely and only flick input can be used.]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = getKeitaiTapInterval(),
|
||||
value = time.to_s(getKeitaiTapInterval()),
|
||||
value_min = 0,
|
||||
value_max = 10,
|
||||
value_step = 1,
|
||||
ok_text = _("Set interval"),
|
||||
default_value = DEFAULT_KEITAI_TAP_INTERVAL,
|
||||
default_value = DEFAULT_KEITAI_TAP_INTERVAL_S,
|
||||
callback = function(spin)
|
||||
setKeitaiTapInterval(spin.value)
|
||||
setKeitaiTapInterval(time.s(spin.value))
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
|
||||
-- Date at which the last migration snippet was added
|
||||
local CURRENT_MIGRATION_DATE = 20220205
|
||||
local CURRENT_MIGRATION_DATE = 20220426
|
||||
|
||||
-- Retrieve the date of the previous migration, if any
|
||||
local last_migration_date = G_reader_settings:readSetting("last_migration_date", 0)
|
||||
@@ -366,5 +366,27 @@ if last_migration_date < 20220205 then
|
||||
end
|
||||
end
|
||||
|
||||
-- Rename several time storing settings and shift their value to the new meaning
|
||||
if last_migration_date < 20220426 then
|
||||
local function migrateSettingsName(old, new, factor)
|
||||
factor = factor or 1
|
||||
if G_reader_settings:readSetting(old) then
|
||||
local value = math.floor(G_reader_settings:readSetting(old) * factor)
|
||||
G_reader_settings:saveSetting(new, value)
|
||||
G_reader_settings:delSetting(old)
|
||||
end
|
||||
end
|
||||
migrateSettingsName("ges_tap_interval", "ges_tap_interval_ms", 1e-3)
|
||||
migrateSettingsName("ges_double_tap_interval", "ges_double_tap_interval_ms", 1e-3)
|
||||
migrateSettingsName("ges_two_finger_tap_duration", "ges_two_finger_tap_duration_ms", 1e-3)
|
||||
migrateSettingsName("ges_hold_interval", "ges_hold_interval_ms", 1e-3)
|
||||
migrateSettingsName("ges_swipe_interval", "ges_swipe_interval_ms", 1e-3)
|
||||
migrateSettingsName("ges_tap_interval_on_keyboard", "ges_tap_interval_on_keyboard_ms", 1e-3)
|
||||
|
||||
migrateSettingsName("device_status_battery_interval", "device_status_battery_interval_minutes")
|
||||
migrateSettingsName("device_status_memory_interval", "device_status_memory_interval_minutes")
|
||||
end
|
||||
|
||||
|
||||
-- We're done, store the current migration date
|
||||
G_reader_settings:saveSetting("last_migration_date", CURRENT_MIGRATION_DATE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
local TimeVal = require("ui/timeval")
|
||||
local time = require("ui/time")
|
||||
|
||||
local GestureRange = {
|
||||
-- gesture matching type
|
||||
@@ -43,8 +43,8 @@ function GestureRange:match(gs)
|
||||
-- This field sets up rate-limiting (in matches per second).
|
||||
-- It's mostly useful for e-Ink devices with less powerful CPUs
|
||||
-- and screens that cannot handle the amount of gesture events that would otherwise be generated.
|
||||
local last_time = self.last_time or TimeVal.zero
|
||||
if gs.time - last_time > TimeVal:new{ usec = 1000000 / self.rate } then
|
||||
local last_time = self.last_time or 0
|
||||
if gs.time - last_time > time.s(1 / self.rate) then
|
||||
self.last_time = gs.time
|
||||
else
|
||||
return false
|
||||
|
||||
@@ -123,8 +123,8 @@ function NetworkListener:_unscheduleActivityCheck()
|
||||
if self._last_tx_packets then
|
||||
self._last_tx_packets = nil
|
||||
end
|
||||
if self._activity_check_delay then
|
||||
self._activity_check_delay = nil
|
||||
if self._activity_check_delay_seconds then
|
||||
self._activity_check_delay_seconds = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -135,8 +135,8 @@ function NetworkListener:_scheduleActivityCheck()
|
||||
local tx_packets = NetworkListener:_getTxPackets()
|
||||
if self._last_tx_packets and tx_packets then
|
||||
-- Compute noise threshold based on the current delay
|
||||
local delay = self._activity_check_delay or default_network_timeout_seconds
|
||||
local noise_threshold = delay / default_network_timeout_seconds * network_activity_noise_margin
|
||||
local delay_seconds = self._activity_check_delay_seconds or default_network_timeout_seconds
|
||||
local noise_threshold = delay_seconds / default_network_timeout_seconds * network_activity_noise_margin
|
||||
local delta = tx_packets - self._last_tx_packets
|
||||
-- If there was no meaningful activity (+/- a couple packets), kill the Wi-Fi
|
||||
if delta <= noise_threshold then
|
||||
@@ -161,19 +161,19 @@ function NetworkListener:_scheduleActivityCheck()
|
||||
self._last_tx_packets = tx_packets
|
||||
|
||||
-- If it's already been scheduled, increase the delay until we hit the ceiling
|
||||
if self._activity_check_delay then
|
||||
self._activity_check_delay = self._activity_check_delay + default_network_timeout_seconds
|
||||
if self._activity_check_delay_seconds then
|
||||
self._activity_check_delay_seconds = self._activity_check_delay_seconds + default_network_timeout_seconds
|
||||
|
||||
if self._activity_check_delay > max_network_timeout_seconds then
|
||||
self._activity_check_delay = max_network_timeout_seconds
|
||||
if self._activity_check_delay_seconds > max_network_timeout_seconds then
|
||||
self._activity_check_delay_seconds = max_network_timeout_seconds
|
||||
end
|
||||
else
|
||||
self._activity_check_delay = default_network_timeout_seconds
|
||||
self._activity_check_delay_seconds = default_network_timeout_seconds
|
||||
end
|
||||
|
||||
UIManager:scheduleIn(self._activity_check_delay, self._scheduleActivityCheck, self)
|
||||
UIManager:scheduleIn(self._activity_check_delay_seconds, self._scheduleActivityCheck, self)
|
||||
self._activity_check_scheduled = true
|
||||
logger.dbg("NetworkListener: network activity check scheduled in", self._activity_check_delay, "seconds")
|
||||
logger.dbg("NetworkListener: network activity check scheduled in", self._activity_check_delay_seconds, "seconds")
|
||||
end
|
||||
|
||||
function NetworkListener:onNetworkConnected()
|
||||
@@ -211,5 +211,4 @@ function NetworkListener:onSuspend()
|
||||
self:onNetworkDisconnected()
|
||||
end
|
||||
|
||||
|
||||
return NetworkListener
|
||||
|
||||
307
frontend/ui/time.lua
Normal file
307
frontend/ui/time.lua
Normal file
@@ -0,0 +1,307 @@
|
||||
--[[--
|
||||
A runtime optimized module to compare and do simple arithmetics with fixed point time values (which are called fts in here).
|
||||
|
||||
Also implements functions to retrieve time from various system clocks (monotonic, monotonic_coarse, realtime, realtime_coarse, boottime ...).
|
||||
|
||||
**Encode:**
|
||||
|
||||
Don't store a numerical constant in an fts encoded time. Use the functions provided here!
|
||||
|
||||
To convert real world units to an fts, you can use the following functions: time.s(seconds), time.ms(milliseconds), time.us(microseconds).
|
||||
|
||||
You can calculate an fts encoded time of 3 s with `time.s(3)`.
|
||||
|
||||
Special values: `0` can be used for a zero time and `time.huge` can be used for the longest possible time.
|
||||
|
||||
Beware of float encoding precision, though. For instance, take 2.1s: 2.1 cannot be encoded with full precision, so time.s(2.1) would be slightly inaccurate.
|
||||
(For small values (under 10 secs) the error will be ±1µs, for values below a minute the error will be below ±2µs, for values below an hour the error will be ±100µs.)
|
||||
|
||||
When full precision is necessary, use `time.s(2) + time.ms(100)` or `time.s(2) + time.us(100000)` instead.
|
||||
|
||||
(For more information about floating-point-representation see: https://stackoverflow.com/questions/3448777/how-to-represent-0-1-in-floating-point-arithmetic-and-decimal)
|
||||
|
||||
**Decode:**
|
||||
|
||||
You can get the number of seconds in an fts encoded time with `time.to_s(time_fts)`.
|
||||
|
||||
You can get the number of milliseconds in an fts encoded time with `time.to_ms(time_fts)`.
|
||||
|
||||
You can get the number of microseconds in an fts encoded time with `time.to_us(time_fts)`.
|
||||
|
||||
Please be aware, that `time.to_number` is the same as a `time.to_s` with a precision of four decimal places.
|
||||
|
||||
**Supported calculations:**
|
||||
|
||||
You can add and subtract all fts encoded times, without any problems.
|
||||
|
||||
You can multiply or divide fts encoded times by numerical constants. So if you need the half of a time, `time_fts/2` is correct.
|
||||
|
||||
A division of two fts encoded times would give you a number. (e.g., `time.s(2.5)/time.s(0.5)` equals `5`).
|
||||
|
||||
The functions `math.abs()`, `math.min()`, `math.max()` and `math.huge` will work as expected.
|
||||
|
||||
Comparisons (`>`, `>=`, `==`, `<`, `<=` and `~=`) of two fts encoded times work as expected.
|
||||
|
||||
If you want a duration form a given time_fts to *now*, `time.since(time_fts)` as a shortcut (or simply use `fts.now - time_fts`) will return an fts encoded time. If you need milliseconds use `time.to_ms(time.since(time_fts))`.
|
||||
|
||||
**Unsupported calculations:**
|
||||
|
||||
Don't add a numerical constant to an fts time (in the best case, the numerical constant is interpreted as µs).
|
||||
|
||||
Don't multiply two fts_encoded times (the position of the comma is wrong).
|
||||
|
||||
But please be aware that _all other not explicitly supported_ math on fts encoded times (`math.xxx()`) won't work as expected. (If you really, really need that, you have to shift the position of the comma yourself!)
|
||||
|
||||
**Background:**
|
||||
Numbers in Lua are double float which have a mantissa (precision) of 53 bit (plus sign + exponent)
|
||||
We won't use the exponent here.
|
||||
|
||||
So we can store 2^53 = 9.0072E15 different values. If we use the lower 6 digits for µs, we can store
|
||||
up to 9.0072E9 seconds.
|
||||
|
||||
A year has 365.25*24*3600 = 3.15576E7 s, so we can store up to 285 years (9.0072E9/3.15576E7) with µs precision.
|
||||
|
||||
The module has been tested with the fixed point comma at 10^6 (other values might work, but are not really tested).
|
||||
|
||||
**Recommendations:**
|
||||
If the name of a variable implies a time (now, when, until, xxxdeadline, xxxtime, getElapsedTimeSinceBoot, lastxxxtimexxx, ...) we assume this value to be a time (fts encoded).
|
||||
|
||||
Other objects which are times (like `last_tap`, `tap_interval_override`, ...) shall be renamed to something like `last_tap_time` (so to make it clear that they are fts encoded).
|
||||
|
||||
All other time variables (a handful) get the appropriate suffix `_ms`, `_us`, `_s` (`_m`, `_h`, `_d`) denoting their status as plain Lua numbers and their resolution.
|
||||
|
||||
@module time
|
||||
|
||||
@usage
|
||||
local time = require("ui/time")
|
||||
|
||||
local start_time = time.now()
|
||||
-- Do some stuff.
|
||||
-- You can add and subtract `fts times` objects.
|
||||
local duration = time.now() - start.fts
|
||||
-- And convert that object to various more human-readable formats, e.g.,
|
||||
print(string.format("Stuff took %.3fms", time.to_ms(duration)))
|
||||
|
||||
local offset = time.s(100)
|
||||
print(string.format("Stuff plus 100s took %.3fms", time.to_ms(duration + offset)))
|
||||
]]
|
||||
|
||||
local ffi = require("ffi")
|
||||
require("ffi/posix_h")
|
||||
local logger = require("logger")
|
||||
|
||||
local C = ffi.C
|
||||
|
||||
-- An FTS_PRECISION of 1e6 will give us a µs precision.
|
||||
local FTS_PRECISION = 1e6
|
||||
|
||||
local S2FTS = FTS_PRECISION
|
||||
local MS2FTS = FTS_PRECISION / 1e3
|
||||
local US2FTS = FTS_PRECISION / 1e6
|
||||
local NS2FTS = FTS_PRECISION / 1e9
|
||||
|
||||
local FTS2S = 1 / S2FTS
|
||||
local FTS2MS = 1 / MS2FTS
|
||||
local FTS2US = 1 / US2FTS
|
||||
|
||||
-- Fixed point time
|
||||
local time = {}
|
||||
|
||||
--- Sometimes we need a very large time
|
||||
time.huge = math.huge
|
||||
|
||||
--- Creates a time (fts) from a number in seconds
|
||||
function time.s(seconds)
|
||||
return math.floor(seconds * S2FTS)
|
||||
end
|
||||
|
||||
--- Creates a time (fts) from a number in milliseconds
|
||||
function time.ms(msec)
|
||||
return math.floor(msec * MS2FTS)
|
||||
end
|
||||
|
||||
--- Creates a time (fts) from a number in microseconds
|
||||
function time.us(usec)
|
||||
return math.floor(usec * US2FTS)
|
||||
end
|
||||
|
||||
--- Creates a time (fts) from a structure similar to timeval
|
||||
function time.timeval(tv)
|
||||
return tv.sec * S2FTS + tv.usec * US2FTS
|
||||
end
|
||||
|
||||
--- Converts an fts time to a Lua (decimal) number (sec.usecs) (accurate to the ms, rounded to 4 decimal places)
|
||||
function time.to_number(time_fts)
|
||||
-- Round to 4 decimal places
|
||||
return math.floor(time.to_s(time_fts) * 10000 + 0.5) / 10000
|
||||
end
|
||||
|
||||
--- Converts an fts to a Lua (int) number (resolution: 1µs)
|
||||
function time.to_s(time_fts)
|
||||
-- Time in seconds with µs precision (without decimal places)
|
||||
return time_fts * FTS2S
|
||||
end
|
||||
|
||||
--[[-- Converts a fts to a Lua (int) number (resolution: 1ms, rounded).
|
||||
|
||||
(Mainly useful when computing a time lapse for benchmarking purposes).
|
||||
]]
|
||||
function time.to_ms(time_fts)
|
||||
-- Time in milliseconds ms (without decimal places)
|
||||
return math.floor(time_fts * FTS2MS + 0.5)
|
||||
end
|
||||
|
||||
--- Converts an fts to a Lua (int) number (resolution: 1µs, rounded)
|
||||
function time.to_us(time_fts)
|
||||
-- Time in microseconds µs (without decimal places)
|
||||
return math.floor(time_fts * FTS2US + 0.5)
|
||||
end
|
||||
|
||||
--[[-- Compare a past *MONOTONIC* fts time to *now*, returning the elapsed time between the two. (sec.usecs variant)
|
||||
|
||||
Returns a Lua (decimal) number (sec.usecs, with decimal places) (accurate to the µs)
|
||||
]]
|
||||
function time.since(start_time)
|
||||
-- Time difference
|
||||
return time.now() - start_time
|
||||
end
|
||||
|
||||
--- Splits an fts to seconds and microseconds.
|
||||
-- If argument is nil, returns nil,nil.
|
||||
function time.split_s_us(time_fts)
|
||||
if not time_fts then return nil, nil end
|
||||
local sec = math.floor(time_fts * FTS2S)
|
||||
local usec = math.floor(time_fts - sec * S2FTS) * FTS2US
|
||||
-- Seconds and µs
|
||||
return sec, usec
|
||||
end
|
||||
|
||||
-- ffi object for C.clock_gettime calls
|
||||
local timespec = ffi.new("struct timespec")
|
||||
|
||||
-- We prefer CLOCK_MONOTONIC_COARSE if it's available and has a decent resolution,
|
||||
-- as we generally don't need nano/micro second precision,
|
||||
-- and it can be more than twice as fast as CLOCK_MONOTONIC/CLOCK_REALTIME/gettimeofday...
|
||||
local PREFERRED_MONOTONIC_CLOCKID = C.CLOCK_MONOTONIC
|
||||
-- Ditto for REALTIME (for :realtime_coarse only, :realtime uses gettimeofday ;)).
|
||||
local PREFERRED_REALTIME_CLOCKID = C.CLOCK_REALTIME
|
||||
-- CLOCK_BOOTTIME is only available on Linux 2.6.39+...
|
||||
local HAVE_BOOTTIME = false
|
||||
if ffi.os == "Linux" then
|
||||
-- Unfortunately, it was only implemented in Linux 2.6.32, and we may run on older kernels than that...
|
||||
-- So, just probe it to see if we can rely on it.
|
||||
local probe_ts = ffi.new("struct timespec")
|
||||
if C.clock_getres(C.CLOCK_MONOTONIC_COARSE, probe_ts) == 0 then
|
||||
-- Now, it usually has a 1ms resolution on modern x86_64 systems,
|
||||
-- but it only provides a 10ms resolution on all my armv7 devices :/.
|
||||
if probe_ts.tv_sec == 0 and probe_ts.tv_nsec <= 1000000 then
|
||||
PREFERRED_MONOTONIC_CLOCKID = C.CLOCK_MONOTONIC_COARSE
|
||||
end
|
||||
end
|
||||
logger.dbg("fts: Preferred MONOTONIC clock source is", PREFERRED_MONOTONIC_CLOCKID == C.CLOCK_MONOTONIC_COARSE and "CLOCK_MONOTONIC_COARSE" or "CLOCK_MONOTONIC")
|
||||
if C.clock_getres(C.CLOCK_REALTIME_COARSE, probe_ts) == 0 then
|
||||
if probe_ts.tv_sec == 0 and probe_ts.tv_nsec <= 1000000 then
|
||||
PREFERRED_REALTIME_CLOCKID = C.CLOCK_REALTIME_COARSE
|
||||
end
|
||||
end
|
||||
logger.dbg("fts: Preferred REALTIME clock source is", PREFERRED_REALTIME_CLOCKID == C.CLOCK_REALTIME_COARSE and "CLOCK_REALTIME_COARSE" or "CLOCK_REALTIME")
|
||||
|
||||
if C.clock_getres(C.CLOCK_BOOTTIME, probe_ts) == 0 then
|
||||
HAVE_BOOTTIME = true
|
||||
end
|
||||
logger.dbg("fts: BOOTTIME clock source is", HAVE_BOOTTIME and "supported" or "NOT supported")
|
||||
|
||||
probe_ts = nil --luacheck: ignore
|
||||
end
|
||||
|
||||
--[[--
|
||||
Returns an fts time based on the current wall clock time.
|
||||
(e.g., gettimeofday / clock_gettime(CLOCK_REALTIME).
|
||||
|
||||
This is a simple wrapper around clock_gettime(CLOCK_REALTIME) to get all the niceties of a time.
|
||||
If you don't need sub-second precision, prefer os.time().
|
||||
Which means that, yes, this is a fancier POSIX Epoch ;).
|
||||
|
||||
@usage
|
||||
local time = require("ui/time")
|
||||
local fts_start = time.realtime()
|
||||
-- Do some stuff.
|
||||
-- You can add and substract fts times
|
||||
local fts_duration = time.realtime() - fts_start
|
||||
|
||||
@treturn fts fixed point time
|
||||
]]
|
||||
function time.realtime()
|
||||
C.clock_gettime(C.CLOCK_REALTIME, timespec)
|
||||
-- TIMESPEC_TO_FTS
|
||||
return tonumber(timespec.tv_sec) * S2FTS + math.floor(tonumber(timespec.tv_nsec) * NS2FTS)
|
||||
end
|
||||
|
||||
--[[--
|
||||
Returns an fts time based on the current value from the system's MONOTONIC clock source.
|
||||
(e.g., clock_gettime(CLOCK_MONOTONIC).)
|
||||
|
||||
POSIX guarantees that this clock source will *never* go backwards (but it *may* return the same value multiple times).
|
||||
On Linux, this will not account for time spent with the device in suspend (unlike CLOCK_BOOTTIME).
|
||||
|
||||
@treturn fts fixed point time
|
||||
]]
|
||||
function time.monotonic()
|
||||
C.clock_gettime(C.CLOCK_MONOTONIC, timespec)
|
||||
-- TIMESPEC_TO_FTS
|
||||
return tonumber(timespec.tv_sec) * S2FTS + math.floor(tonumber(timespec.tv_nsec) * NS2FTS)
|
||||
end
|
||||
|
||||
--- Ditto, but w/ CLOCK_MONOTONIC_COARSE if it's available and has a 1ms resolution or better (uses CLOCK_MONOTONIC otherwise).
|
||||
function time.monotonic_coarse()
|
||||
C.clock_gettime(PREFERRED_MONOTONIC_CLOCKID, timespec)
|
||||
-- TIMESPEC_TO_FTS
|
||||
return tonumber(timespec.tv_sec) * S2FTS + math.floor(tonumber(timespec.tv_nsec) * NS2FTS)
|
||||
end
|
||||
|
||||
-- Ditto, but w/ CLOCK_REALTIME_COARSE if it's available and has a 1ms resolution or better (uses CLOCK_REALTIME otherwise).
|
||||
function time.realtime_coarse()
|
||||
C.clock_gettime(PREFERRED_REALTIME_CLOCKID, timespec)
|
||||
-- TIMESPEC_TO_FTS
|
||||
return tonumber(timespec.tv_sec) * S2FTS + math.floor(tonumber(timespec.tv_nsec) * NS2FTS)
|
||||
end
|
||||
|
||||
--- Since CLOCK_BOOTIME may not be supported, we offer a few aliases with automatic fallbacks to MONOTONIC or REALTIME
|
||||
if HAVE_BOOTTIME then
|
||||
--- Ditto, but w/ CLOCK_BOOTTIME (will return an fts time set to 0, 0 if the clock source is unsupported, as it's 2.6.39+)
|
||||
--- Only use it if you *know* it's going to be supported, otherwise, prefer the four following aliases.
|
||||
function time.boottime()
|
||||
C.clock_gettime(C.CLOCK_BOOTTIME, timespec)
|
||||
-- TIMESPEC_TO_FTS
|
||||
return tonumber(timespec.tv_sec) * S2FTS + math.floor(tonumber(timespec.tv_nsec) * NS2FTS)
|
||||
end
|
||||
|
||||
time.boottime_or_monotonic = time.boottime
|
||||
time.boottime_or_monotonic_coarse = time.boottime
|
||||
time.boottime_or_realtime = time.boottime
|
||||
time.boottime_or_realtime_coarse = time.boottime
|
||||
else
|
||||
function time.boottime()
|
||||
logger.warn("fts: Attemped to call boottime on a platform where it's unsupported!")
|
||||
return 0
|
||||
end
|
||||
|
||||
time.boottime_or_monotonic = time.monotonic
|
||||
time.boottime_or_monotonic_coarse = time.monotonic_coarse
|
||||
time.boottime_or_realtime = time.realtime
|
||||
time.boottime_or_realtime_coarse = time.realtime_coarse
|
||||
end
|
||||
|
||||
--[[-- Alias for `monotonic_coarse`.
|
||||
|
||||
The assumption being anything that requires accurate timestamps expects a monotonic clock source.
|
||||
This is certainly true for KOReader's UI scheduling.
|
||||
]]
|
||||
time.now = time.monotonic_coarse
|
||||
|
||||
--- Converts an fts time to a string (seconds with 6 decimal places)
|
||||
function time.format_time(time_fts)
|
||||
return string.format("%.06f", time_fts * FTS2S)
|
||||
end
|
||||
|
||||
return time
|
||||
@@ -5,11 +5,11 @@ This module manages widgets.
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local Geom = require("ui/geometry")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local dbg = require("dbg")
|
||||
local logger = require("logger")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local util = require("util")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local Input = Device.input
|
||||
local Screen = Device.screen
|
||||
@@ -30,7 +30,7 @@ local UIManager = {
|
||||
event_handlers = nil,
|
||||
|
||||
_running = true,
|
||||
_now = TimeVal:now(),
|
||||
_now = time.now(),
|
||||
_window_stack = {},
|
||||
_task_queue = {},
|
||||
_task_queue_dirty = false,
|
||||
@@ -523,14 +523,14 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither)
|
||||
end
|
||||
|
||||
-- schedule an execution task, task queue is in ascendant order
|
||||
function UIManager:schedule(time, action, ...)
|
||||
function UIManager:schedule(sched_time, action, ...)
|
||||
local p, s, e = 1, 1, #self._task_queue
|
||||
if e ~= 0 then
|
||||
-- do a binary insert
|
||||
repeat
|
||||
p = math.floor(s + (e - s) / 2)
|
||||
p = math.floor((e + s) / 2) -- Not necessary to use (s + (e -s) / 2) here!
|
||||
local p_time = self._task_queue[p].time
|
||||
if time > p_time then
|
||||
if sched_time > p_time then
|
||||
if s == e then
|
||||
p = e + 1
|
||||
break
|
||||
@@ -539,11 +539,11 @@ function UIManager:schedule(time, action, ...)
|
||||
else
|
||||
s = p
|
||||
end
|
||||
elseif time < p_time then
|
||||
e = p
|
||||
if s == e then
|
||||
elseif sched_time < p_time then
|
||||
if s == p then
|
||||
break
|
||||
end
|
||||
e = p
|
||||
else
|
||||
-- for fairness, it's better to make p+1 is strictly less than
|
||||
-- p might want to revisit here in the future
|
||||
@@ -552,7 +552,7 @@ function UIManager:schedule(time, action, ...)
|
||||
until e < s
|
||||
end
|
||||
table.insert(self._task_queue, p, {
|
||||
time = time,
|
||||
time = sched_time,
|
||||
action = action,
|
||||
argc = select('#', ...),
|
||||
args = {...},
|
||||
@@ -560,8 +560,8 @@ function UIManager:schedule(time, action, ...)
|
||||
self._task_queue_dirty = true
|
||||
end
|
||||
dbg:guard(UIManager, 'schedule',
|
||||
function(self, time, action)
|
||||
assert(time.sec >= 0, "Only positive time allowed")
|
||||
function(self, sched_time, action)
|
||||
assert(sched_time >= 0, "Only positive time allowed")
|
||||
assert(action ~= nil, "No action")
|
||||
end)
|
||||
|
||||
@@ -577,7 +577,7 @@ Schedules a task to be run a certain amount of seconds from now.
|
||||
function UIManager:scheduleIn(seconds, action, ...)
|
||||
-- We might run significantly late inside an UI frame, so we can't use the cached value here.
|
||||
-- It would also cause some bad interactions with the way nextTick & co behave.
|
||||
local when = TimeVal:now() + TimeVal:fromnumber(seconds)
|
||||
local when = time.now() + time.s(seconds)
|
||||
self:schedule(when, action, ...)
|
||||
end
|
||||
dbg:guard(UIManager, 'scheduleIn',
|
||||
@@ -1065,15 +1065,15 @@ function UIManager:discardEvents(set_or_seconds)
|
||||
-- sometimes > 500ms on some devices/temperatures.
|
||||
-- So, block for 400ms (to have it displayed) + 400ms
|
||||
-- for user reaction to it
|
||||
delay = TimeVal:new{ sec = 0, usec = 800000 }
|
||||
delay = time.ms(800)
|
||||
else
|
||||
-- On non-eInk screen, display is usually instantaneous
|
||||
delay = TimeVal:new{ sec = 0, usec = 400000 }
|
||||
delay = time.ms(400)
|
||||
end
|
||||
else -- we expect a number
|
||||
delay = TimeVal:new{ sec = set_or_seconds, usec = 0 }
|
||||
delay = time.s(set_or_seconds)
|
||||
end
|
||||
self._discard_events_till = TimeVal:now() + delay
|
||||
self._discard_events_till = time.now() + delay
|
||||
end
|
||||
|
||||
--[[--
|
||||
@@ -1089,7 +1089,7 @@ function UIManager:sendEvent(event)
|
||||
|
||||
-- Ensure discardEvents
|
||||
if self._discard_events_till then
|
||||
if TimeVal:now() < self._discard_events_till then
|
||||
if time.now() < self._discard_events_till then
|
||||
return
|
||||
else
|
||||
self._discard_events_till = nil
|
||||
@@ -1173,10 +1173,10 @@ end
|
||||
|
||||
--[[
|
||||
function UIManager:getNextTaskTimes(count)
|
||||
count = count or 1
|
||||
count = math.min(count or 1, #self._task_queue)
|
||||
local times = {}
|
||||
for i = 1, math.min(count, #self._task_queue) do
|
||||
times[i] = self._task_queue[i].time - TimeVal:now()
|
||||
for i = 1, count do
|
||||
times[i] = self._task_queue[i].time - time.now()
|
||||
end
|
||||
return times
|
||||
end
|
||||
@@ -1184,14 +1184,14 @@ end
|
||||
|
||||
function UIManager:getNextTaskTime()
|
||||
if #self._task_queue > 0 then
|
||||
return self._task_queue[1].time - TimeVal:now()
|
||||
return self._task_queue[1].time - time:now()
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function UIManager:_checkTasks()
|
||||
self._now = TimeVal:now()
|
||||
self._now = time.now()
|
||||
local wait_until = nil
|
||||
|
||||
-- task.action may schedule other events
|
||||
@@ -1202,8 +1202,8 @@ function UIManager:_checkTasks()
|
||||
break
|
||||
end
|
||||
local next_task = self._task_queue[1]
|
||||
local task_tv = next_task.time or TimeVal.zero
|
||||
if task_tv <= self._now then
|
||||
local task_time = next_task.time or 0
|
||||
if task_time <= self._now then
|
||||
-- remove from table
|
||||
local task = table.remove(self._task_queue, 1)
|
||||
-- task is pending to be executed right now. do it.
|
||||
@@ -1213,7 +1213,7 @@ function UIManager:_checkTasks()
|
||||
else
|
||||
-- queue is sorted in ascendant order, safe to assume all items
|
||||
-- are future tasks for now
|
||||
wait_until = next_task.time
|
||||
wait_until = task_time
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -1222,9 +1222,9 @@ function UIManager:_checkTasks()
|
||||
end
|
||||
|
||||
--[[--
|
||||
Returns a TimeVal object corresponding to the last UI tick.
|
||||
Returns a time (fts) corresponding to the last tick.
|
||||
|
||||
This is essentially a cached TimeVal:now(), computed at the top of every iteration of the main UI loop,
|
||||
This is essentially a cached time.now(), computed at the top of every iteration of the main UI loop,
|
||||
(right before checking/running scheduled tasks).
|
||||
This is mainly useful to compute/schedule stuff in the same time scale as the UI loop (i.e., MONOTONIC),
|
||||
without having to resort to a syscall.
|
||||
@@ -1233,7 +1233,7 @@ unless you're blocking the UI for a significant amount of time in a single UI fr
|
||||
|
||||
That is to say, its granularity is an UI frame.
|
||||
|
||||
Prefer the appropriate TimeVal method for your needs if you require perfect accuracy or better granularity
|
||||
Prefer the appropriate time function for your needs if you require perfect accuracy or better granularity
|
||||
(e.g., when you're actually working on the event loop *itself* (UIManager, Input, GestureDetector),
|
||||
or if you're dealing with intra-frame timers).
|
||||
|
||||
@@ -1244,10 +1244,10 @@ function UIManager:getTime()
|
||||
end
|
||||
|
||||
--[[--
|
||||
Returns a TimeVal object corresponding to the last UI tick plus the time in standby and suspend.
|
||||
Returns a time (fts) corresponding to the last UI tick plus the time in standby.
|
||||
]]
|
||||
function UIManager:getElapsedTimeSinceBoot()
|
||||
return self:getTime() + Device.total_standby_tv + Device.total_suspend_tv
|
||||
return self:getTime() + Device.total_standby_time + Device.total_suspend_time
|
||||
end
|
||||
|
||||
-- precedence of refresh modes:
|
||||
@@ -1676,7 +1676,7 @@ function UIManager:handleInput()
|
||||
|
||||
-- We pass that on as an absolute deadline, not a relative wait time.
|
||||
if wait_us then
|
||||
deadline = now + TimeVal:new{ usec = wait_us }
|
||||
deadline = now + time.us(wait_us)
|
||||
end
|
||||
|
||||
-- If there's a scheduled task pending, that puts an upper bound on how long to wait.
|
||||
@@ -1721,7 +1721,6 @@ function UIManager:handleInput()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function UIManager:onRotation()
|
||||
self:setDirty("all", "full")
|
||||
self:forceRePaint()
|
||||
|
||||
@@ -18,7 +18,6 @@ local ScrollHtmlWidget = require("ui/widget/scrollhtmlwidget")
|
||||
local ScrollTextWidget = require("ui/widget/scrolltextwidget")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local TitleBar = require("ui/widget/titlebar")
|
||||
local Translator = require("ui/translator")
|
||||
local UIManager = require("ui/uimanager")
|
||||
@@ -32,6 +31,7 @@ local C_ = _.pgettext
|
||||
local Input = Device.input
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
local time = require("ui/time")
|
||||
|
||||
--[[
|
||||
Display quick lookup word definition
|
||||
@@ -154,7 +154,7 @@ function DictQuickLookup:init()
|
||||
args = function(text, hold_duration)
|
||||
-- do this lookup in the same domain (dict/wikipedia)
|
||||
local lookup_wikipedia = self.is_wiki
|
||||
if hold_duration >= TimeVal:new{ sec = 3, usec = 0 } then
|
||||
if hold_duration >= time.s(3) then
|
||||
-- but allow switching domain with a long hold
|
||||
lookup_wikipedia = not lookup_wikipedia
|
||||
end
|
||||
|
||||
@@ -13,13 +13,13 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local LineWidget = require("ui/widget/linewidget")
|
||||
local ScrollHtmlWidget = require("ui/widget/scrollhtmlwidget")
|
||||
local Size = require("ui/size")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
local time = require("ui/time")
|
||||
|
||||
-- If we wanted to use the default font set for the book,
|
||||
-- we'd need to add a few functions to crengine and cre.cpp
|
||||
@@ -195,7 +195,7 @@ function FootnoteWidget:init()
|
||||
-- callback function when HoldReleaseText is handled as args
|
||||
args = function(text, hold_duration)
|
||||
if self.dialog then
|
||||
local lookup_target = hold_duration < TimeVal:new{ sec = 3, usec = 0 } and "LookupWord" or "LookupWikipedia"
|
||||
local lookup_target = hold_duration < time.s(3) and "LookupWord" or "LookupWikipedia"
|
||||
self.dialog:handleEvent(
|
||||
Event:new(lookup_target, text)
|
||||
)
|
||||
|
||||
@@ -15,12 +15,12 @@ local NaturalLight = require("ui/widget/naturallightwidget")
|
||||
local ProgressWidget = require("ui/widget/progresswidget")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local TitleBar = require("ui/widget/titlebar")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
|
||||
@@ -30,7 +30,7 @@ local FrontLightWidget = FocusManager:new{
|
||||
-- This should stay active during natural light configuration
|
||||
is_always_active = true,
|
||||
rate = Screen.low_pan_rate and 3 or 30, -- Widget update rate.
|
||||
last_time = TimeVal.zero, -- Tracks last update time to prevent update spamming.
|
||||
last_time = 0, -- Tracks last update time to prevent update spamming.
|
||||
}
|
||||
|
||||
function FrontLightWidget:init()
|
||||
@@ -569,9 +569,9 @@ function FrontLightWidget:onTapProgress(arg, ges_ev)
|
||||
|
||||
-- But limit the widget update frequency on E Ink.
|
||||
if Screen.low_pan_rate then
|
||||
local current_time = TimeVal:now()
|
||||
local last_time = self.last_time or TimeVal.zero
|
||||
if current_time - last_time > TimeVal:new{ usec = 1000000 / self.rate } then
|
||||
local current_time = time.now()
|
||||
local last_time = self.last_time or 0
|
||||
if current_time - last_time > time.s(1 / self.rate) then
|
||||
self.last_time = current_time
|
||||
else
|
||||
-- Schedule a final update after we stop panning.
|
||||
|
||||
@@ -9,9 +9,9 @@ local GestureRange = require("ui/gesturerange")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Mupdf = require("ffi/mupdf")
|
||||
local Screen = Device.screen
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
|
||||
local HtmlBoxWidget = InputContainer:new{
|
||||
@@ -21,7 +21,7 @@ local HtmlBoxWidget = InputContainer:new{
|
||||
page_count = 0,
|
||||
page_number = 1,
|
||||
hold_start_pos = nil,
|
||||
hold_start_tv = nil,
|
||||
hold_start_time = nil,
|
||||
html_link_tapped_callback = nil,
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ function HtmlBoxWidget:onHoldStartText(_, ges)
|
||||
return false -- let event be processed by other widgets
|
||||
end
|
||||
|
||||
self.hold_start_tv = UIManager:getTime()
|
||||
self.hold_start_time = UIManager:getTime()
|
||||
|
||||
return true
|
||||
end
|
||||
@@ -230,7 +230,7 @@ function HtmlBoxWidget:onHoldReleaseText(callback, ges)
|
||||
return false
|
||||
end
|
||||
|
||||
local hold_duration = TimeVal.now() - self.hold_start_tv
|
||||
local hold_duration = time.now() - self.hold_start_time
|
||||
|
||||
local page = self.document:openPage(self.page_number)
|
||||
local lines = page:getPageText()
|
||||
|
||||
@@ -13,10 +13,10 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local RectSpan = require("ui/widget/rectspan")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local Input = Device.input
|
||||
local time = require("ui/time")
|
||||
local Screen = Device.screen
|
||||
|
||||
local band = bit.band
|
||||
@@ -168,9 +168,9 @@ function Notification:_cleanShownStack(num)
|
||||
-- to follow what is happening).
|
||||
-- As a sanity check, we also forget those shown for
|
||||
-- more than 30s in case no close event was received.
|
||||
local expire_tv = UIManager:getTime() - TimeVal:new{ sec = 30, usec = 0 }
|
||||
local expire_time = UIManager:getTime() - time.s(30)
|
||||
for i=#Notification._nums_shown, 1, -1 do
|
||||
if Notification._nums_shown[i] and Notification._nums_shown[i] > expire_tv then
|
||||
if Notification._nums_shown[i] and Notification._nums_shown[i] > expire_time then
|
||||
break -- still shown (or not yet expired)
|
||||
end
|
||||
table.remove(Notification._nums_shown, i)
|
||||
|
||||
@@ -24,11 +24,11 @@ local RenderText = require("ui/rendertext")
|
||||
local RightContainer = require("ui/widget/container/rightcontainer")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Math = require("optmath")
|
||||
local logger = require("logger")
|
||||
local dbg = require("dbg")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
local Screen = require("device").screen
|
||||
|
||||
@@ -1852,18 +1852,18 @@ function TextBoxWidget:onHoldStartText(_, ges)
|
||||
-- check coordinates are actually inside our area
|
||||
if self.hold_start_x < 0 or self.hold_start_x > self.dimen.w or
|
||||
self.hold_start_y < 0 or self.hold_start_y > self.dimen.h then
|
||||
self.hold_start_tv = nil -- don't process coming HoldRelease event
|
||||
self.hold_start_time = nil -- don't process coming HoldRelease event
|
||||
return false -- let event be processed by other widgets
|
||||
end
|
||||
|
||||
self.hold_start_tv = UIManager:getTime()
|
||||
self.hold_start_time = UIManager:getTime()
|
||||
return true
|
||||
end
|
||||
|
||||
function TextBoxWidget:onHoldPanText(_, ges)
|
||||
-- We don't highlight the currently selected text, but just let this
|
||||
-- event pop up if we are not currently selecting text
|
||||
if not self.hold_start_tv then
|
||||
if not self.hold_start_time then
|
||||
return false
|
||||
end
|
||||
-- Don't let that event be processed by other widget
|
||||
@@ -1877,7 +1877,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
local hold_end_y = ges.pos.y - self.dimen.y
|
||||
|
||||
-- check we have seen a HoldStart event
|
||||
if not self.hold_start_tv then
|
||||
if not self.hold_start_time then
|
||||
return false
|
||||
end
|
||||
-- check start and end coordinates are actually inside our area
|
||||
@@ -1888,7 +1888,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
return false
|
||||
end
|
||||
|
||||
local hold_duration = TimeVal.now() - self.hold_start_tv
|
||||
local hold_duration = time.now() - self.hold_start_time
|
||||
|
||||
-- If page contains an image, check if Hold is on this image and deal
|
||||
-- with it directly
|
||||
@@ -1950,7 +1950,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
-- a missed start event
|
||||
self.hold_start_x = nil
|
||||
self.hold_start_y = nil
|
||||
self.hold_start_tv = nil
|
||||
self.hold_start_time = nil
|
||||
|
||||
if self.use_xtext then
|
||||
-- With xtext and fribidi, words may not be laid out in logical order,
|
||||
@@ -1982,7 +1982,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
-- to consider when looking for word boundaries)
|
||||
local selected_text = self._xtext:getSelectedWords(sel_start_idx, sel_end_idx, 50)
|
||||
|
||||
logger.dbg("onHoldReleaseText (duration:", hold_duration:tonumber(), ") :",
|
||||
logger.dbg("onHoldReleaseText (duration:", time.format_time(hold_duration), ") :",
|
||||
sel_start_idx, ">", sel_end_idx, "=", selected_text)
|
||||
callback(selected_text, hold_duration)
|
||||
return true
|
||||
@@ -2000,7 +2000,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
end
|
||||
|
||||
local selected_text = table.concat(self.charlist, "", sel_start_idx, sel_end_idx)
|
||||
logger.dbg("onHoldReleaseText (duration:", hold_duration:tonumber(), ") :", sel_start_idx, ">", sel_end_idx, "=", selected_text)
|
||||
logger.dbg("onHoldReleaseText (duration:", time.format_time(hold_duration), ") :", sel_start_idx, ">", sel_end_idx, "=", selected_text)
|
||||
callback(selected_text, hold_duration)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -14,12 +14,12 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local KeyboardLayoutDialog = require("ui/widget/keyboardlayoutdialog")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
local Screen = Device.screen
|
||||
|
||||
@@ -665,8 +665,7 @@ function VirtualKeyPopup:init()
|
||||
}
|
||||
},
|
||||
}
|
||||
self.tap_interval_override = G_reader_settings:readSetting("ges_tap_interval_on_keyboard", 0)
|
||||
self.tap_interval_override = TimeVal:new{ usec = self.tap_interval_override }
|
||||
self.tap_interval_override = time.ms(G_reader_settings:readSetting("ges_tap_interval_on_keyboard_ms", 0))
|
||||
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Close = { {Device.input.group.Back}, doc = "close keyboard" }
|
||||
@@ -787,8 +786,7 @@ function VirtualKeyboard:init()
|
||||
self.min_layer = keyboard.min_layer
|
||||
self.max_layer = keyboard.max_layer
|
||||
self:initLayer(self.keyboard_layer)
|
||||
self.tap_interval_override = G_reader_settings:readSetting("ges_tap_interval_on_keyboard", 0)
|
||||
self.tap_interval_override = TimeVal:new{ usec = self.tap_interval_override }
|
||||
self.tap_interval_override = time.ms(G_reader_settings:readSetting("ges_tap_interval_on_keyboard_ms", 0))
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Close = { {"Back"}, doc = "close keyboard" }
|
||||
end
|
||||
|
||||
@@ -13,11 +13,11 @@ end
|
||||
local Event = require("ui/event")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local PluginShare = require("pluginshare")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local Math = require("optmath")
|
||||
local T = require("ffi/util").template
|
||||
@@ -32,7 +32,7 @@ local AutoSuspend = WidgetContainer:new{
|
||||
autoshutdown_timeout_seconds = default_autoshutdown_timeout_seconds,
|
||||
auto_suspend_timeout_seconds = default_auto_suspend_timeout_seconds,
|
||||
auto_standby_timeout_seconds = default_auto_standby_timeout_seconds,
|
||||
last_action_tv = TimeVal.zero,
|
||||
last_action_time = 0,
|
||||
is_standby_scheduled = false,
|
||||
task = nil,
|
||||
standby_task = nil,
|
||||
@@ -58,7 +58,7 @@ function AutoSuspend:_schedule(shutdown_only)
|
||||
return
|
||||
end
|
||||
|
||||
local suspend_delay, shutdown_delay
|
||||
local suspend_delay_seconds, shutdown_delay_seconds
|
||||
local is_charging
|
||||
-- On devices with an auxiliary battery, we only care about the auxiliary battery being charged...
|
||||
local powerd = Device:getPowerDevice()
|
||||
@@ -68,29 +68,29 @@ function AutoSuspend:_schedule(shutdown_only)
|
||||
is_charging = powerd:isCharging()
|
||||
end
|
||||
if PluginShare.pause_auto_suspend or is_charging then
|
||||
suspend_delay = self.auto_suspend_timeout_seconds
|
||||
shutdown_delay = self.autoshutdown_timeout_seconds
|
||||
suspend_delay_seconds = self.auto_suspend_timeout_seconds
|
||||
shutdown_delay_seconds = self.autoshutdown_timeout_seconds
|
||||
else
|
||||
local now_tv = UIManager:getElapsedTimeSinceBoot()
|
||||
suspend_delay = self.auto_suspend_timeout_seconds - (now_tv - self.last_action_tv):tonumber()
|
||||
shutdown_delay = self.autoshutdown_timeout_seconds - (now_tv - self.last_action_tv):tonumber()
|
||||
local now = UIManager:getElapsedTimeSinceBoot()
|
||||
suspend_delay_seconds = self.auto_suspend_timeout_seconds - time.to_number(now - self.last_action_time)
|
||||
shutdown_delay_seconds = self.autoshutdown_timeout_seconds - time.to_number(now - self.last_action_time)
|
||||
end
|
||||
|
||||
-- Try to shutdown first, as we may have been woken up from suspend just for the sole purpose of doing that.
|
||||
if self:_enabledShutdown() and shutdown_delay <= 0 then
|
||||
if self:_enabledShutdown() and shutdown_delay_seconds <= 0 then
|
||||
logger.dbg("AutoSuspend: initiating shutdown")
|
||||
UIManager:poweroff_action()
|
||||
elseif self:_enabled() and suspend_delay <= 0 and not shutdown_only then
|
||||
elseif self:_enabled() and suspend_delay_seconds <= 0 and not shutdown_only then
|
||||
logger.dbg("AutoSuspend: will suspend the device")
|
||||
UIManager:suspend()
|
||||
else
|
||||
if self:_enabled() and not shutdown_only then
|
||||
logger.dbg("AutoSuspend: scheduling next suspend check in", suspend_delay)
|
||||
UIManager:scheduleIn(suspend_delay, self.task)
|
||||
logger.dbg("AutoSuspend: scheduling next suspend check in", suspend_delay_seconds)
|
||||
UIManager:scheduleIn(suspend_delay_seconds, self.task)
|
||||
end
|
||||
if self:_enabledShutdown() then
|
||||
logger.dbg("AutoSuspend: scheduling next shutdown check in", shutdown_delay)
|
||||
UIManager:scheduleIn(shutdown_delay, self.task)
|
||||
logger.dbg("AutoSuspend: scheduling next shutdown check in", shutdown_delay_seconds)
|
||||
UIManager:scheduleIn(shutdown_delay_seconds, self.task)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -104,14 +104,14 @@ end
|
||||
|
||||
function AutoSuspend:_start()
|
||||
if self:_enabled() or self:_enabledShutdown() then
|
||||
logger.dbg("AutoSuspend: start suspend/shutdown timer at", self.last_action_tv:tonumber())
|
||||
logger.dbg("AutoSuspend: start suspend/shutdown timer at", time.format_time(self.last_action_time))
|
||||
self:_schedule()
|
||||
end
|
||||
end
|
||||
|
||||
function AutoSuspend:_start_standby()
|
||||
if self:_enabledStandby() then
|
||||
logger.dbg("AutoSuspend: start standby timer at", self.last_action_tv:tonumber())
|
||||
logger.dbg("AutoSuspend: start standby timer at", time.format_time(self.last_action_time))
|
||||
self:_schedule_standby()
|
||||
end
|
||||
end
|
||||
@@ -119,7 +119,7 @@ end
|
||||
-- Variant that only re-engages the shutdown timer for onUnexpectedWakeupLimit
|
||||
function AutoSuspend:_restart()
|
||||
if self:_enabledShutdown() then
|
||||
logger.dbg("AutoSuspend: restart shutdown timer at", self.last_action_tv:tonumber())
|
||||
logger.dbg("AutoSuspend: restart shutdown timer at", time.format_time(self.last_action_time))
|
||||
self:_schedule(true)
|
||||
end
|
||||
end
|
||||
@@ -161,7 +161,7 @@ function AutoSuspend:init()
|
||||
-- Make sure we only have an AllowStandby handler when we actually want one...
|
||||
self:toggleStandbyHandler(self:_enabledStandby())
|
||||
|
||||
self.last_action_tv = UIManager:getElapsedTimeSinceBoot()
|
||||
self.last_action_time = UIManager:getElapsedTimeSinceBoot()
|
||||
self:_start()
|
||||
self:_start_standby()
|
||||
|
||||
@@ -185,7 +185,7 @@ end
|
||||
|
||||
function AutoSuspend:onInputEvent()
|
||||
logger.dbg("AutoSuspend: onInputEvent")
|
||||
self.last_action_tv = UIManager:getElapsedTimeSinceBoot()
|
||||
self.last_action_time = UIManager:getElapsedTimeSinceBoot()
|
||||
end
|
||||
|
||||
function AutoSuspend:_unschedule_standby()
|
||||
@@ -219,41 +219,41 @@ function AutoSuspend:_schedule_standby()
|
||||
end
|
||||
|
||||
-- When we're in a state where entering suspend is undesirable, we simply postpone the check by the full delay.
|
||||
local standby_delay
|
||||
local standby_delay_seconds
|
||||
if NetworkMgr:isWifiOn() then
|
||||
-- Don't enter standby if wifi is on, as this will break in fun and interesting ways (from Wi-Fi issues to kernel deadlocks).
|
||||
--logger.dbg("AutoSuspend: WiFi is on, delaying standby")
|
||||
standby_delay = self.auto_standby_timeout_seconds
|
||||
standby_delay_seconds = self.auto_standby_timeout_seconds
|
||||
elseif Device.powerd:isCharging() and not Device:canPowerSaveWhileCharging() then
|
||||
-- Don't enter standby when charging on devices where charging prevents entering low power states.
|
||||
-- NOTE: Minor simplification here, we currently don't do the hasAuxBattery dance like in _schedule,
|
||||
-- because all the hasAuxBattery devices can currently enter PM states while charging ;).
|
||||
--logger.dbg("AutoSuspend: charging, delaying standby")
|
||||
standby_delay = self.auto_standby_timeout_seconds
|
||||
standby_delay_seconds = self.auto_standby_timeout_seconds
|
||||
else
|
||||
local now_tv = UIManager:getElapsedTimeSinceBoot()
|
||||
standby_delay = self.auto_standby_timeout_seconds - (now_tv - self.last_action_tv):tonumber()
|
||||
local now = UIManager:getElapsedTimeSinceBoot()
|
||||
standby_delay_seconds = self.auto_standby_timeout_seconds - time.to_number(now - self.last_action_time)
|
||||
|
||||
-- If we blow past the deadline on the first call of a scheduling cycle,
|
||||
-- make sure we don't go straight to allowStandby, as we haven't called preventStandby yet...
|
||||
if not self.is_standby_scheduled and standby_delay <= 0 then
|
||||
if not self.is_standby_scheduled and standby_delay_seconds <= 0 then
|
||||
-- If this happens, it means we hit LeaveStandby or Resume *before* consuming new input events,
|
||||
-- e.g., if there weren't any input events at all (woken up by an alarm),
|
||||
-- or if the only input events we consumed did not trigger an InputEvent event (woken up by gyro events),
|
||||
-- meaning self.last_action_tv is further in the past than it ought to.
|
||||
-- meaning self.last_action_time is further in the past than it ought to.
|
||||
-- Delay by the full amount to avoid further bad scheduling interactions.
|
||||
standby_delay = self.auto_standby_timeout_seconds
|
||||
standby_delay_seconds = self.auto_standby_timeout_seconds
|
||||
end
|
||||
end
|
||||
|
||||
if standby_delay <= 0 then
|
||||
if standby_delay_seconds <= 0 then
|
||||
-- We blew the deadline, tell UIManager we're ready to enter standby
|
||||
self:allowStandby()
|
||||
else
|
||||
-- Reschedule standby for the full or remaining delay
|
||||
-- NOTE: This is fairly chatty, given the low delays, but really helpful nonetheless... :/
|
||||
logger.dbg("AutoSuspend: scheduling next standby check in", standby_delay)
|
||||
UIManager:scheduleIn(standby_delay, self.standby_task)
|
||||
logger.dbg("AutoSuspend: scheduling next standby check in", standby_delay_seconds)
|
||||
UIManager:scheduleIn(standby_delay_seconds, self.standby_task)
|
||||
|
||||
-- Prevent standby until we actually blow the deadline
|
||||
if not self.is_standby_scheduled then
|
||||
@@ -318,7 +318,7 @@ function AutoSuspend:onResume()
|
||||
end
|
||||
-- Unschedule in case we tripped onUnexpectedWakeupLimit first...
|
||||
self:_unschedule()
|
||||
-- We should always follow an InputEvent, so last_action_tv is already up to date :).
|
||||
-- We should always follow an InputEvent, so last_action_time is already up to date :).
|
||||
self:_start()
|
||||
self:_unschedule_standby()
|
||||
self:_start_standby()
|
||||
@@ -391,13 +391,13 @@ function AutoSuspend:pickTimeoutValue(touchmenu_instance, title, info, setting,
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = title,
|
||||
info_text = info,
|
||||
callback = function(time)
|
||||
callback = function(spinner)
|
||||
if time_scale == 2 then
|
||||
self[setting] = (time.hour * 24 + time.min) * 3600
|
||||
self[setting] = (spinner.hour * 24 + spinner.min) * 3600
|
||||
elseif time_scale == 1 then
|
||||
self[setting] = time.hour * 3600 + time.min * 60
|
||||
self[setting] = spinner.hour * 3600 + spinner.min * 60
|
||||
else
|
||||
self[setting] = time.hour * 60 + time.min
|
||||
self[setting] = spinner.hour * 60 + spinner.min
|
||||
end
|
||||
self[setting] = Math.clamp(self[setting], range[1], range[2])
|
||||
G_reader_settings:saveSetting(setting, self[setting])
|
||||
@@ -571,7 +571,7 @@ function AutoSuspend:AllowStandbyHandler()
|
||||
if next_task_time then
|
||||
-- Wake up slightly after the formerly scheduled event,
|
||||
-- to avoid resheduling the same function after a fraction of a second again (e.g. don't draw footer twice).
|
||||
wake_in = math.floor(next_task_time:tonumber()) + 1
|
||||
wake_in = math.floor(time.to_number(next_task_time)) + 1
|
||||
else
|
||||
wake_in = math.huge
|
||||
end
|
||||
@@ -583,12 +583,12 @@ function AutoSuspend:AllowStandbyHandler()
|
||||
-- This obviously needs a matching implementation in Device, the canonical one being Kobo.
|
||||
Device:standby(wake_in)
|
||||
|
||||
logger.dbg("AutoSuspend: left standby after", Device.last_standby_tv:tonumber(), "s")
|
||||
logger.dbg("AutoSuspend: left standby after", time.format_time(Device.last_standby_time), "s")
|
||||
|
||||
-- We delay the LeaveStandby event (our onLeaveStandby handler is responsible for rescheduling everything properly),
|
||||
-- to make sure UIManager will consume the input events that woke us up first
|
||||
-- (in case we were woken up by user input, as opposed to an rtc wake alarm)!
|
||||
-- (This ensures we'll use an up to date last_action_tv, and that it only ever gets updated from *user* input).
|
||||
-- (This ensures we'll use an up to date last_action_time, and that it only ever gets updated from *user* input).
|
||||
-- NOTE: UIManager consumes scheduled tasks before input events, which is why we can't use nextTick.
|
||||
UIManager:tickAfterNext(self.leave_standby_task)
|
||||
end
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local PluginShare = require("pluginshare")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
|
||||
@@ -14,7 +14,7 @@ local AutoTurn = WidgetContainer:new{
|
||||
autoturn_sec = 0,
|
||||
autoturn_distance = 1,
|
||||
enabled = false,
|
||||
last_action_tv = TimeVal.zero,
|
||||
last_action_time = 0,
|
||||
task = nil,
|
||||
}
|
||||
|
||||
@@ -28,21 +28,21 @@ function AutoTurn:_schedule()
|
||||
return
|
||||
end
|
||||
|
||||
local delay = self.last_action_tv + TimeVal:new{ sec = self.autoturn_sec, usec = 0 } - UIManager:getTime()
|
||||
delay = delay:tonumber()
|
||||
local delay = self.last_action_time + time.s(self.autoturn_sec) - UIManager:getTime()
|
||||
|
||||
if delay <= 0 then
|
||||
if UIManager:getTopWidget() == "ReaderUI" then
|
||||
logger.dbg("AutoTurn: go to next page")
|
||||
self.ui:handleEvent(Event:new("GotoViewRel", self.autoturn_distance))
|
||||
self.last_action_tv = UIManager:getTime()
|
||||
self.last_action_time = UIManager:getTime()
|
||||
end
|
||||
logger.dbg("AutoTurn: schedule in", self.autoturn_sec)
|
||||
UIManager:scheduleIn(self.autoturn_sec, self.task)
|
||||
self.scheduled = true
|
||||
else
|
||||
logger.dbg("AutoTurn: schedule in", delay)
|
||||
UIManager:scheduleIn(delay, self.task)
|
||||
local delay_s = time.to_number(delay)
|
||||
logger.dbg("AutoTurn: schedule in", delay_s, "s")
|
||||
UIManager:scheduleIn(delay_s, self.task)
|
||||
self.scheduled = true
|
||||
end
|
||||
end
|
||||
@@ -58,10 +58,10 @@ end
|
||||
|
||||
function AutoTurn:_start()
|
||||
if self:_enabled() then
|
||||
local now_tv = UIManager:getTime()
|
||||
logger.dbg("AutoTurn: start at", now_tv:tonumber())
|
||||
local now = UIManager:getTime()
|
||||
logger.dbg("AutoTurn: start at", time.format_time(now))
|
||||
PluginShare.pause_auto_suspend = true
|
||||
self.last_action_tv = now_tv
|
||||
self.last_action_time = now
|
||||
self:_schedule()
|
||||
|
||||
local text
|
||||
@@ -107,7 +107,7 @@ end
|
||||
|
||||
function AutoTurn:onInputEvent()
|
||||
logger.dbg("AutoTurn: onInputEvent")
|
||||
self.last_action_tv = UIManager:getTime()
|
||||
self.last_action_time = UIManager:getTime()
|
||||
end
|
||||
|
||||
function AutoTurn:onEnterStandby()
|
||||
@@ -122,9 +122,9 @@ function AutoTurn:onSuspend()
|
||||
end
|
||||
|
||||
function AutoTurn:_onLeaveStandby()
|
||||
self.last_action_tv = self.last_action_tv - Device.last_standby_tv
|
||||
self.last_action_time = self.last_action_time - Device.last_standby_time
|
||||
|
||||
-- We messed with last_action_tv, so a complete reschedule has to be done.
|
||||
-- We messed with last_action_time, so a complete reschedule has to be done.
|
||||
if self:_enabled() then
|
||||
self:_unschedule()
|
||||
self:_schedule()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local logger = require("logger")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local time = require("ui/time")
|
||||
|
||||
local CommandRunner = {
|
||||
pio = nil,
|
||||
@@ -37,7 +37,7 @@ function CommandRunner:start(job)
|
||||
assert(self.pio == nil)
|
||||
assert(self.job == nil)
|
||||
self.job = job
|
||||
self.job.start_tv = UIManager:getTime()
|
||||
self.job.start_time = UIManager:getTime()
|
||||
assert(type(self.job.executable) == "string")
|
||||
local command = self:createEnvironment() .. " " ..
|
||||
"sh plugins/backgroundrunner.koplugin/luawrapper.sh " ..
|
||||
@@ -77,7 +77,7 @@ function CommandRunner:poll()
|
||||
UIManager:allowStandby()
|
||||
self.pio:close()
|
||||
self.pio = nil
|
||||
self.job.end_tv = TimeVal:now()
|
||||
self.job.end_time = time.now()
|
||||
local job = self.job
|
||||
self.job = nil
|
||||
return job
|
||||
|
||||
@@ -9,10 +9,10 @@ end
|
||||
|
||||
local CommandRunner = require("commandrunner")
|
||||
local PluginShare = require("pluginshare")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
|
||||
-- BackgroundRunner is an experimental feature to execute non-critical jobs in
|
||||
@@ -72,9 +72,9 @@ local _ = require("gettext")
|
||||
-- bad_command: boolean, whether the command is not found. Not available for
|
||||
-- function executable.
|
||||
-- blocked: boolean, whether the job is blocked.
|
||||
-- start_tv: number, the TimeVal when the job was started.
|
||||
-- end_tv: number, the TimeVal when the job was stopped.
|
||||
-- insert_tv: number, the TimeVal when the job was inserted into queue.
|
||||
-- start_time: number, the time (fts) when the job was started.
|
||||
-- end_time: number, the time (fts) when the job was stopped.
|
||||
-- insert_time: number, the time (fts) when the job was inserted into queue.
|
||||
-- (All of them in the monotonic time scale, like the main event loop & task queue).
|
||||
|
||||
local BackgroundRunner = {
|
||||
@@ -117,9 +117,9 @@ end
|
||||
function BackgroundRunner:_finishJob(job)
|
||||
assert(self ~= nil)
|
||||
if type(job.executable) == "function" then
|
||||
local tv_diff = job.end_tv - job.start_tv
|
||||
local threshold = TimeVal:new{ sec = 1, usec = 0 }
|
||||
job.timeout = (tv_diff > threshold)
|
||||
local time_diff = job.end_time - job.start_time
|
||||
local threshold = time.s(1)
|
||||
job.timeout = (time_diff > threshold)
|
||||
end
|
||||
job.blocked = job.timeout
|
||||
if not job.blocked and self:_shouldRepeat(job) then
|
||||
@@ -141,7 +141,7 @@ function BackgroundRunner:_executeJob(job)
|
||||
CommandRunner:start(job)
|
||||
return true
|
||||
elseif type(job.executable) == "function" then
|
||||
job.start_tv = UIManager:getTime()
|
||||
job.start_time = UIManager:getTime()
|
||||
local status, err = pcall(job.executable)
|
||||
if status then
|
||||
job.result = 0
|
||||
@@ -149,7 +149,7 @@ function BackgroundRunner:_executeJob(job)
|
||||
job.result = 1
|
||||
job.exception = err
|
||||
end
|
||||
job.end_tv = TimeVal:now()
|
||||
job.end_time = time.now()
|
||||
self:_finishJob(job)
|
||||
return true
|
||||
else
|
||||
@@ -176,10 +176,10 @@ function BackgroundRunner:_execute()
|
||||
local round = 0
|
||||
while #self.jobs > 0 do
|
||||
local job = table.remove(self.jobs, 1)
|
||||
if job.insert_tv == nil then
|
||||
if job.insert_time == nil then
|
||||
-- Jobs are first inserted to jobs table from external users.
|
||||
-- So they may not have an insert field.
|
||||
job.insert_tv = UIManager:getTime()
|
||||
job.insert_time = UIManager:getTime()
|
||||
end
|
||||
local should_execute = false
|
||||
local should_ignore = false
|
||||
@@ -192,7 +192,7 @@ function BackgroundRunner:_execute()
|
||||
end
|
||||
elseif type(job.when) == "number" then
|
||||
if job.when >= 0 then
|
||||
should_execute = ((UIManager:getTime() - job.insert_tv) >= TimeVal:fromnumber(job.when))
|
||||
should_execute = (UIManager:getTime() - job.insert_time >= time.s(job.when))
|
||||
else
|
||||
should_ignore = true
|
||||
end
|
||||
@@ -253,7 +253,7 @@ end
|
||||
|
||||
function BackgroundRunner:_insert(job)
|
||||
assert(self ~= nil)
|
||||
job.insert_tv = UIManager:getTime()
|
||||
job.insert_time = UIManager:getTime()
|
||||
table.insert(self.jobs, job)
|
||||
end
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@ of storing it.
|
||||
@module koplugin.calibre.metadata
|
||||
--]]--
|
||||
|
||||
local TimeVal = require("ui/timeval")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local rapidjson = require("rapidjson")
|
||||
local logger = require("logger")
|
||||
local parser = require("parser")
|
||||
local util = require("util")
|
||||
local time = require("ui/time")
|
||||
|
||||
local used_metadata = {
|
||||
"uuid",
|
||||
@@ -242,7 +242,7 @@ end
|
||||
|
||||
function CalibreMetadata:init(dir, is_search)
|
||||
if not dir then return end
|
||||
local start = TimeVal:now()
|
||||
local start_time = time.now()
|
||||
self.path = dir
|
||||
local ok_meta, ok_drive, file_meta, file_drive = findCalibreFiles(dir)
|
||||
self.driveinfo = file_drive
|
||||
@@ -261,12 +261,12 @@ function CalibreMetadata:init(dir, is_search)
|
||||
if is_search then
|
||||
self:cleanUnused(is_search)
|
||||
msg = string.format("(search) in %.3f milliseconds: %d books",
|
||||
TimeVal:getDurationMs(start), #self.books)
|
||||
time.to_ms(time.since(start_time())), #self.books)
|
||||
else
|
||||
local deleted_count = self:prune()
|
||||
self:cleanUnused()
|
||||
msg = string.format("in %.3f milliseconds: %d books. %d pruned",
|
||||
TimeVal:getDurationMs(start), #self.books, deleted_count)
|
||||
time.to_ms(time.since(start_time())), #self.books, deleted_count)
|
||||
end
|
||||
logger.info(string.format("calibre info loaded from disk %s", msg))
|
||||
return true
|
||||
|
||||
@@ -13,12 +13,12 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local Persist = require("persist")
|
||||
local Screen = require("device").screen
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local rapidjson = require("rapidjson")
|
||||
local util = require("util")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
|
||||
@@ -325,10 +325,10 @@ function CalibreSearch:find(option)
|
||||
end
|
||||
|
||||
-- measure time elapsed searching
|
||||
local start = TimeVal:now()
|
||||
local start_time = time.now()
|
||||
self:browse(option)
|
||||
logger.info(string.format("search done in %.3f milliseconds (%s, %s, %s, %s, %s)",
|
||||
TimeVal:getDurationMs(start),
|
||||
time.to_ms(time.since(start_time)),
|
||||
option == "find" and "books" or option,
|
||||
"case sensitive: " .. tostring(not self.case_insensitive),
|
||||
"title: " .. tostring(self.find_by_title),
|
||||
@@ -552,7 +552,7 @@ end
|
||||
|
||||
-- get metadata from cache or calibre files
|
||||
function CalibreSearch:getMetadata()
|
||||
local start = TimeVal:now()
|
||||
local start_time = time.now()
|
||||
local template = "metadata: %d books imported from %s in %.3f milliseconds"
|
||||
|
||||
-- try to load metadata from cache
|
||||
@@ -594,7 +594,7 @@ function CalibreSearch:getMetadata()
|
||||
end
|
||||
end
|
||||
if is_newer then
|
||||
logger.info(string.format(template, #cache, "cache", TimeVal:getDurationMs(start)))
|
||||
logger.info(string.format(template, #cache, "cache", time.to_ms(time.since(start_time))))
|
||||
return cache
|
||||
else
|
||||
logger.warn("cache is older than metadata, ignoring it")
|
||||
@@ -623,7 +623,7 @@ function CalibreSearch:getMetadata()
|
||||
logger.info("Failed to serialize calibre metadata cache:", err)
|
||||
end
|
||||
end
|
||||
logger.info(string.format(template, #books, "calibre", TimeVal:getDurationMs(start)))
|
||||
logger.info(string.format(template, #books, "calibre", time.to_ms(time.since(start_time))))
|
||||
return books
|
||||
end
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ local FFIUtil = require("ffi/util")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local RenderImage = require("ui/renderimage")
|
||||
local SQ3 = require("lua-ljsqlite3/init")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local zstd = require("ffi/zstd")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local N_ = _.ngettext
|
||||
local T = FFIUtil.template
|
||||
@@ -137,8 +137,8 @@ function BookInfoManager:init()
|
||||
self.subprocesses_collector = nil
|
||||
self.subprocesses_collect_interval = 10 -- do that every 10 seconds
|
||||
self.subprocesses_pids = {}
|
||||
self.subprocesses_last_added_tv = TimeVal.zero
|
||||
self.subprocesses_killall_timeout_tv = TimeVal:new{ sec = 300, usec = 0 } -- cleanup timeout for stuck subprocesses
|
||||
self.subprocesses_last_added_time = 0
|
||||
self.subprocesses_killall_timeout_time = time.s(300) -- cleanup timeout for stuck subprocesses
|
||||
-- 300 seconds should be more than enough to open and get info from 9-10 books
|
||||
-- Whether to use former blitbuffer:scale() (default to using MuPDF)
|
||||
self.use_legacy_image_scaling = G_reader_settings:isTrue("legacy_image_scaling")
|
||||
@@ -657,7 +657,7 @@ function BookInfoManager:collectSubprocesses()
|
||||
-- the user has not left FileManager or changed page - that would
|
||||
-- have caused a terminateBackgroundJobs() - if we're here, it's
|
||||
-- that user has left reader in FileBrower and went away)
|
||||
if TimeVal:now() > self.subprocesses_last_added_tv + self.subprocesses_killall_timeout_tv then
|
||||
if time.now() > self.subprocesses_last_added_time + self.subprocesses_killall_timeout_time then
|
||||
logger.warn("Some subprocesses were running for too long, killing them")
|
||||
self:terminateBackgroundJobs()
|
||||
-- we'll collect them next time we're run
|
||||
@@ -730,7 +730,7 @@ function BookInfoManager:extractInBackground(files)
|
||||
-- counter on each task, and undo that inside collectSubprocesses() zombie reaper.
|
||||
UIManager:preventStandby()
|
||||
table.insert(self.subprocesses_pids, task_pid)
|
||||
self.subprocesses_last_added_tv = TimeVal:now()
|
||||
self.subprocesses_last_added_time = time.now()
|
||||
|
||||
-- We need to collect terminated jobs pids (so they do not stay "zombies"
|
||||
-- and fill linux processes table)
|
||||
|
||||
@@ -17,6 +17,7 @@ local SpinWidget = require("ui/widget/spinwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local util = require("util")
|
||||
local T = FFIUtil.template
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
local logger = require("logger")
|
||||
|
||||
@@ -478,16 +479,16 @@ Any other taps made within this interval after a first tap will be considered ac
|
||||
|
||||
The interval value is in milliseconds and can range from 0 (0 seconds) to 2000 (2 seconds).]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = GestureDetector:getInterval("ges_tap_interval")/1000,
|
||||
value = time.to_ms(GestureDetector.ges_tap_interval),
|
||||
value_min = 0,
|
||||
value_max = 2000,
|
||||
value_step = 50,
|
||||
value_hold_step = 200,
|
||||
ok_text = _("Set interval"),
|
||||
default_value = GestureDetector.TAP_INTERVAL/1000,
|
||||
default_value = GestureDetector.TAP_INTERVAL_MS,
|
||||
callback = function(spin)
|
||||
G_reader_settings:saveSetting("ges_tap_interval", spin.value*1000)
|
||||
GestureDetector:setNewInterval("ges_tap_interval", spin.value*1000)
|
||||
G_reader_settings:saveSetting("ges_tap_interval_ms", spin.value)
|
||||
GestureDetector.ges_tap_interval = time.ms(spin.value)
|
||||
end
|
||||
}
|
||||
UIManager:show(items)
|
||||
@@ -504,7 +505,7 @@ Any other taps made within this interval after a first tap will be considered ac
|
||||
|
||||
The interval value is in milliseconds and can range from 0 (0 seconds) to 2000 (2 seconds).]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = G_reader_settings:readSetting("ges_tap_interval_on_keyboard", 0)/1000,
|
||||
value = time.to_ms(G_reader_settings:readSetting("ges_tap_interval_on_keyboard_ms", 0)),
|
||||
value_min = 0,
|
||||
value_max = 2000,
|
||||
value_step = 50,
|
||||
@@ -512,7 +513,7 @@ The interval value is in milliseconds and can range from 0 (0 seconds) to 2000 (
|
||||
ok_text = _("Set interval"),
|
||||
default_value = 0,
|
||||
callback = function(spin)
|
||||
G_reader_settings:saveSetting("ges_tap_interval_on_keyboard", spin.value*1000)
|
||||
G_reader_settings:saveSetting("ges_tap_interval_on_keyboard_ms", spin.value)
|
||||
end
|
||||
}
|
||||
UIManager:show(items)
|
||||
@@ -529,16 +530,16 @@ When double tap is enabled, this sets the time to wait for the second tap. A sin
|
||||
|
||||
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = GestureDetector:getInterval("ges_double_tap_interval")/1000,
|
||||
value = time.to_ms(GestureDetector.ges_double_tap_interval),
|
||||
value_min = 100,
|
||||
value_max = 2000,
|
||||
value_step = 100,
|
||||
value_hold_step = 500,
|
||||
ok_text = _("Set interval"),
|
||||
default_value = GestureDetector.DOUBLE_TAP_INTERVAL/1000,
|
||||
default_value = GestureDetector.DOUBLE_TAP_INTERVAL_MS,
|
||||
callback = function(spin)
|
||||
G_reader_settings:saveSetting("ges_double_tap_interval", spin.value*1000)
|
||||
GestureDetector:setNewInterval("ges_double_tap_interval", spin.value*1000)
|
||||
G_reader_settings:saveSetting("ges_double_tap_interval_ms", spin.value)
|
||||
GestureDetector.ges_double_tap_interval = time.ms(spin.value)
|
||||
end
|
||||
}
|
||||
UIManager:show(items)
|
||||
@@ -555,16 +556,16 @@ This sets the allowed duration of any of the two fingers touch/release for the c
|
||||
|
||||
The duration value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = GestureDetector:getInterval("ges_two_finger_tap_duration")/1000,
|
||||
value = time.to_ms(GestureDetector.ges_two_finger_tap_duration),
|
||||
value_min = 100,
|
||||
value_max = 2000,
|
||||
value_step = 100,
|
||||
value_hold_step = 500,
|
||||
ok_text = _("Set duration"),
|
||||
default_value = GestureDetector.TWO_FINGER_TAP_DURATION/1000,
|
||||
default_value = GestureDetector.TWO_FINGER_TAP_DURATION_MS,
|
||||
callback = function(spin)
|
||||
G_reader_settings:saveSetting("ges_two_finger_tap_duration", spin.value*1000)
|
||||
GestureDetector:setNewInterval("ges_two_finger_tap_duration", spin.value*1000)
|
||||
G_reader_settings:saveSetting("ges_two_finger_tap_duration_ms", spin.value)
|
||||
GestureDetector.ges_two_finger_tap_duration = time.ms(spin.value)
|
||||
end
|
||||
}
|
||||
UIManager:show(items)
|
||||
@@ -581,16 +582,16 @@ If a touch is not released in this interval, it is considered a long-press. On d
|
||||
|
||||
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = GestureDetector:getInterval("ges_hold_interval")/1000,
|
||||
value = time.to_ms(GestureDetector.ges_hold_interval),
|
||||
value_min = 100,
|
||||
value_max = 2000,
|
||||
value_step = 100,
|
||||
value_hold_step = 500,
|
||||
ok_text = _("Set interval"),
|
||||
default_value = GestureDetector.HOLD_INTERVAL/1000,
|
||||
default_value = GestureDetector.HOLD_INTERVAL_MS,
|
||||
callback = function(spin)
|
||||
G_reader_settings:saveSetting("ges_hold_interval", spin.value*1000)
|
||||
GestureDetector:setNewInterval("ges_hold_interval", spin.value*1000)
|
||||
G_reader_settings:saveSetting("ges_hold_interval_ms", spin.value)
|
||||
GestureDetector.ges_hold_interval = time.ms(spin.value)
|
||||
end
|
||||
}
|
||||
UIManager:show(items)
|
||||
@@ -607,16 +608,16 @@ This sets the maximum delay between the start and the end of a swipe for it to b
|
||||
|
||||
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).]]),
|
||||
width = math.floor(Screen:getWidth() * 0.75),
|
||||
value = GestureDetector:getInterval("ges_swipe_interval")/1000,
|
||||
value = time.to_ms(GestureDetector.ges_swipe_interval),
|
||||
value_min = 100,
|
||||
value_max = 2000,
|
||||
value_step = 100,
|
||||
value_hold_step = 500,
|
||||
ok_text = _("Set interval"),
|
||||
default_value = GestureDetector.SWIPE_INTERVAL/1000,
|
||||
default_value = GestureDetector.SWIPE_INTERVAL_MS,
|
||||
callback = function(spin)
|
||||
G_reader_settings:saveSetting("ges_swipe_interval", spin.value*1000)
|
||||
GestureDetector:setNewInterval("ges_swipe_interval", spin.value*1000)
|
||||
G_reader_settings:saveSetting("ges_swipe_interval_ms", spin.value)
|
||||
GestureDetector.ges_swipe_interval = time.ms(spin.value)
|
||||
end
|
||||
}
|
||||
UIManager:show(items)
|
||||
|
||||
@@ -3,6 +3,7 @@ local Dispatcher = require("dispatcher")
|
||||
local KeyValuePage = require("ui/widget/keyvaluepage")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local time = require("ui/time")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
|
||||
@@ -48,11 +49,11 @@ function SystemStat:appendCounters()
|
||||
util.secondsToClockDuration("", os.difftime(os.time(), self.start_sec), false, true, true)})
|
||||
if Device:canSuspend() then
|
||||
self:put({" " .. _("Time in suspend"),
|
||||
util.secondsToClockDuration("", Device.total_suspend_tv:tonumber(), false, true, true)})
|
||||
util.secondsToClockDuration("", time.to_number(Device.total_suspend_time), false, true, true)})
|
||||
end
|
||||
if Device:canStandby() then
|
||||
self:put({" " .. _("Time in standby"),
|
||||
util.secondsToClockDuration("", Device.total_standby_tv:tonumber(), false, true, true)})
|
||||
util.secondsToClockDuration("", time.to_number(Device.total_standby_time), false, true, true)})
|
||||
end
|
||||
self:put({_("Counters"), ""})
|
||||
self:put({_(" wake-ups"), self.wakeup_count})
|
||||
|
||||
@@ -39,6 +39,7 @@ describe("BackgroundRunner widget tests", function()
|
||||
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
assert.is_false(executed)
|
||||
MockTime:increase(9)
|
||||
UIManager:handleInput()
|
||||
assert.is_false(executed)
|
||||
@@ -132,7 +133,7 @@ describe("BackgroundRunner widget tests", function()
|
||||
table.insert(PluginShare.backgroundJobs, job)
|
||||
notifyBackgroundJobsUpdated()
|
||||
|
||||
while job.end_tv == nil do
|
||||
while job.end_time == nil do
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
end
|
||||
@@ -157,7 +158,7 @@ describe("BackgroundRunner widget tests", function()
|
||||
table.insert(PluginShare.backgroundJobs, job)
|
||||
notifyBackgroundJobsUpdated()
|
||||
|
||||
while job.end_tv == nil do
|
||||
while job.end_time == nil do
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
end
|
||||
@@ -171,11 +172,11 @@ describe("BackgroundRunner widget tests", function()
|
||||
ENV1 = "yes",
|
||||
ENV2 = "no",
|
||||
}
|
||||
job.end_tv = nil
|
||||
job.end_time = nil
|
||||
table.insert(PluginShare.backgroundJobs, job)
|
||||
notifyBackgroundJobsUpdated()
|
||||
|
||||
while job.end_tv == nil do
|
||||
while job.end_time == nil do
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
end
|
||||
@@ -206,7 +207,7 @@ describe("BackgroundRunner widget tests", function()
|
||||
table.insert(PluginShare.backgroundJobs, job)
|
||||
notifyBackgroundJobsUpdated()
|
||||
|
||||
while job.end_tv == nil do
|
||||
while job.end_time == nil do
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
end
|
||||
@@ -216,12 +217,12 @@ describe("BackgroundRunner widget tests", function()
|
||||
assert.is_false(job.timeout)
|
||||
assert.is_false(job.bad_command)
|
||||
|
||||
job.end_tv = nil
|
||||
job.end_time = nil
|
||||
env2 = "no"
|
||||
table.insert(PluginShare.backgroundJobs, job)
|
||||
notifyBackgroundJobsUpdated()
|
||||
|
||||
while job.end_tv == nil do
|
||||
while job.end_time == nil do
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
end
|
||||
@@ -244,7 +245,7 @@ describe("BackgroundRunner widget tests", function()
|
||||
table.insert(PluginShare.backgroundJobs, job)
|
||||
notifyBackgroundJobsUpdated()
|
||||
|
||||
while job.end_tv == nil do
|
||||
while job.end_time == nil do
|
||||
MockTime:increase(2)
|
||||
UIManager:handleInput()
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require("commonrequire")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local time = require("ui/time")
|
||||
local ffi = require("ffi")
|
||||
local dummy = require("ffi/posix_h")
|
||||
local logger = require("logger")
|
||||
@@ -21,6 +22,10 @@ local MockTime = {
|
||||
realtime = 0,
|
||||
boottime = 0,
|
||||
boottime_or_realtime_coarse = 0,
|
||||
monotonic_time = 0,
|
||||
realtime_time = 0,
|
||||
boottime_time = 0,
|
||||
boottime_or_realtime_coarse_time = 0,
|
||||
}
|
||||
|
||||
function MockTime:install()
|
||||
@@ -100,7 +105,72 @@ function MockTime:install()
|
||||
logger.dbg("MockTime:TimeVal.now: ", self.monotonic)
|
||||
return TimeVal:new{ sec = self.monotonic }
|
||||
end
|
||||
end
|
||||
|
||||
if self.original_tv_realtime_time == nil then
|
||||
self.original_tv_realtime_time = time.realtime
|
||||
assert(self.original_tv_realtime_time ~= nil)
|
||||
end
|
||||
if self.original_tv_realtime_coarse_time == nil then
|
||||
self.original_tv_realtime_coarse_time = time.realtime_coarse
|
||||
assert(self.original_tv_realtime_coarse_time ~= nil)
|
||||
end
|
||||
if self.original_tv_monotonic_time == nil then
|
||||
self.original_tv_monotonic_time = time.monotonic
|
||||
assert(self.original_tv_monotonic_time ~= nil)
|
||||
end
|
||||
if self.original_tv_monotonic_coarse_time == nil then
|
||||
self.original_tv_monotonic_coarse_time = time.monotonic_coarse
|
||||
assert(self.original_tv_monotonic_coarse_time ~= nil)
|
||||
end
|
||||
if self.original_tv_boottime_time == nil then
|
||||
self.original_tv_boottime_time = time.boottime
|
||||
assert(self.original_tv_boottime_time ~= nil)
|
||||
end
|
||||
if self.original_tv_boottime_or_realtime_coarse_time == nil then
|
||||
self.original_tv_boottime_or_realtime_coarse_time = time.boottime_or_realtime_coarse
|
||||
assert(self.original_tv_boottime_or_realtime_coarse_time ~= nil)
|
||||
end
|
||||
if self.original_tv_now == nil then
|
||||
self.original_tv_now = time.now
|
||||
assert(self.original_tv_now ~= nil)
|
||||
end
|
||||
|
||||
-- Store both REALTIME & MONOTONIC clocks for fts
|
||||
self.realtime_time = os.time() * 1e6
|
||||
local timespec_time = ffi.new("struct timespec")
|
||||
C.clock_gettime(C.CLOCK_MONOTONIC_COARSE, timespec_time)
|
||||
self.monotonic = tonumber(timespec.tv_sec) * 1e6
|
||||
|
||||
time.realtime = function()
|
||||
logger.dbg("MockTime:TimeVal.realtime: ", self.realtime_time)
|
||||
return self.realtime_time
|
||||
end
|
||||
time.realtime_coarse = function()
|
||||
logger.dbg("MockTime:TimeVal.realtime_coarse: ", self.realtime_coarse_time)
|
||||
return self.realtime_coarse_time
|
||||
end
|
||||
time.monotonic = function()
|
||||
logger.dbg("MockTime:TimeVal.monotonic: ", self.monotonic)
|
||||
return self.monotonic_time
|
||||
end
|
||||
time.monotonic_coarse = function()
|
||||
logger.dbg("MockTime:TimeVal.monotonic_coarse: ", self.monotonic)
|
||||
return self.monotonic_time
|
||||
end
|
||||
time.boottime = function()
|
||||
logger.dbg("MockTime:TimeVal.boottime: ", self.boottime_time)
|
||||
return self.boottime_time
|
||||
end
|
||||
time.boottime_or_realtime_coarse = function()
|
||||
logger.dbg("MockTime:TimeVal.boottime: ", self.boottime_or_realtime_coarse_time)
|
||||
return self.boottime_or_realtime_coarse_time
|
||||
end
|
||||
time.now = function()
|
||||
logger.dbg("MockTime:TimeVal.now: ", self.monotonic)
|
||||
return self.monotonic_time
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function MockTime:uninstall()
|
||||
assert(self ~= nil)
|
||||
@@ -240,6 +310,17 @@ function MockTime:increase(value)
|
||||
logger.dbg("MockTime:increase (boottime) ", self.boottime)
|
||||
self.boottime_or_realtime_coarse = math.floor(self.boottime_or_realtime_coarse + value)
|
||||
logger.dbg("MockTime:increase (boottime) ", self.boottime_or_realtime_coarse)
|
||||
|
||||
local value_time = value * 1e6
|
||||
self.realtime_time = math.floor(self.realtime_time + value_time)
|
||||
logger.dbg("MockTime:increase (realtime) ", self.realtime_time)
|
||||
self.monotonic_time = math.floor(self.monotonic_time + value_time)
|
||||
logger.dbg("MockTime:increase (monotonic) ", self.monotonic)
|
||||
self.boottime_time = math.floor(self.boottime_time + value_time)
|
||||
logger.dbg("MockTime:increase (boottime) ", self.boottime_time)
|
||||
self.boottime_or_realtime_coarse_time = math.floor(self.boottime_or_realtime_coarse_time + value_time)
|
||||
logger.dbg("MockTime:increase (boottime) ", self.boottime_or_realtime_coarse_time)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
135
spec/unit/time_spec.lua
Normal file
135
spec/unit/time_spec.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
describe("Time module", function()
|
||||
local time, dbg, dbg_on
|
||||
setup(function()
|
||||
require("commonrequire")
|
||||
time = require("ui/time")
|
||||
dbg = require("dbg")
|
||||
dbg_on = dbg.is_on
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
if dbg_on then
|
||||
dbg:turnOn()
|
||||
else
|
||||
dbg:turnOff()
|
||||
end
|
||||
end)
|
||||
|
||||
it("should set", function()
|
||||
local time1 = time.s(12)
|
||||
local time2 = time.ms(12)
|
||||
local time3 = time.us(12)
|
||||
|
||||
assert.is.same(12000000, time1)
|
||||
assert.is.same(12000, time2)
|
||||
assert.is.same(12, time3)
|
||||
end)
|
||||
|
||||
it("should convert", function()
|
||||
local time1 = 12000000
|
||||
local time2 = 12000
|
||||
local time3 = 12
|
||||
local time4 = time.s(12) + time.us(40)
|
||||
local time5 = time.s(12) + time.us(60)
|
||||
|
||||
assert.is.same(12, time.to_s(time1))
|
||||
assert.is.same(12000, time.to_ms(time1))
|
||||
assert.is.same(12000000, time.to_us(time1))
|
||||
|
||||
assert.is.same(0.012, time.to_s(time2))
|
||||
assert.is.same(12, time.to_ms(time2))
|
||||
assert.is.same(12000, time.to_us(time2))
|
||||
|
||||
assert.is.same(0.000012, time.to_s(time3))
|
||||
assert.is.same(math.floor(0.012), time.to_ms(time3))
|
||||
assert.is.same(12, time.to_us(time3))
|
||||
|
||||
assert.is.same(12.0000, time.to_number(time4))
|
||||
assert.is.same(12.0001, time.to_number(time5))
|
||||
end)
|
||||
|
||||
|
||||
it("should add", function()
|
||||
local time1 = time.s(5) + time.us(5000)
|
||||
local time2 = time.s(10) + time.us(6000)
|
||||
local time3 = time.s(10) + time.us(50000000)
|
||||
|
||||
assert.is.same(time.s(15) + time.us(11000), time1 + time2)
|
||||
assert.is.same(time.s(65) + time.us(5000), time1 + time3)
|
||||
end)
|
||||
|
||||
it("should subtract", function()
|
||||
local time1 = time.s(5.005)
|
||||
local time2 = time.s(10.006)
|
||||
|
||||
assert.is.same(time.s(5.001), time2 - time1)
|
||||
local backwards_sub = time1 - time2
|
||||
assert.is.same(time.s(-5.001), backwards_sub)
|
||||
|
||||
-- Check that to/from float conversions behave, even for negative values.
|
||||
assert.is.same(-5.001, time.to_number(backwards_sub))
|
||||
assert.is.same(time.s(-6) + time.us(999000), time.s(-5.001))
|
||||
|
||||
local tv = time.s(-6) + time.us(1000)
|
||||
assert.is.same(-5.999, time.to_number(tv))
|
||||
assert.is.same(time.s(-6) + time.us(1000), time.s(-5.999))
|
||||
|
||||
-- We lose precision because of rounding if we go higher resolution than a ms...
|
||||
tv = time.s(-6) + time.us(101)
|
||||
assert.is.same(-5.9999, time.to_number(tv))
|
||||
assert.is.same(time.s(-6) + time.us(100), time.s(-5.9999))
|
||||
-- ^ precision loss
|
||||
|
||||
tv = time.s(-6) + time.us(11)
|
||||
assert.is.same(-6, time.to_number(tv))
|
||||
-- ^ precision loss
|
||||
assert.is.same(time.s(-6) + time.us(10), time.s(-5.99999))
|
||||
-- ^ precision loss
|
||||
|
||||
tv = time.s(-6) + time.us(1)
|
||||
assert.is.same(-6, time.to_number(tv))
|
||||
-- ^ precision loss
|
||||
assert.is.same(time.s(-6) + time.us(1), time.s(-5.999999))
|
||||
end)
|
||||
|
||||
it("should derive sec and usec from more than 1 sec worth of usec", function()
|
||||
local time1 = time.s(5) + time.us(5000000)
|
||||
|
||||
assert.is.same(time.s(10), time1)
|
||||
end)
|
||||
|
||||
it("should compare", function()
|
||||
local time1 = time.s(5) + time.us(5000)
|
||||
local time2 = time.s(10) + time.us(6000)
|
||||
local time3 = time.s(5) + time.us(5000)
|
||||
local time4 = time.s(5) + time.us(6000)
|
||||
|
||||
assert.is_true(time2 > time1)
|
||||
assert.is_false(time2 < time1)
|
||||
assert.is_true(time2 >= time1)
|
||||
|
||||
assert.is_true(time4 > time1)
|
||||
assert.is_false(time4 < time1)
|
||||
assert.is_true(time4 >= time1)
|
||||
|
||||
assert.is_true(time1 < time2)
|
||||
assert.is_false(time1 > time2)
|
||||
assert.is_true(time1 <= time2)
|
||||
|
||||
assert.is_true(time1 == time3)
|
||||
assert.is_false(time1 == time2)
|
||||
assert.is_true(time1 >= time3)
|
||||
assert.is_true(time1 <= time3)
|
||||
end)
|
||||
|
||||
it("should calculate durations", function()
|
||||
local time1 = time.s(5) + time.us(500000)
|
||||
local function now() return time.s(10) end
|
||||
local now_save = time.now
|
||||
time.now = now
|
||||
assert.is.equal(time.to_s(time.s(4) + time.us(500000)), time.to_s(time.since(time1)))
|
||||
assert.is.equal(time.to_ms(time.s(4) + time.us(500000)), time.to_ms(time.since(time1)))
|
||||
assert.is.equal(time.to_us(time.s(4) + time.us(500000)), time.to_us(time.since(time1)))
|
||||
time.now = now_save
|
||||
end)
|
||||
end)
|
||||
@@ -1,50 +1,54 @@
|
||||
require("commonrequire")
|
||||
local util = require("ffi/util")
|
||||
|
||||
local UIManager = require("ui/uimanager")
|
||||
|
||||
local time = require("ui/time")
|
||||
|
||||
local NB_TESTS = 40000
|
||||
local noop = function() end
|
||||
|
||||
describe("UIManager checkTasks benchmark", function()
|
||||
local now = { util.gettime() }
|
||||
local now = time.now()
|
||||
local wait_until -- luacheck: no unused
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {}
|
||||
|
||||
for i=1,1000000 do
|
||||
for i=1, NB_TESTS do
|
||||
table.insert(
|
||||
UIManager._task_queue,
|
||||
{ time = { now[1] + 10000+i, now[2] }, action = noop }
|
||||
{ time = now + i, action = noop, argc = 0, args = {} }
|
||||
)
|
||||
end
|
||||
|
||||
-- for i=1,1000 do
|
||||
for i=1, NB_TESTS do
|
||||
wait_until, now = UIManager:_checkTasks() -- luacheck: no unused
|
||||
-- end
|
||||
end
|
||||
end)
|
||||
|
||||
describe("UIManager schedule benchmark", function()
|
||||
local now = { util.gettime() }
|
||||
local now = time.now()
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {}
|
||||
for i=1,100000 do
|
||||
UIManager:schedule({ now[1] + i, now[2] }, noop)
|
||||
|
||||
for i=1, NB_TESTS do
|
||||
UIManager:schedule(now + i, noop)
|
||||
end
|
||||
end)
|
||||
|
||||
describe("UIManager unschedule benchmark", function()
|
||||
local now = { util.gettime() }
|
||||
local now = time.now()
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {}
|
||||
|
||||
for i=1,1000 do
|
||||
for i=1, NB_TESTS do
|
||||
table.insert(
|
||||
UIManager._task_queue,
|
||||
{ time = { now[1] + 10000+i, now[2] }, action = 'a' }
|
||||
{ time = now + i, action = 'a', argc=0, args={} }
|
||||
)
|
||||
end
|
||||
|
||||
for i=1,1000 do
|
||||
UIManager:schedule(now, noop)
|
||||
for i=1, NB_TESTS do
|
||||
UIManager:schedule(now + i, noop)
|
||||
UIManager:unschedule(noop)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
describe("UIManager spec", function()
|
||||
local TimeVal, UIManager
|
||||
local time, UIManager
|
||||
local now, wait_until
|
||||
local noop = function() end
|
||||
|
||||
setup(function()
|
||||
require("commonrequire")
|
||||
TimeVal = require("ui/timeval")
|
||||
time = require("ui/time")
|
||||
UIManager = require("ui/uimanager")
|
||||
end)
|
||||
|
||||
it("should consume due tasks", function()
|
||||
now = TimeVal:now()
|
||||
local future = TimeVal:new{ sec = now.sec + 60000, usec = now.usec }
|
||||
local future2 = TimeVal:new{ sec = future.sec + 5, usec = future.usec}
|
||||
now = time.now()
|
||||
local future = now + time.s(60000)
|
||||
local future2 = future + time.s(5)
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = TimeVal:new{ sec = now.sec - 10, usec = now.usec }, action = noop, args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = noop, args = {}, argc = 0 },
|
||||
{ time = now - time.s(10), action = noop, args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = noop, args = {}, argc = 0 },
|
||||
{ time = now, action = noop, args = {}, argc = 0 },
|
||||
{ time = future, action = noop, args = {}, argc = 0 },
|
||||
{ time = future2, action = noop, args = {}, argc = 0 },
|
||||
@@ -28,26 +28,25 @@ describe("UIManager spec", function()
|
||||
end)
|
||||
|
||||
it("should calcualte wait_until properly in checkTasks routine", function()
|
||||
now = TimeVal:now()
|
||||
local future = TimeVal:new{ sec = now.sec + 60000, usec = now.usec }
|
||||
now = time.now()
|
||||
local future_time = now + time.s(60000)
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = TimeVal:new{ sec = now.sec - 10, usec = now.usec }, action = noop, args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = noop, args = {}, argc = 0 },
|
||||
{ time = now - time.s(10), action = noop, args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = noop, args = {}, argc = 0 },
|
||||
{ time = now, action = noop, args = {}, argc = 0 },
|
||||
{ time = future, action = noop, args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = future.sec + 5, usec = future.usec }, action = noop, args = {}, argc = 0 },
|
||||
{ time = future_time, action = noop, args = {}, argc = 0 },
|
||||
}
|
||||
wait_until, now = UIManager:_checkTasks()
|
||||
assert.are.same(future, wait_until)
|
||||
assert.are.same(future_time, wait_until)
|
||||
end)
|
||||
|
||||
it("should return nil wait_until properly in checkTasks routine", function()
|
||||
now = TimeVal:now()
|
||||
now = time.now()
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = TimeVal:new{ sec = now.sec - 10, usec = now.usec }, action = noop, args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = noop, args = {}, argc = 0 },
|
||||
{ time = now - time.s(10), action = noop, args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = noop, args = {}, argc = 0 },
|
||||
{ time = now, action = noop, args = {}, argc = 0 },
|
||||
}
|
||||
wait_until, now = UIManager:_checkTasks()
|
||||
@@ -55,7 +54,7 @@ describe("UIManager spec", function()
|
||||
end)
|
||||
|
||||
it("should insert new task properly in empty task queue", function()
|
||||
now = TimeVal:now()
|
||||
now = time.now()
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {}
|
||||
assert.are.same(0, #UIManager._task_queue)
|
||||
@@ -65,11 +64,11 @@ describe("UIManager spec", function()
|
||||
end)
|
||||
|
||||
it("should insert new task properly in single task queue", function()
|
||||
now = TimeVal:now()
|
||||
local future = TimeVal:new{ sec = now.sec + 10000, usec = now.usec }
|
||||
now = time.now()
|
||||
local future_time = now + time.s(10000)
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = future, action = '1', args = {}, argc = 0 },
|
||||
{ time = future_time, action = '1', args = {}, argc = 0 },
|
||||
}
|
||||
assert.are.same(1, #UIManager._task_queue)
|
||||
UIManager:scheduleIn(150, 'quz')
|
||||
@@ -90,59 +89,59 @@ describe("UIManager spec", function()
|
||||
end)
|
||||
|
||||
it("should insert new task in ascendant order", function()
|
||||
now = TimeVal:now()
|
||||
now = time.now()
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = TimeVal:new{ sec = now.sec - 10, usec = now.usec }, action = '1', args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = '2', args = {}, argc = 0 },
|
||||
{ time = now - time.s(10), action = '1', args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = '2', args = {}, argc = 0 },
|
||||
{ time = now, action = '3', args = {}, argc = 0 },
|
||||
}
|
||||
-- insert into the tail slot
|
||||
UIManager:scheduleIn(10, 'foo')
|
||||
assert.are.same('foo', UIManager._task_queue[4].action)
|
||||
-- insert into the second slot
|
||||
UIManager:schedule(TimeVal:new{ sec = now.sec - 5, usec = now.usec }, 'bar')
|
||||
UIManager:schedule(now - time.s(5), 'bar')
|
||||
assert.are.same('bar', UIManager._task_queue[2].action)
|
||||
-- insert into the head slot
|
||||
UIManager:schedule(TimeVal:new{ sec = now.sec - 15, usec = now.usec }, 'baz')
|
||||
UIManager:schedule(now - time.s(15), 'baz')
|
||||
assert.are.same('baz', UIManager._task_queue[1].action)
|
||||
-- insert into the last second slot
|
||||
UIManager:scheduleIn(5, 'qux')
|
||||
assert.are.same('qux', UIManager._task_queue[6].action)
|
||||
-- insert into the middle slot
|
||||
UIManager:schedule(TimeVal:new{ sec = now.sec, usec = now.usec - 1 }, 'quux')
|
||||
UIManager:schedule(now - time.us(1), 'quux')
|
||||
assert.are.same('quux', UIManager._task_queue[5].action)
|
||||
end)
|
||||
|
||||
it("should unschedule all the tasks with the same action", function()
|
||||
now = TimeVal:now()
|
||||
now = time.now()
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = TimeVal:new{ sec = now.sec - 15, usec = now.usec }, action = '3', args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec - 10, usec = now.usec }, action = '1', args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 6 }, action = '3', args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = '2', args = {}, argc = 0 },
|
||||
{ time = now - time.s(15), action = '3', args = {}, argc = 0 },
|
||||
{ time = now - time.s(10), action = '1', args = {}, argc = 0 },
|
||||
{ time = now - time.us(6), action = '3', args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = '2', args = {}, argc = 0 },
|
||||
{ time = now, action = '3', args = {}, argc = 0 },
|
||||
}
|
||||
-- insert into the tail slot
|
||||
UIManager:unschedule('3')
|
||||
assert.are.same({
|
||||
{ time = TimeVal:new{ sec = now.sec - 10, usec = now.usec }, action = '1', args = {}, argc = 0 },
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = '2', args = {}, argc = 0 },
|
||||
{ time = now - time.s(10), action = '1', args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = '2', args = {}, argc = 0 },
|
||||
}, UIManager._task_queue)
|
||||
end)
|
||||
|
||||
it("should not have race between unschedule and _checkTasks", function()
|
||||
now = TimeVal:now()
|
||||
now = time.now()
|
||||
local run_count = 0
|
||||
local task_to_remove = function()
|
||||
run_count = run_count + 1
|
||||
end
|
||||
UIManager:quit()
|
||||
UIManager._task_queue = {
|
||||
{ time = TimeVal:new{ sec = now.sec, usec = now.usec - 5 }, action = task_to_remove, args = {}, argc = 0 },
|
||||
{ time = now - time.us(5), action = task_to_remove, args = {}, argc = 0 },
|
||||
{
|
||||
time = TimeVal:new{ sec = now.sec - 10, usec = now.usec },
|
||||
time = now - time.s(10),
|
||||
action = function()
|
||||
run_count = run_count + 1
|
||||
UIManager:unschedule(task_to_remove)
|
||||
|
||||
Reference in New Issue
Block a user