Clarify our OOP semantics across the codebase (#9586)

Basically:

* Use `extend` for class definitions
* Use `new` for object instantiations

That includes some minor code cleanups along the way:

* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
  * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
reviewable/pr9597/r1
NiLuJe 2 years ago committed by GitHub
parent 7b9f02e1ac
commit fadee1f5dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1 +1 @@
Subproject commit bdc6cb8fb0669094bc5c9da1b9326b39674bb4f2
Subproject commit 7484668769f8e72d3be62762501aacf0a9b22870

@ -44,6 +44,7 @@ local T = BaseUtil.template
local FileManager = InputContainer:extend{
title = _("KOReader"),
active_widgets = nil, -- array
root_path = lfs.currentdir(),
clipboard = nil, -- for single file operations

@ -7,15 +7,15 @@ local DocSettings = require("docsettings")
local DocumentRegistry = require("document/documentregistry")
local ImageViewer = require("ui/widget/imageviewer")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local KeyValuePage = require("ui/widget/keyvaluepage")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local filemanagerutil = require("apps/filemanager/filemanagerutil")
local lfs = require("libs/libkoreader-lfs")
local util = require("util")
local _ = require("gettext")
local BookInfo = InputContainer:extend{
local BookInfo = WidgetContainer:extend{
bookinfo_menu_title = _("Book information"),
}

@ -3,17 +3,17 @@ local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local Device = require("device")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local Menu = require("ui/widget/menu")
local ReadCollection = require("readcollection")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = require("device").screen
local BaseUtil = require("ffi/util")
local util = require("util")
local _ = require("gettext")
local T = BaseUtil.template
local FileManagerCollection = InputContainer:extend{
local FileManagerCollection = WidgetContainer:extend{
coll_menu_title = _("Favorites"),
}

@ -4,23 +4,23 @@ local CenterContainer = require("ui/widget/container/centercontainer")
local DocumentRegistry = require("document/documentregistry")
local FileChooser = require("ui/widget/filechooser")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local Menu = require("ui/widget/menu")
local Size = require("ui/size")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local BaseUtil = require("ffi/util")
local Utf8Proc = require("ffi/utf8proc")
local lfs = require("libs/libkoreader-lfs")
local BaseUtil = require("ffi/util")
local util = require("util")
local _ = require("gettext")
local Screen = require("device").screen
local T = require("ffi/util").template
local FileSearcher = InputContainer:new{
dirs = {},
files = {},
results = {},
local FileSearcher = WidgetContainer:extend{
dirs = nil, -- table
files = nil, -- table
results = nil, -- table
case_sensitive = false,
include_subfolders = true,
@ -32,6 +32,12 @@ local sys_folders = { -- do not search in sys_folders
["/sys"] = true,
}
function FileSearcher:init()
self.dirs = {}
self.files = {}
self.results = {}
end
function FileSearcher:readDir()
local ReaderUI = require("apps/reader/readerui")
local show_unsupported = G_reader_settings:isTrue("show_unsupported")

@ -4,9 +4,9 @@ local ConfirmBox = require("ui/widget/confirmbox")
local DocSettings = require("docsettings")
local FFIUtil = require("ffi/util")
local FileManagerBookInfo = require("apps/filemanager/filemanagerbookinfo")
local InputContainer = require("ui/widget/container/inputcontainer")
local Menu = require("ui/widget/menu")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = require("device").screen
local filemanagerutil = require("apps/filemanager/filemanagerutil")
local lfs = require("libs/libkoreader-lfs")
@ -14,7 +14,7 @@ local _ = require("gettext")
local C_ = _.pgettext
local T = FFIUtil.template
local FileManagerHistory = InputContainer:extend{
local FileManagerHistory = WidgetContainer:extend{
hist_menu_title = _("History"),
}

@ -19,7 +19,7 @@ local T = FFIUtil.template
local FileManagerMenu = InputContainer:extend{
tab_item_table = nil,
menu_items = {},
menu_items = nil, -- table, mandatory
registered_widgets = nil,
}
@ -522,22 +522,20 @@ To:
end,
})
end
if not Device.should_restrict_JIT then
local Blitbuffer = require("ffi/blitbuffer")
table.insert(self.menu_items.developer_options.sub_item_table, {
text = _("Disable C blitter"),
enabled_func = function()
return Blitbuffer.has_cblitbuffer
end,
checked_func = function()
return G_reader_settings:isTrue("dev_no_c_blitter")
end,
callback = function()
G_reader_settings:flipNilOrFalse("dev_no_c_blitter")
Blitbuffer:enableCBB(G_reader_settings:nilOrFalse("dev_no_c_blitter"))
end,
})
end
local Blitbuffer = require("ffi/blitbuffer")
table.insert(self.menu_items.developer_options.sub_item_table, {
text = _("Disable C blitter"),
enabled_func = function()
return Blitbuffer.has_cblitbuffer
end,
checked_func = function()
return G_reader_settings:isTrue("dev_no_c_blitter")
end,
callback = function()
G_reader_settings:flipNilOrFalse("dev_no_c_blitter")
Blitbuffer:enableCBB(G_reader_settings:nilOrFalse("dev_no_c_blitter"))
end,
})
if Device:hasEinkScreen() and Device:canHWDither() then
table.insert(self.menu_items.developer_options.sub_item_table, {
text = _("Disable HW dithering"),

@ -21,11 +21,10 @@ local SetDefaultsWidget = CenterContainer:extend{
}
function SetDefaultsWidget:init()
-- We're a CenterContainer, so handle our own stuff first
-- This would usually be passed to the constructor, as CenterContainer's paintTo does *NOT* set/update self.dimen...
self.dimen = Screen:getSize()
-- Don't refresh the FM behind us. May leave stray bits of overflowed InputDialog behind in the popout border space.
self.covers_fullscreen = true
CenterContainer.init(self)
-- Then deal with our child widgets and our internal variables
self.screen_width = Screen:getWidth()

@ -1,17 +1,17 @@
local BD = require("ui/bidi")
local ButtonDialog = require("ui/widget/buttondialog")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local Menu = require("ui/widget/menu")
local Screen = require("device").screen
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local lfs = require("libs/libkoreader-lfs")
local util = require("ffi/util")
local _ = require("gettext")
local T = util.template
local FileManagerShortcuts = InputContainer:extend{
local FileManagerShortcuts = WidgetContainer:extend{
folder_shortcuts = G_reader_settings:readSetting("folder_shortcuts", {}),
}

@ -13,8 +13,8 @@ local _ = require("gettext")
-- additionally handles a location stack for each visited page or
-- page view change (when scrolling in a same page)
local ReaderBack = EventListener:new{
location_stack = {},
local ReaderBack = EventListener:extend{
location_stack = nil, -- array
-- a limit not intended to be a practical limit but just a failsafe
max_stack = 5000,
}

@ -31,7 +31,7 @@ local DISPLAY_PREFIX = {
bookmark = "\u{F097}\u{2002}", -- "empty bookmark"
}
local ReaderBookmark = InputContainer:new{
local ReaderBookmark = InputContainer:extend{
bookmarks_items_per_page_default = 14,
bookmarks = nil,
}

@ -1,14 +1,13 @@
local ConfigDialog = require("ui/widget/configdialog")
local Device = require("device")
local Event = require("ui/event")
local Geom = require("ui/geometry")
local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local CreOptions = require("ui/data/creoptions")
local KoptOptions = require("ui/data/koptoptions")
local _ = require("gettext")
local ReaderConfig = InputContainer:new{
local ReaderConfig = InputContainer:extend{
last_panel_index = 1,
}
@ -20,7 +19,6 @@ function ReaderConfig:init()
end
self.configurable:loadDefaults(self.options)
if not self.dimen then self.dimen = Geom:new{} end
if Device:hasKeys() then
self.key_events = {
ShowConfigMenu = { {{"Press","AA"}}, doc = "show config dialog" },
@ -120,7 +118,6 @@ end
function ReaderConfig:onShowConfigMenu()
self.config_dialog = ConfigDialog:new{
dimen = self.dimen:copy(),
document = self.document,
ui = self.ui,
configurable = self.configurable,

@ -8,7 +8,7 @@ local logger = require("logger")
local T = require("ffi/util").template
local _ = require("gettext")
local ReaderCoptListener = EventListener:new{}
local ReaderCoptListener = EventListener:extend{}
local CRE_HEADER_DEFAULT_SIZE = 20

@ -5,15 +5,15 @@ local CenterContainer = require("ui/widget/container/centercontainer")
local Event = require("ui/event")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local InputContainer = require("ui/widget/container/inputcontainer")
local Math = require("optmath")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local VerticalGroup = require("ui/widget/verticalgroup")
local Device = require("device")
local Screen = Device.screen
local _ = require("gettext")
local ReaderCropping = InputContainer:new{}
local ReaderCropping = WidgetContainer:extend{}
function ReaderCropping:onPageCrop(mode)
self.ui:handleEvent(Event:new("CloseConfigMenu"))
@ -171,7 +171,9 @@ function ReaderCropping:setZoomMode(mode)
end
function ReaderCropping:onReadSettings(config)
self.document.bbox = config:readSetting("bbox")
if config:has("bbox") then
self.document.bbox = config:readSetting("bbox")
end
end
function ReaderCropping:onSaveSettings()

@ -2,15 +2,15 @@ local ConfirmBox = require("ui/widget/confirmbox")
local Device = require("device")
local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local SpinWidget = require("ui/widget/spinwidget")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local powerd = Device:getPowerDevice()
local _ = require("gettext")
local C_ = _.pgettext
local T = require("ffi/util").template
local ReaderDeviceStatus = InputContainer:new{
local ReaderDeviceStatus = WidgetContainer:extend{
battery_confirm_box = nil,
memory_confirm_box = nil,
}

@ -6,7 +6,6 @@ local DictQuickLookup = require("ui/widget/dictquicklookup")
local Event = require("ui/event")
local Geom = require("ui/geometry")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local JSON = require("json")
local KeyValuePage = require("ui/widget/keyvaluepage")
@ -16,6 +15,7 @@ local NetworkMgr = require("ui/network/manager")
local SortWidget = require("ui/widget/sortwidget")
local Trapper = require("ui/trapper")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local ffi = require("ffi")
local C = ffi.C
local ffiUtil = require("ffi/util")
@ -60,9 +60,9 @@ local function getIfosInDir(path)
return ifos
end
local ReaderDictionary = InputContainer:new{
local ReaderDictionary = WidgetContainer:extend{
data_dir = nil,
dict_window_list = {},
dict_window_list = nil, -- array
lookup_msg = _("Searching dictionary for:\n%1"),
}
@ -100,6 +100,7 @@ local function getDictionaryFixHtmlFunc(path)
end
function ReaderDictionary:init()
self.dict_window_list = {}
self.disable_lookup_history = G_reader_settings:isTrue("disable_lookup_history")
self.dicts_order = G_reader_settings:readSetting("dicts_order", {})
self.dicts_disabled = G_reader_settings:readSetting("dicts_disabled", {})
@ -156,7 +157,7 @@ function ReaderDictionary:init()
self:updateSdcvDictNamesOptions()
if not lookup_history then
lookup_history = LuaData:open(DataStorage:getSettingsDir() .. "/lookup_history.lua", { name = "LookupHistory" })
lookup_history = LuaData:open(DataStorage:getSettingsDir() .. "/lookup_history.lua", "LookupHistory")
end
end

@ -2,13 +2,13 @@ local BD = require("ui/bidi")
local Device = require("device")
local Geom = require("ui/geometry")
local IconWidget = require("ui/widget/iconwidget")
local InputContainer = require("ui/widget/container/inputcontainer")
local RightContainer = require("ui/widget/container/rightcontainer")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = Device.screen
local ReaderDogear = InputContainer:new{}
local ReaderDogear = WidgetContainer:extend{}
function ReaderDogear:init()
-- This image could be scaled for DPI (with scale_for_dpi=true, scale_factor=0.7),

@ -1,10 +1,10 @@
local Geom = require("ui/geometry")
local IconWidget = require("ui/widget/iconwidget")
local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = require("device").screen
local ReaderFlipping = InputContainer:new{
local ReaderFlipping = WidgetContainer:extend{
orig_reflow_mode = 0,
}

@ -19,7 +19,7 @@ local _ = require("gettext")
local C_ = _.pgettext
local optionsutil = require("ui/data/optionsutil")
local ReaderFont = InputContainer:new{
local ReaderFont = InputContainer:extend{
font_face = nil,
font_size = nil,
line_space_percent = nil,

@ -444,7 +444,7 @@ local ReaderFooter = WidgetContainer:extend{
height = Screen:scaleBySize(G_defaults:readSetting("DMINIBAR_CONTAINER_HEIGHT")),
horizontal_margin = Size.span.horizontal_default,
bottom_padding = Size.padding.tiny,
settings = {},
settings = nil, -- table
-- added to expose them to unit tests
textGeneratorMap = footerTextGeneratorMap,
}

@ -1,13 +1,12 @@
local Event = require("ui/event")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local SkimToWidget = require("ui/widget/skimtowidget")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local _ = require("gettext")
local T = require("ffi/util").template
local ReaderGoto = InputContainer:new{
}
local ReaderGoto = WidgetContainer:extend{}
function ReaderGoto:init()
self.ui.menu:registerToMainMenu(self)

@ -20,8 +20,7 @@ local C_ = _.pgettext
local T = require("ffi/util").template
local Screen = Device.screen
local ReaderHighlight = InputContainer:new{
}
local ReaderHighlight = InputContainer:extend{}
local function inside_box(pos, box)
if pos then

@ -2,10 +2,14 @@ local EventListener = require("ui/widget/eventlistener")
local DHINTCOUNT = G_defaults:readSetting("DHINTCOUNT")
local ReaderHinting = EventListener:new{
hinting_states = {}
local ReaderHinting = EventListener:extend{
hinting_states = nil, -- array
}
function ReaderHinting:init()
self.hinting_states = {}
end
function ReaderHinting:onHintPage()
if not self.view.hinting then return true end
for i=1, DHINTCOUNT do

@ -4,7 +4,7 @@ local ReaderZooming = require("apps/reader/modules/readerzooming")
local UIManager = require("ui/uimanager")
local util = require("util")
local ReaderKoptListener = EventListener:new{}
local ReaderKoptListener = EventListener:extend{}
function ReaderKoptListener:setZoomMode(zoom_mode)
if self.document.configurable.text_wrap == 1 then

@ -21,8 +21,8 @@ local _ = require("gettext")
local Screen = Device.screen
local T = ffiutil.template
local ReaderLink = InputContainer:new{
location_stack = {}
local ReaderLink = InputContainer:extend{
location_stack = nil, -- table, per-instance
}
function ReaderLink:init()
@ -154,7 +154,7 @@ function ReaderLink:addToMainMenu(menu_items)
-- insert table to main reader menu
menu_items.go_to_previous_location = {
text = _("Go back to previous location"),
enabled_func = function() return #self.location_stack > 0 end,
enabled_func = function() return self.location_stack and #self.location_stack > 0 end,
callback = function() self:onGoBackLink() end,
hold_callback = function(touchmenu_instance)
UIManager:show(ConfirmBox:new{

@ -13,10 +13,10 @@ local Screen = Device.screen
local _ = require("gettext")
local T = require("ffi/util").template
local ReaderMenu = InputContainer:new{
local ReaderMenu = InputContainer:extend{
tab_item_table = nil,
menu_items = {},
registered_widgets = {},
menu_items = nil, -- table, mandatory
registered_widgets = nil, -- array
}
function ReaderMenu:init()

@ -6,18 +6,18 @@ local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local InputContainer = require("ui/widget/container/inputcontainer")
local Menu = require("ui/widget/menu")
local MultiConfirmBox = require("ui/widget/multiconfirmbox")
local OverlapGroup = require("ui/widget/overlapgroup")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = Device.screen
local T = require("ffi/util").template
local _ = require("gettext")
local ReaderPageMap = InputContainer:new{
local ReaderPageMap = WidgetContainer:extend{
label_font_face = "ffont",
label_default_font_size = 14,
-- Black so it's readable (and non-gray-flashing on GloHD)

@ -27,7 +27,7 @@ local function copyPageState(page_state)
end
local ReaderPaging = InputContainer:new{
local ReaderPaging = InputContainer:extend{
pan_rate = 30, -- default 30 ops, will be adjusted in readerui
current_page = 0,
number_of_pages = 0,
@ -37,7 +37,7 @@ local ReaderPaging = InputContainer:new{
page_flipping_mode = false,
bookmark_flipping_mode = false,
flip_steps = {0,1,2,5,10,20,50,100},
flip_steps = {0, 1, 2, 5, 10, 20, 50, 100},
}
function ReaderPaging:init()

@ -2,7 +2,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("device")
local _ = require("gettext")
local ReaderPanning = InputContainer:new{
local ReaderPanning = InputContainer:extend{
-- defaults
panning_steps = {
normal = 50,

@ -39,12 +39,12 @@ local band = bit.band
it in explicit page turning. And use that xpointer for non-page-turning
rendering.
--]]
local ReaderRolling = InputContainer:new{
local ReaderRolling = InputContainer:extend{
pan_rate = 30, -- default 30 ops, will be adjusted in readerui
rendering_hash = 0,
current_pos = 0,
-- only used for page view mode
current_page= nil,
current_page = nil,
xpointer = nil,
panning_steps = ReaderPanning.panning_steps,
cre_top_bar_enabled = false,

@ -3,8 +3,8 @@ local Device = require("device")
local Event = require("ui/event")
local _ = require("gettext")
local ReaderRotation = InputContainer:new{
current_rotation = 0
local ReaderRotation = InputContainer:extend{
current_rotation = 0,
}
function ReaderRotation:init()

@ -1,7 +1,7 @@
local Device = require("device")
local Event = require("ui/event")
local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local time = require("ui/time")
local _ = require("gettext")
@ -16,7 +16,7 @@ local SCROLL_METHOD_CLASSIC = "classic"
local SCROLL_METHOD_TURBO = "turbo"
local SCROLL_METHOD_ON_RELEASE = "on_release"
local ReaderScrolling = InputContainer:new{
local ReaderScrolling = WidgetContainer:extend{
-- Available scrolling methods (make them available to other reader modules)
SCROLL_METHOD_CLASSIC = SCROLL_METHOD_CLASSIC,
SCROLL_METHOD_TURBO = SCROLL_METHOD_TURBO,
@ -221,9 +221,6 @@ function ReaderScrolling:applyScrollSettings()
end
function ReaderScrolling:setupTouchZones()
self.ges_events = {}
self.onGesture = nil
local zones = {
{
id = "inertial_scrolling_touch",

@ -3,10 +3,10 @@ local ButtonDialog = require("ui/widget/buttondialog")
local CheckButton = require("ui/widget/checkbutton")
local Device = require("device")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local Notification = require("ui/widget/notification")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local _ = require("gettext")
local Screen = Device.screen
@ -14,7 +14,7 @@ local T = require("ffi/util").template
local DGENERIC_ICON_SIZE = G_defaults:readSetting("DGENERIC_ICON_SIZE")
local ReaderSearch = InputContainer:new{
local ReaderSearch = WidgetContainer:extend{
direction = 0, -- 0 for search forward, 1 for search backward
case_insensitive = true, -- default to case insensitive

@ -4,22 +4,16 @@ local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
local Device = require("device")
local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local util = require("util")
local _ = require("gettext")
local T = require("ffi/util").template
local ReaderStatus = InputContainer:new {
local ReaderStatus = WidgetContainer:extend{
document = nil,
summary = {
rating = 0,
note = nil,
status = "",
modified = "",
},
enabled = true,
total_pages = 0
total_pages = 0,
}
function ReaderStatus:init()

@ -19,6 +19,7 @@ local TextBoxWidget = require("ui/widget/textboxwidget")
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 lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
local util = require("util")
@ -27,7 +28,7 @@ local Screen = Device.screen
local T = require("ffi/util").template
-- Simple widget for showing tweak info
local TweakInfoWidget = InputContainer:new{
local TweakInfoWidget = InputContainer:extend{
tweak = nil,
is_global_default = nil,
toggle_global_default_callback = function() end,
@ -226,7 +227,7 @@ end
-- Reader component for managing tweaks. The aggregated css_text
-- is actually requested from us and applied by ReaderTypeset
local ReaderStyleTweak = InputContainer:new{
local ReaderStyleTweak = WidgetContainer:extend{
tweaks_by_id = nil,
tweaks_table = nil, -- sub-menu items
nb_enabled_tweaks = 0, -- for use by main menu item

@ -2,11 +2,11 @@ local Blitbuffer = require("ffi/blitbuffer")
local Cache = require("cache")
local Device = require("device")
local Geom = require("ui/geometry")
local InputContainer = require("ui/widget/container/inputcontainer")
local Persist = require("persist")
local RenderImage = require("ui/renderimage")
local TileCacheItem = require("document/tilecacheitem")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Screen = Device.screen
local ffiutil = require("ffi/util")
local logger = require("logger")
@ -18,7 +18,7 @@ local _ = require("gettext")
-- It handles launching via the menu or Dispatcher/Gestures two fullscreen
-- widgets related to showing pages and thumbnails that will make use of
-- its services: BookMap and PageBrowser.
local ReaderThumbnail = InputContainer:new{}
local ReaderThumbnail = WidgetContainer:extend{}
function ReaderThumbnail:init()
if not Device:isTouchDevice() then

@ -20,15 +20,15 @@ local N_ = _.ngettext
local Screen = Device.screen
local T = require("ffi/util").template
local ReaderToc = InputContainer:new{
local ReaderToc = InputContainer:extend{
toc = nil,
toc_depth = nil,
ticks = nil,
ticks_flattened = nil,
ticks_flattened_filtered = nil,
collapsed_toc = {},
collapsed_toc = nil, -- table
collapse_depth = 2,
expanded_nodes = {},
expanded_nodes = nil, -- table
toc_menu_title = _("Table of contents"),
alt_toc_menu_title = _("Table of contents *"),
toc_items_per_page_default = 14,

@ -2,10 +2,10 @@ local BD = require("ui/bidi")
local ConfirmBox = require("ui/widget/confirmbox")
local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local Math = require("optmath")
local Notification = require("ui/widget/notification")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local lfs = require("libs/libkoreader-lfs")
local optionsutil = require("ui/data/optionsutil")
local _ = require("gettext")
@ -13,7 +13,7 @@ local C_ = _.pgettext
local Screen = require("device").screen
local T = require("ffi/util").template
local ReaderTypeset = InputContainer:new{
local ReaderTypeset = WidgetContainer:extend{
-- @translators This is style in the sense meant by CSS (cascading style sheets), relating to the layout and presentation of the document. See <https://en.wikipedia.org/wiki/CSS> for more information.
css_menu_title = C_("CSS", "Style"),
css = nil,

@ -2,9 +2,9 @@ local BD = require("ui/bidi")
local Device = require("device")
local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local MultiConfirmBox = require("ui/widget/multiconfirmbox")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local util = require("util")
local _ = require("gettext")
@ -12,7 +12,7 @@ local C_ = _.pgettext
local T = require("ffi/util").template
local Screen = Device.screen
local ReaderTypography = InputContainer:new{}
local ReaderTypography = WidgetContainer:extend{}
-- This is used to migrate old hyph settings, and to show the currently
-- used hyph dict language in the hyphenation menu.

@ -16,7 +16,7 @@ local T = require("ffi/util").template
-- and some `if NORM then` branches can be simplified.
local NORM = false
local ReaderUserHyph = WidgetContainer:new{
local ReaderUserHyph = WidgetContainer:extend{
-- return values from setUserHyphenationDict (crengine's UserHyphDict::init())
USER_DICT_RELOAD = 0,
USER_DICT_NOCHANGE = 1,

@ -28,28 +28,13 @@ local T = require("ffi/util").template
local ReaderView = OverlapGroup:extend{
document = nil,
view_modules = nil, -- array
-- single page state
state = {
page = nil,
pos = 0,
zoom = 1.0,
rotation = 0,
gamma = 1.0,
offset = nil,
bbox = nil,
},
state = nil, -- table
outer_page_color = Blitbuffer.gray(G_defaults:readSetting("DOUTER_PAGE_COLOR") / 15),
-- highlight with "lighten" or "underscore" or "strikeout" or "invert"
highlight = {
lighten_factor = G_reader_settings:readSetting("highlight_lighten_factor", 0.2),
note_mark = G_reader_settings:readSetting("highlight_note_marker"),
temp_drawer = "invert",
temp = {},
saved_drawer = "lighten",
saved = {},
indicator = nil, -- geom: non-touch highlight position indicator: {x = 50, y=50}
},
highlight = nil, -- table
highlight_visible = true,
note_mark_line_w = 3, -- side line thickness
note_mark_sign = nil,
@ -58,12 +43,9 @@ local ReaderView = OverlapGroup:extend{
-- PDF/DjVu continuous paging
page_scroll = nil,
page_bgcolor = Blitbuffer.gray(G_defaults:readSetting("DBACKGROUND_COLOR") / 15),
page_states = {},
page_states = nil, -- table
-- properties of the gap drawn between each page in scroll mode:
page_gap = {
-- color (0 = white, 8 = gray, 15 = black)
color = Blitbuffer.gray((G_reader_settings:readSetting("page_gap_color") or 8) / 15),
},
page_gap = nil, -- table
-- DjVu page rendering mode (used in djvu.c:drawPage())
render_mode = G_defaults:readSetting("DRENDER_MODE"), -- default to COLOR
-- Crengine view mode
@ -91,10 +73,30 @@ local ReaderView = OverlapGroup:extend{
function ReaderView:init()
self.view_modules = {}
-- fix recalculate from close document pageno
self.state.page = nil
-- Reset the various areas across documents
self.state = {
page = nil,
pos = 0,
zoom = 1.0,
rotation = 0,
gamma = 1.0,
offset = nil,
bbox = nil,
}
self.highlight = {
lighten_factor = G_reader_settings:readSetting("highlight_lighten_factor", 0.2),
note_mark = G_reader_settings:readSetting("highlight_note_marker"),
temp_drawer = "invert",
temp = {},
saved_drawer = "lighten",
saved = {},
indicator = nil, -- geom: non-touch highlight position indicator: {x = 50, y=50}
}
self.page_states = {}
self.page_gap = {
-- color (0 = white, 8 = gray, 15 = black)
color = Blitbuffer.gray((G_reader_settings:readSetting("page_gap_color") or 8) / 15),
}
self.visible_area = Geom:new{x = 0, y = 0, w = 0, h = 0}
self.page_area = Geom:new{x = 0, y = 0, w = 0, h = 0}
self.dim_area = Geom:new{x = 0, y = 0, w = 0, h = 0}
@ -103,6 +105,9 @@ function ReaderView:init()
self.emitHintPageEvent = function()
self.ui:handleEvent(Event:new("HintPage", self.hinting))
end
-- We've subclassed OverlapGroup, go through its init, because it does some funky stuff with self.dimen...
OverlapGroup.init(self)
end
function ReaderView:addWidgets()
@ -1071,8 +1076,7 @@ function ReaderView:getRenderModeMenuTable()
end
function ReaderView:onCloseDocument()
self.hinting = false
-- stop any in fly HintPage event
-- stop any pending HintPage event
UIManager:unschedule(self.emitHintPageEvent)
end

@ -31,7 +31,7 @@ function ReaderWikipedia:init()
self.wiki_languages = {}
self.ui.menu:registerToMainMenu(self)
if not wikipedia_history then
wikipedia_history = LuaData:open(DataStorage:getSettingsDir() .. "/wikipedia_history.lua", { name = "WikipediaHistory" })
wikipedia_history = LuaData:open(DataStorage:getSettingsDir() .. "/wikipedia_history.lua", "WikipediaHistory")
end
end

@ -14,9 +14,9 @@ local Input = Device.input
local Screen = Device.screen
local T = require("ffi/util").template
local ReaderZooming = InputContainer:new{
local ReaderZooming = InputContainer:extend{
zoom = 1.0,
available_zoom_modes = {
available_zoom_modes = { -- const
"page",
"pagewidth",
"pageheight",
@ -27,26 +27,26 @@ local ReaderZooming = InputContainer:new{
"rows",
"manual",
},
zoom_genus_to_mode = {
zoom_genus_to_mode = { -- const
[4] = "page",
[3] = "content",
[2] = "columns",
[1] = "rows",
[0] = "manual",
},
zoom_mode_to_genus = {
zoom_mode_to_genus = { -- const
page = 4,
content = 3,
columns = 2,
rows = 1,
manual = 0,
},
zoom_type_to_mode = {
zoom_type_to_mode = { -- const
[2] = "",
[1] = "width",
[0] = "height",
},
zoom_mode_to_type = {
zoom_mode_to_type = { -- const
[""] = 2,
width = 1,
height = 0,
@ -58,7 +58,7 @@ local ReaderZooming = InputContainer:new{
-- with overlap of zoom_overlap_h % (horizontally)
-- and zoom_overlap_v % (vertically).
kopt_zoom_factor = 1.5,
zoom_pan_settings = {
zoom_pan_settings = { -- const
"kopt_zoom_factor",
"zoom_overlap_h",
"zoom_overlap_v",
@ -71,7 +71,7 @@ local ReaderZooming = InputContainer:new{
zoom_direction_vertical = nil, -- true for column mode
current_page = 1,
rotation = 0,
paged_modes = {
paged_modes = { -- const
page = _("Zoom to fit page works best with page view."),
pageheight = _("Zoom to fit page height works best with page view."),
contentheight = _("Zoom to fit content height works best with page view."),

@ -66,9 +66,9 @@ local _ = require("gettext")
local Screen = require("device").screen
local T = ffiUtil.template
local ReaderUI = InputContainer:new{
local ReaderUI = InputContainer:extend{
name = "ReaderUI",
active_widgets = {},
active_widgets = nil, -- array
-- if we have a parent container, it must be referenced for now
dialog = nil,
@ -104,6 +104,8 @@ function ReaderUI:registerPostReadyCallback(callback)
end
function ReaderUI:init()
self.active_widgets = {}
-- cap screen refresh on pan to 2 refreshes per second
local pan_rate = Screen.low_pan_rate and 2.0 or 30.0

@ -8,11 +8,6 @@ local lru = require("ffi/lru")
local md5 = require("ffi/sha2").md5
local util = require("util")
local CanvasContext = require("document/canvascontext")
if CanvasContext.should_restrict_JIT then
jit.off(true, true)
end
local Cache = {
-- Cache configuration:
-- Max storage space, in bytes...

@ -9,12 +9,15 @@ local CacheItem = {
--- and the most common items we cache are Geom-like tables (i.e., 4 key-value pairs).
--- That's generally a low estimation, especially for larger tables, where memory allocation trickery may be happening.
function CacheItem:new(o)
function CacheItem:extend(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
-- NOTE: There's no object-specific initialization, the entirety of the new data *is* the table we pass to new.
-- We only keep the distinction as a matter of semantics, to differentiate class declarations from object instantiations.
CacheItem.new = CacheItem.extend
-- Called on eviction.
-- We generally use it to free C/FFI resources *immediately* (as opposed to relying on our Userdata/FFI finalizers to do it "later" on GC).

@ -67,7 +67,7 @@ local external = require("device/thirdparty"):new{
end,
}
local Device = Generic:new{
local Device = Generic:extend{
isAndroid = yes,
model = android.prop.product,
hasKeys = yes,
@ -111,21 +111,6 @@ local Device = Generic:new{
android.dictLookup(text, app, action)
end
end,
-- Android is very finicky, and the LuaJIT allocator has a tremendously hard time getting the system
-- to allocate memory for it in the very specific memory range it requires to store generated code (mcode).
-- Failure to do so at runtime (mcode_alloc) will *tank* performance
-- (much worse than if the JIT were simply disabled).
-- The first line of defense is left to android-luajit-launcher,
-- which will try to grab the full mcode region in one go right at startup.
-- The second line of defense is *this* flag, which disables the JIT in a few code-hungry modules,
-- but not necessarily performance critical ones, to hopefully limit the amount of mcode memory
-- required for those modules where it *really* matters (e.g., ffi/blitbuffer.lua).
-- This is also why we try to actually avoid entering actual loops in the Lua blitter on Android,
-- and instead attempt to do most of everything via the C implementation.
-- NOTE: Since https://github.com/koreader/android-luajit-launcher/pull/283, we've patched LuaJIT
-- to ensure that the initial mcode alloc works, and sticks around, which is why this is no longer enabled.
should_restrict_JIT = false,
}
function Device:init()

@ -34,7 +34,7 @@ local function isMassStorageSupported()
return true
end
local Cervantes = Generic:new{
local Cervantes = Generic:extend{
model = "Cervantes",
isCervantes = yes,
isAlwaysPortrait = yes,
@ -65,33 +65,33 @@ local Cervantes = Generic:new{
canHWInvert = yes,
}
-- Cervantes Touch
local CervantesTouch = Cervantes:new{
local CervantesTouch = Cervantes:extend{
model = "CervantesTouch",
display_dpi = 167,
hasFrontlight = no,
hasMultitouch = no,
}
-- Cervantes TouchLight / Fnac Touch Plus
local CervantesTouchLight = Cervantes:new{
local CervantesTouchLight = Cervantes:extend{
model = "CervantesTouchLight",
display_dpi = 167,
hasMultitouch = no,
}
-- Cervantes 2013 / Fnac Touch Light
local Cervantes2013 = Cervantes:new{
local Cervantes2013 = Cervantes:extend{
model = "Cervantes2013",
display_dpi = 212,
hasMultitouch = no,
--- @fixme: Possibly requires canHWInvert = no, as it seems to be based on a similar board as the Kobo Aura...
}
-- Cervantes 3 / Fnac Touch Light 2
local Cervantes3 = Cervantes:new{
local Cervantes3 = Cervantes:extend{
model = "Cervantes3",
display_dpi = 300,
hasMultitouch = no,
}
-- Cervantes 4
local Cervantes4 = Cervantes:new{
local Cervantes4 = Cervantes:extend{
model = "Cervantes4",
display_dpi = 300,
hasNaturalLight = yes,

@ -1,6 +1,6 @@
local Device = require("device")
local Event = require("ui/event")
local InputContainer = require("ui/widget/container/inputcontainer")
local EventListener = require("ui/widget/eventlistener")
local Notification = require("ui/widget/notification")
local Screen = Device.screen
local UIManager = require("ui/uimanager")
@ -8,7 +8,7 @@ local bit = require("bit")
local _ = require("gettext")
local T = require("ffi/util").template
local DeviceListener = InputContainer:new{}
local DeviceListener = EventListener:extend{}
local function _setSetting(name)
G_reader_settings:makeTrue(name)

@ -4,7 +4,7 @@ local logger = require("logger")
local function yes() return true end
local function no() return false end
local Device = Generic:new{
local Device = Generic:extend{
model = "dummy",
hasKeyboard = no,
hasKeys = no,

@ -20,7 +20,6 @@ local Device = {
charging_mode = false,
survive_screen_saver = false,
is_cover_closed = false,
should_restrict_JIT = false,
model = nil,
powerd = nil,
screen = nil,
@ -130,7 +129,7 @@ local Device = {
canExternalDictLookup = no,
}
function Device:new(o)
function Device:extend(o)
o = o or {}
setmetatable(o, self)
self.__index = self
@ -159,7 +158,6 @@ function Device:invertButtons()
end
function Device:init()
assert(self ~= nil)
if not self.screen then
error("screen/framebuffer must be implemented")
end

@ -73,12 +73,10 @@ function BasePowerD:beforeSuspend() end
function BasePowerD:afterResume() end
function BasePowerD:isFrontlightOn()
assert(self ~= nil)
return self.is_fl_on
end
function BasePowerD:_decideFrontlightState()
assert(self ~= nil)
assert(self.device:hasFrontlight())
self.is_fl_on = self:isFrontlightOnHW()
end
@ -88,7 +86,6 @@ function BasePowerD:isFrontlightOff()
end
function BasePowerD:frontlightIntensity()
assert(self ~= nil)
if not self.device:hasFrontlight() then return 0 end
if self:isFrontlightOff() then return 0 end
--- @note: We assume that nothing other than us will set the frontlight level,
@ -98,7 +95,6 @@ function BasePowerD:frontlightIntensity()
end
function BasePowerD:toggleFrontlight()
assert(self ~= nil)
if not self.device:hasFrontlight() then return false end
if self:isFrontlightOn() then
return self:turnOffFrontlight()
@ -108,7 +104,6 @@ function BasePowerD:toggleFrontlight()
end
function BasePowerD:turnOffFrontlight()
assert(self ~= nil)
if not self.device:hasFrontlight() then return end
if self:isFrontlightOff() then return false end
self:turnOffFrontlightHW()
@ -118,7 +113,6 @@ function BasePowerD:turnOffFrontlight()
end
function BasePowerD:turnOnFrontlight()
assert(self ~= nil)
if not self.device:hasFrontlight() then return end
if self:isFrontlightOn() then return false end
if self.fl_intensity == self.fl_min then return false end --- @fixme what the hell?
@ -129,7 +123,6 @@ function BasePowerD:turnOnFrontlight()
end
function BasePowerD:frontlightWarmth()
assert(self ~= nil)
if not self.device:hasNaturalLight() then
return 0
end

@ -63,6 +63,7 @@ local TWO_FINGER_TAP_DURATION_MS = 300
local HOLD_INTERVAL_MS = 500
local SWIPE_INTERVAL_MS = 900
-- This is used as a singleton by Input (itself used as a singleton).
local GestureDetector = {
-- must be initialized with the Input singleton class
input = nil,
@ -73,7 +74,7 @@ local GestureDetector = {
HOLD_INTERVAL_MS = HOLD_INTERVAL_MS,
SWIPE_INTERVAL_MS = SWIPE_INTERVAL_MS,
-- pinch/spread direction table
DIRECTION_TABLE = {
DIRECTION_TABLE = { -- const
east = "horizontal",
west = "horizontal",
north = "vertical",

@ -141,7 +141,7 @@ local function frameworkStopped()
end
end
local Kindle = Generic:new{
local Kindle = Generic:extend{
model = "Kindle",
isKindle = yes,
-- NOTE: We can cheat by adding a platform-specific entry here, because the only code that will check for this is here.
@ -411,7 +411,7 @@ function Kindle:ambientBrightnessLevel()
return 4
end
local Kindle2 = Kindle:new{
local Kindle2 = Kindle:extend{
model = "Kindle2",
isREAGL = no,
hasKeyboard = yes,
@ -424,7 +424,7 @@ local Kindle2 = Kindle:new{
supportsScreensaver = yes, -- The first ad-supported device was the K3
}
local KindleDXG = Kindle:new{
local KindleDXG = Kindle:extend{
model = "KindleDXG",
isREAGL = no,
hasKeyboard = yes,
@ -437,7 +437,7 @@ local KindleDXG = Kindle:new{
supportsScreensaver = yes, -- The first ad-supported device was the K3
}
local Kindle3 = Kindle:new{
local Kindle3 = Kindle:extend{
model = "Kindle3",
isREAGL = no,
hasKeyboard = yes,
@ -449,7 +449,7 @@ local Kindle3 = Kindle:new{
isSpecialOffers = hasSpecialOffers(),
}
local Kindle4 = Kindle:new{
local Kindle4 = Kindle:extend{
model = "Kindle4",
isREAGL = no,
hasKeys = yes,
@ -461,7 +461,7 @@ local Kindle4 = Kindle:new{
isSpecialOffers = hasSpecialOffers(),
}
local KindleTouch = Kindle:new{
local KindleTouch = Kindle:extend{
model = "KindleTouch",
isREAGL = no,
isTouchDevice = yes,
@ -469,7 +469,7 @@ local KindleTouch = Kindle:new{
touch_dev = "/dev/input/event3",
}
local KindlePaperWhite = Kindle:new{
local KindlePaperWhite = Kindle:extend{
model = "KindlePaperWhite",
isREAGL = no,
isTouchDevice = yes,
@ -479,7 +479,7 @@ local KindlePaperWhite = Kindle:new{
touch_dev = "/dev/input/event0",
}
local KindlePaperWhite2 = Kindle:new{
local KindlePaperWhite2 = Kindle:extend{
model = "KindlePaperWhite2",
isTouchDevice = yes,
hasFrontlight = yes,
@ -488,13 +488,13 @@ local KindlePaperWhite2 = Kindle:new{
touch_dev = "/dev/input/event1",
}
local KindleBasic = Kindle:new{
local KindleBasic = Kindle:extend{
model = "KindleBasic",
isTouchDevice = yes,
touch_dev = "/dev/input/event1",
}
local KindleVoyage = Kindle:new{
local KindleVoyage = Kindle:extend{
model = "KindleVoyage",
isTouchDevice = yes,
hasFrontlight = yes,
@ -504,7 +504,7 @@ local KindleVoyage = Kindle:new{
touch_dev = "/dev/input/event1",
}
local KindlePaperWhite3 = Kindle:new{
local KindlePaperWhite3 = Kindle:extend{
model = "KindlePaperWhite3",
isTouchDevice = yes,
hasFrontlight = yes,
@ -513,7 +513,7 @@ local KindlePaperWhite3 = Kindle:new{
touch_dev = "/dev/input/event1",
}
local KindleOasis = Kindle:new{
local KindleOasis = Kindle:extend{
model = "KindleOasis",
isTouchDevice = yes,
hasFrontlight = yes,
@ -529,7 +529,7 @@ local KindleOasis = Kindle:new{
touch_dev = "/dev/input/by-path/platform-imx-i2c.1-event",
}
local KindleOasis2 = Kindle:new{
local KindleOasis2 = Kindle:extend{
model = "KindleOasis2",
isZelda = yes,
isTouchDevice = yes,
@ -540,7 +540,7 @@ local KindleOasis2 = Kindle:new{
touch_dev = "/dev/input/by-path/platform-30a30000.i2c-event",
}
local KindleOasis3 = Kindle:new{
local KindleOasis3 = Kindle:extend{
model = "KindleOasis3",
isZelda = yes,
isTouchDevice = yes,
@ -553,13 +553,13 @@ local KindleOasis3 = Kindle:new{
touch_dev = "/dev/input/by-path/platform-30a30000.i2c-event",
}
local KindleBasic2 = Kindle:new{
local KindleBasic2 = Kindle:extend{
model = "KindleBasic2",
isTouchDevice = yes,
touch_dev = "/dev/input/event0",
}
local KindlePaperWhite4 = Kindle:new{
local KindlePaperWhite4 = Kindle:extend{
model = "KindlePaperWhite4",
isRex = yes,
isTouchDevice = yes,
@ -571,7 +571,7 @@ local KindlePaperWhite4 = Kindle:new{
touch_dev = "/dev/input/event2",
}
local KindleBasic3 = Kindle:new{
local KindleBasic3 = Kindle:extend{
model = "KindleBasic3",
isRex = yes,
-- NOTE: Apparently, the KT4 doesn't actually support the fancy nightmode waveforms, c.f., ko/#5076
@ -582,7 +582,7 @@ local KindleBasic3 = Kindle:new{
touch_dev = "/dev/input/event2",
}
local KindlePaperWhite5 = Kindle:new{
local KindlePaperWhite5 = Kindle:extend{
model = "KindlePaperWhite5",
isMTK = yes,
isTouchDevice = yes,
@ -599,7 +599,7 @@ local KindlePaperWhite5 = Kindle:new{
canDoSwipeAnimation = yes,
}
local KindleScribe = Kindle:new{
local KindleScribe = Kindle:extend{
model = "KindleScribe",
isMTK = yes,
isTouchDevice = yes,

@ -18,6 +18,7 @@ require("ffi/posix_h")
local function yes() return true end
local function no() return false end
local function NOP() return end
local function koboEnableWifi(toggle)
if toggle == true then
@ -131,7 +132,7 @@ local function getRTCName()
end
end
local Kobo = Generic:new{
local Kobo = Generic:extend{
model = "Kobo",
isKobo = yes,
isTouchDevice = yes, -- all of them are
@ -192,21 +193,21 @@ local Kobo = Generic:new{
}
-- Kobo Touch A/B:
local KoboTrilogyAB = Kobo:new{
local KoboTrilogyAB = Kobo:extend{
model = "Kobo_trilogy_AB",
touch_kobo_mk3_protocol = true,
hasKeys = yes,
hasMultitouch = no,
}
-- Kobo Touch C:
local KoboTrilogyC = Kobo:new{
local KoboTrilogyC = Kobo:extend{
model = "Kobo_trilogy_C",
hasKeys = yes,
hasMultitouch = no,
}
-- Kobo Mini:
local KoboPixie = Kobo:new{
local KoboPixie = Kobo:extend{
model = "Kobo_pixie",
display_dpi = 200,
hasMultitouch = no,
@ -215,7 +216,7 @@ local KoboPixie = Kobo:new{
}
-- Kobo Aura One:
local KoboDaylight = Kobo:new{
local KoboDaylight = Kobo:extend{
model = "Kobo_daylight",
hasFrontlight = yes,
touch_phoenix_protocol = true,
@ -229,8 +230,10 @@ local KoboDaylight = Kobo:new{
}
-- Kobo Aura H2O:
local KoboDahlia = Kobo:new{
local KoboDahlia = Kobo:extend{
model = "Kobo_dahlia",
canToggleChargingLED = no, -- Possibly weird interactions with Nickel
led_uses_channel_3 = true,
hasFrontlight = yes,
touch_phoenix_protocol = true,
-- There's no slot 0, the first finger gets assigned slot 1, and the second slot 2.
@ -243,7 +246,7 @@ local KoboDahlia = Kobo:new{
}
-- Kobo Aura HD:
local KoboDragon = Kobo:new{
local KoboDragon = Kobo:extend{
model = "Kobo_dragon",
hasFrontlight = yes,
hasMultitouch = no,
@ -251,7 +254,7 @@ local KoboDragon = Kobo:new{
}
-- Kobo Glo:
local KoboKraken = Kobo:new{
local KoboKraken = Kobo:extend{
model = "Kobo_kraken",
hasFrontlight = yes,
hasMultitouch = no,
@ -259,7 +262,7 @@ local KoboKraken = Kobo:new{
}
-- Kobo Aura:
local KoboPhoenix = Kobo:new{
local KoboPhoenix = Kobo:extend{
model = "Kobo_phoenix",
hasFrontlight = yes,
touch_phoenix_protocol = true,
@ -273,7 +276,7 @@ local KoboPhoenix = Kobo:new{
}
-- Kobo Aura H2O2:
local KoboSnow = Kobo:new{
local KoboSnow = Kobo:extend{
model = "Kobo_snow",
hasFrontlight = yes,
touch_snow_protocol = true,
@ -289,7 +292,7 @@ local KoboSnow = Kobo:new{
-- Kobo Aura H2O2, Rev2:
--- @fixme Check if the Clara fix actually helps here... (#4015)
local KoboSnowRev2 = Kobo:new{
local KoboSnowRev2 = Kobo:extend{
model = "Kobo_snow_r2",
isMk7 = yes,
hasFrontlight = yes,
@ -303,7 +306,7 @@ local KoboSnowRev2 = Kobo:new{
}
-- Kobo Aura second edition:
local KoboStar = Kobo:new{
local KoboStar = Kobo:extend{
model = "Kobo_star",
hasFrontlight = yes,
touch_phoenix_protocol = true,
@ -311,7 +314,7 @@ local KoboStar = Kobo:new{
}
-- Kobo Aura second edition, Rev 2:
local KoboStarRev2 = Kobo:new{
local KoboStarRev2 = Kobo:extend{
model = "Kobo_star_r2",
isMk7 = yes,
hasFrontlight = yes,
@ -320,7 +323,7 @@ local KoboStarRev2 = Kobo:new{
}
-- Kobo Glo HD:
local KoboAlyssum = Kobo:new{
local KoboAlyssum = Kobo:extend{
model = "Kobo_alyssum",
hasFrontlight = yes,
touch_phoenix_protocol = true,
@ -329,14 +332,14 @@ local KoboAlyssum = Kobo:new{
}
-- Kobo Touch 2.0:
local KoboPika = Kobo:new{
local KoboPika = Kobo:extend{
model = "Kobo_pika",
touch_phoenix_protocol = true,
main_finger_slot = 1,
}
-- Kobo Clara HD:
local KoboNova = Kobo:new{
local KoboNova = Kobo:extend{
model = "Kobo_nova",
isMk7 = yes,
canToggleChargingLED = yes,
@ -362,7 +365,7 @@ local KoboNova = Kobo:new{
-- i.e., this will affect KSM users.
-- c.f., https://github.com/koreader/koreader/pull/4414#issuecomment-449652335
-- There's also a CM_ROTARY_ENABLE command, but which seems to do as much nothing as the STATUS one...
local KoboFrost = Kobo:new{
local KoboFrost = Kobo:extend{
model = "Kobo_frost",
isMk7 = yes,
canToggleChargingLED = yes,
@ -387,7 +390,7 @@ local KoboFrost = Kobo:new{
-- Kobo Libra:
-- NOTE: Assume the same quirks as the Forma apply.
local KoboStorm = Kobo:new{
local KoboStorm = Kobo:extend{
model = "Kobo_storm",
isMk7 = yes,
canToggleChargingLED = yes,
@ -418,7 +421,7 @@ local KoboStorm = Kobo:new{
-- Kobo Nia:
--- @fixme: Mostly untested, assume it's Clara-ish for now.
local KoboLuna = Kobo:new{
local KoboLuna = Kobo:extend{
model = "Kobo_luna",
isMk7 = yes,
canToggleChargingLED = yes,
@ -428,7 +431,7 @@ local KoboLuna = Kobo:new{
}
-- Kobo Elipsa
local KoboEuropa = Kobo:new{
local KoboEuropa = Kobo:extend{
model = "Kobo_europa",
isSunxi = yes,
hasEclipseWfm = yes,
@ -448,7 +451,7 @@ local KoboEuropa = Kobo:new{
}
-- Kobo Sage
local KoboCadmus = Kobo:new{
local KoboCadmus = Kobo:extend{
model = "Kobo_cadmus",
isSunxi = yes,
hasEclipseWfm = yes,
@ -481,7 +484,7 @@ local KoboCadmus = Kobo:new{
}
-- Kobo Libra 2:
local KoboIo = Kobo:new{
local KoboIo = Kobo:extend{
model = "Kobo_io",
isMk7 = yes,
hasEclipseWfm = yes,
@ -513,7 +516,7 @@ local KoboIo = Kobo:new{
}
-- Kobo Clara 2E:
local KoboGoldfinch = Kobo:new{
local KoboGoldfinch = Kobo:extend{
model = "Kobo_goldfinch",
isMk7 = yes,
hasEclipseWfm = yes,
@ -682,15 +685,15 @@ function Kobo:init()
self.default_cpu_governor = getCPUGovernor(self.cpu_governor_knob)
-- NOP unsupported methods
if not self.default_cpu_governor then
self.performanceCPUGovernor = function() end
self.defaultCPUGovernor = function() end
self.performanceCPUGovernor = NOP
self.defaultCPUGovernor = NOP
end
-- And while we're on CPU-related endeavors...
self.cpu_count = self:isSMP() and getCPUCount() or 1
-- NOP unsupported methods
if self.cpu_count == 1 then
self.enableCPUCores = function() end
self.enableCPUCores = NOP
end
-- Automagically set this so we never have to remember to do it manually ;p
@ -742,6 +745,7 @@ function Kobo:init()
dodgy_rtc = dodgy_rtc,
}
-- Let generic properly setup the standard stuff
Generic.init(self)
-- Various HW Buttons, Switches & Synthetic NTX events
@ -768,14 +772,14 @@ function Kobo:init()
-- See if the device supports key repeat
if not self:getKeyRepeat() then
-- NOP unsupported methods
self.disableKeyRepeat = function() end
self.restoreKeyRepeat = function() end
self.disableKeyRepeat = NOP
self.restoreKeyRepeat = NOP
end
-- NOP unsupported methods
if not self:canToggleChargingLED() then
self.toggleChargingLED = function() end
self.setupChargingLED = function() end
self.toggleChargingLED = NOP
self.setupChargingLED = NOP
end
-- We have no way of querying the current state of the charging LED, so, start from scratch.
@ -1233,12 +1237,15 @@ function Kobo:toggleChargingLED(toggle)
-- In fact, Nickel itself doesn't provide this feature on said older devices
-- (when it does, it's an option in the Energy saving settings),
-- which is why we also limit ourselves to "true" on devices where this was tested.
-- FWIW, on older devices, the knob is at "/sys/devices/platform/pmic_light.1/lit".
-- c.f., drivers/misc/ntx_misc_light.c
local f = io.open("/sys/devices/platform/ntx_led/lit", "we")
if not f then
logger.err("cannot open /sys/devices/platform/ntx_led/lit for writing!")
return false
end
-- Relying on LFs is mildly more elegant than spamming f:flush() calls ;).
C.setlinebuf(f)
-- c.f., strace -fittTvyy -e trace=ioctl,file,signal,ipc,desc -s 256 -o /tmp/nickel.log -p $(pidof -s nickel) &
-- This was observed on a Forma, so I'm mildly hopeful that it's safe on other Mk. 7 devices ;).
@ -1247,38 +1254,13 @@ function Kobo:toggleChargingLED(toggle)
-- NOTE: Technically, Nickel forces a toggle off before that, too.
-- But since we do that on startup, it shouldn't be necessary here...
if self.led_uses_channel_3 then
f:write("ch 3")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 63")
f:flush()
f:write("ch 3\n", "cur 1\n", "dc 63\n")
end
f:write("ch 4")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 63")
f:flush()
f:write("ch 4\n", "cur 1\n", "dc 63\n")
else
f:write("ch 3")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 0")
f:flush()
f:write("ch 4")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 0")
f:flush()
f:write("ch 5")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 0")
f:flush()
for ch = 3, 5 do
f:write("ch " .. tostring(ch) .. "\n", "cur 1\n", "dc 0\n")
end
end
f:close()

@ -21,7 +21,7 @@ local function no() return false end
local ext_path = "/mnt/ext1/system/config/extensions.cfg"
local app_name = "koreader.app"
local PocketBook = Generic:new{
local PocketBook = Generic:extend{
model = "PocketBook",
isPocketBook = yes,
hasOTAUpdates = yes,
@ -407,7 +407,7 @@ local function landscape_ccw() return {
} end
-- PocketBook Mini (515)
local PocketBook515 = PocketBook:new{
local PocketBook515 = PocketBook:extend{
model = "PB515",
display_dpi = 200,
isTouchDevice = no,
@ -417,7 +417,7 @@ local PocketBook515 = PocketBook:new{
}
-- PocketBook Basic 4 (606)
local PocketBook606 = PocketBook:new{
local PocketBook606 = PocketBook:extend{
model = "PB606",
display_dpi = 212,
isTouchDevice = no,
@ -427,7 +427,7 @@ local PocketBook606 = PocketBook:new{
}
-- PocketBook Basic (611)
local PocketBook611 = PocketBook:new{
local PocketBook611 = PocketBook:extend{
model = "PB611",
display_dpi = 167,
isTouchDevice = no,
@ -437,7 +437,7 @@ local PocketBook611 = PocketBook:new{
}
-- PocketBook Basic (613)
local PocketBook613 = PocketBook:new{
local PocketBook613 = PocketBook:extend{
model = "PB613B",
display_dpi = 167,
isTouchDevice = no,
@ -448,7 +448,7 @@ local PocketBook613 = PocketBook:new{
}
-- PocketBook Basic 2 / Basic 3 (614/614W)
local PocketBook614W = PocketBook:new{
local PocketBook614W = PocketBook:extend{
model = "PB614W",
display_dpi = 167,
isTouchDevice = no,
@ -458,7 +458,7 @@ local PocketBook614W = PocketBook:new{
}
-- PocketBook Basic Lux / 615 Plus (615/615W)
local PocketBook615 = PocketBook:new{
local PocketBook615 = PocketBook:extend{
model = "PBBLux",
display_dpi = 212,
isTouchDevice = no,
@ -467,7 +467,7 @@ local PocketBook615 = PocketBook:new{
}
-- PocketBook Basic Lux 2 (616/616W)
local PocketBook616 = PocketBook:new{
local PocketBook616 = PocketBook:extend{
model = "PBBLux2",
display_dpi = 212,
isTouchDevice = no,
@ -476,7 +476,7 @@ local PocketBook616 = PocketBook:new{
}
-- PocketBook Basic Lux 3 (617)
local PocketBook617 = PocketBook:new{
local PocketBook617 = PocketBook:extend{
model = "PBBLux3",
display_dpi = 212,
isTouchDevice = no,
@ -486,47 +486,47 @@ local PocketBook617 = PocketBook:new{
}
-- PocketBook Touch (622)
local PocketBook622 = PocketBook:new{
local PocketBook622 = PocketBook:extend{
model = "PBTouch",
display_dpi = 167,
hasFrontlight = no,
}
-- PocketBook Touch Lux (623)
local PocketBook623 = PocketBook:new{
local PocketBook623 = PocketBook:extend{
model = "PBTouchLux",
display_dpi = 212,
}
-- PocketBook Basic Touch (624)
local PocketBook624 = PocketBook:new{
local PocketBook624 = PocketBook:extend{
model = "PBBasicTouch",
display_dpi = 167,
hasFrontlight = no,
}
-- PocketBook Basic Touch 2 (625)
local PocketBook625 = PocketBook:new{
local PocketBook625 = PocketBook:extend{
model = "PBBasicTouch2",
display_dpi = 167,
hasFrontlight = no,
}
-- PocketBook Touch Lux 2 / Touch Lux 3 (626)
local PocketBook626 = PocketBook:new{
local PocketBook626 = PocketBook:extend{
model = "PBLux3",
display_dpi = 212,
}
-- PocketBook Touch Lux 4 (627)
local PocketBook627 = PocketBook:new{
local PocketBook627 = PocketBook:extend{
model = "PBLux4",
display_dpi = 212,
isAlwaysPortrait = yes,
}
-- PocketBook Touch Lux 5 (628)
local PocketBook628 = PocketBook:new{
local PocketBook628 = PocketBook:extend{
model = "PBTouchLux5",
display_dpi = 212,
isAlwaysPortrait = yes,
@ -535,13 +535,13 @@ local PocketBook628 = PocketBook:new{
}
-- PocketBook Sense / Sense 2 (630)
local PocketBook630 = PocketBook:new{
local PocketBook630 = PocketBook:extend{
model = "PBSense",
display_dpi = 212,
}
-- PocketBook Touch HD / Touch HD 2 (631)
local PocketBook631 = PocketBook:new{
local PocketBook631 = PocketBook:extend{
model = "PBTouchHD",
display_dpi = 300,
-- see https://github.com/koreader/koreader/pull/6531#issuecomment-676629182
@ -549,7 +549,7 @@ local PocketBook631 = PocketBook:new{
}
-- PocketBook Touch HD Plus / Touch HD 3 (632)
local PocketBook632 = PocketBook:new{
local PocketBook632 = PocketBook:extend{
model = "PBTouchHDPlus",
display_dpi = 300,
isAlwaysPortrait = yes,
@ -558,7 +558,7 @@ local PocketBook632 = PocketBook:new{
}
-- PocketBook Color (633)
local PocketBook633 = PocketBook:new{
local PocketBook633 = PocketBook:extend{
model = "PBColor",
display_dpi = 300,
hasColorScreen = yes,
@ -568,25 +568,25 @@ local PocketBook633 = PocketBook:new{
}
-- PocketBook Aqua (640)
local PocketBook640 = PocketBook:new{
local PocketBook640 = PocketBook:extend{
model = "PBAqua",
display_dpi = 167,
}
-- PocketBook Aqua 2 (641)
local PocketBook641 = PocketBook:new{
local PocketBook641 = PocketBook:extend{
model = "PBAqua2",
display_dpi = 212,
}
-- PocketBook Ultra (650)
local PocketBook650 = PocketBook:new{
local PocketBook650 = PocketBook:extend{
model = "PBUltra",
display_dpi = 212,
}
-- PocketBook Era (700)
local PocketBook700 = PocketBook:new{
local PocketBook700 = PocketBook:extend{
model = "PB700",
display_dpi = 300,
isAlwaysPortrait = yes,
@ -594,7 +594,7 @@ local PocketBook700 = PocketBook:new{
}
-- PocketBook InkPad 3 (740)
local PocketBook740 = PocketBook:new{
local PocketBook740 = PocketBook:extend{
model = "PBInkPad3",
display_dpi = 300,
isAlwaysPortrait = yes,
@ -603,7 +603,7 @@ local PocketBook740 = PocketBook:new{
}
-- PocketBook InkPad 3 Pro (740_2)
local PocketBook740_2 = PocketBook:new{
local PocketBook740_2 = PocketBook:extend{
model = "PBInkPad3Pro",
display_dpi = 300,
isAlwaysPortrait = yes,
@ -620,7 +620,7 @@ local PocketBook740_2 = PocketBook:new{
}
-- PocketBook InkPad Color (741)
local PocketBook741 = PocketBook:new{
local PocketBook741 = PocketBook:extend{
model = "PBInkPadColor",
display_dpi = 300,
hasColorScreen = yes,
@ -635,7 +635,7 @@ function PocketBook741._fb_init(fb, finfo, vinfo)
end
-- PocketBook Color Lux (801)
local PocketBookColorLux = PocketBook:new{
local PocketBookColorLux = PocketBook:extend{
model = "PBColorLux",
display_dpi = 125,
hasColorScreen = yes,
@ -653,13 +653,13 @@ function PocketBookColorLux._fb_init(fb, finfo, vinfo)
end
-- PocketBook InkPad / InkPad 2 (840)
local PocketBook840 = PocketBook:new{
local PocketBook840 = PocketBook:extend{
model = "PBInkPad",
display_dpi = 250,
}
-- PocketBook InkPad Lite (970)
local PocketBook970 = PocketBook:new{
local PocketBook970 = PocketBook:extend{
model = "PB970",
display_dpi = 150,
isAlwaysPortrait = yes,
@ -667,7 +667,7 @@ local PocketBook970 = PocketBook:new{
}
-- PocketBook InkPad X (1040)
local PocketBook1040 = PocketBook:new{
local PocketBook1040 = PocketBook:extend{
model = "PB1040",
display_dpi = 227,
isAlwaysPortrait = yes,

@ -29,7 +29,7 @@ local wacom_scale_x = screen_width / wacom_width
local wacom_scale_y = screen_height / wacom_height
local isRm2, rm_model = getModel()
local Remarkable = Generic:new{
local Remarkable = Generic:extend{
isRemarkable = yes,
model = rm_model,
hasKeys = yes,
@ -47,7 +47,7 @@ local Remarkable = Generic:new{
home_dir = "/home/root",
}
local Remarkable1 = Remarkable:new{
local Remarkable1 = Remarkable:extend{
mt_width = 767, -- unscaled_size_check: ignore
mt_height = 1023, -- unscaled_size_check: ignore
input_wacom = "/dev/input/event0",
@ -70,7 +70,7 @@ function Remarkable1:adjustTouchEvent(ev, by)
end
end
local Remarkable2 = Remarkable:new{
local Remarkable2 = Remarkable:extend{
mt_width = 1403, -- unscaled_size_check: ignore
mt_height = 1871, -- unscaled_size_check: ignore
input_wacom = "/dev/input/event1",

@ -60,7 +60,7 @@ local external = require("device/thirdparty"):new{
end,
}
local Device = Generic:new{
local Device = Generic:extend{
model = "SDL",
isSDL = yes,
home_dir = os.getenv("XDG_DOCUMENTS_DIR") or os.getenv("HOME"),
@ -105,21 +105,21 @@ local Device = Generic:new{
window = G_reader_settings:readSetting("sdl_window", {}),
}
local AppImage = Device:new{
local AppImage = Device:extend{
model = "AppImage",
hasMultitouch = no,
hasOTAUpdates = yes,
isDesktop = yes,
}
local Desktop = Device:new{
local Desktop = Device:extend{
model = SDL.getPlatform(),
isDesktop = yes,
canRestart = notOSX,
hasExitOptions = notOSX,
}
local Emulator = Device:new{
local Emulator = Device:extend{
model = "Emulator",
isEmulator = yes,
hasBattery = yes,
@ -137,7 +137,7 @@ local Emulator = Device:new{
canStandby = no,
}
local UbuntuTouch = Device:new{
local UbuntuTouch = Device:extend{
model = "UbuntuTouch",
hasFrontlight = yes,
isDefaultFullscreen = yes,

@ -9,7 +9,7 @@ require("ffi/linux_input_h")
local function yes() return true end
local function no() return false end
local SonyPRSTUX = Generic:new{
local SonyPRSTUX = Generic:extend{
model = "Sony PRSTUX",
isSonyPRSTUX = yes,
hasKeys = yes,
@ -239,7 +239,7 @@ function SonyPRSTUX:setEventHandlers(UIManager)
end
-- For Sony PRS-T2
local SonyPRSTUX_T2 = SonyPRSTUX:new{
local SonyPRSTUX_T2 = SonyPRSTUX:extend{
isTouchDevice = yes,
hasKeys = yes,
hasFrontlight = no,

@ -21,7 +21,7 @@ WakeupMgr base class.
--]]
local WakeupMgr = {
dev_rtc = "/dev/rtc0", -- RTC device
_task_queue = {}, -- Table with epoch at which to schedule the task and the function to be scheduled.
_task_queue = nil, -- Table with epoch at which to schedule the task and the function to be scheduled.
rtc = RTC, -- The RTC implementation to use, defaults to the RTC module.
dodgy_rtc = false, -- If the RTC has trouble with timers further away than UINT16_MAX (e.g., on i.MX5).
}
@ -45,6 +45,10 @@ function WakeupMgr:new(o)
return o
end
function WakeupMgr:init()
self._task_queue = {}
end
-- This is a dummy task we use when working around i.MX5 RTC issues.
-- We need to be able to recognize it so that we can deal with it in removeTasks...
function WakeupMgr.DummyTaskCallback()

@ -5,13 +5,14 @@ in the so-called sidecar directory
]]
local DataStorage = require("datastorage")
local LuaSettings = require("luasettings")
local dump = require("dump")
local ffiutil = require("ffi/util")
local lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
local util = require("util")
local DocSettings = {}
local DocSettings = LuaSettings:extend{}
local HISTORY_DIR = DataStorage:getHistoryDir()
@ -102,18 +103,20 @@ end
-- @treturn DocSettings object
function DocSettings:open(docfile)
--- @todo (zijiehe): Remove history_path, use only sidecar.
local new = {}
new.history_file = self:getHistoryPath(docfile)
local sidecar = self:getSidecarDir(docfile)
-- NOTE: Beware, our new instance is new, but self is still DocSettings!
local new = DocSettings:extend{}
new.history_file = new:getHistoryPath(docfile)
local sidecar = new:getSidecarDir(docfile)
new.sidecar = sidecar
DocSettings:ensureSidecar(sidecar)
-- If there is a file which has a same name as the sidecar directory, or
-- the file system is read-only, we should not waste time to read it.
-- If there is a file which has a same name as the sidecar directory,
-- or the file system is read-only, we should not waste time to read it.
if lfs.attributes(sidecar, "mode") == "directory" then
-- New sidecar file name is metadata.{file last suffix}.lua. So we
-- can handle two files with only different suffixes.
new.sidecar_file = self:getSidecarFile(docfile)
-- New sidecar file name is metadata.{file last suffix}.lua.
-- So we can handle two files with only different suffixes.
new.sidecar_file = new:getSidecarFile(docfile)
new.legacy_sidecar_file = sidecar.."/"..
ffiutil.basename(docfile)..".lua"
end
@ -163,139 +166,7 @@ function DocSettings:open(docfile)
new.data = {}
end
return setmetatable(new, {__index = DocSettings})
end
--[[-- Reads a setting, optionally initializing it to a default.
If default is provided, and the key doesn't exist yet, it is initialized to default first.
This ensures both that the defaults are actually set if necessary,
and that the returned reference actually belongs to the DocSettings object straight away,
without requiring further interaction (e.g., saveSetting) from the caller.
This is mainly useful if the data type you want to retrieve/store is assigned/returned/passed by reference (e.g., a table),
and you never actually break that reference by assigning another one to the same variable, (by e.g., assigning it a new object).
c.f., https://www.lua.org/manual/5.1/manual.html#2.2
@param key The setting's key
@param default Initialization data (Optional)
]]
function DocSettings:readSetting(key, default)
-- No initialization data: legacy behavior
if not default then
return self.data[key]
end
if not self:has(key) then
self.data[key] = default
end
return self.data[key]
end
--- Saves a setting.
function DocSettings:saveSetting(key, value)
self.data[key] = value
return self
end
--- Deletes a setting.
function DocSettings:delSetting(key)
self.data[key] = nil
return self
end
--- Checks if setting exists.
function DocSettings:has(key)
return self.data[key] ~= nil
end
--- Checks if setting does not exist.
function DocSettings:hasNot(key)
return self.data[key] == nil
end
--- Checks if setting is `true` (boolean).
function DocSettings:isTrue(key)
return self.data[key] == true
end
--- Checks if setting is `false` (boolean).
function DocSettings:isFalse(key)
return self.data[key] == false
end
--- Checks if setting is `nil` or `true`.
function DocSettings:nilOrTrue(key)
return self:hasNot(key) or self:isTrue(key)
end
--- Checks if setting is `nil` or `false`.
function DocSettings:nilOrFalse(key)
return self:hasNot(key) or self:isFalse(key)
end
--- Flips `nil` or `true` to `false`, and `false` to `nil`.
--- e.g., a setting that defaults to true.
function DocSettings:flipNilOrTrue(key)
if self:nilOrTrue(key) then
self:saveSetting(key, false)
else
self:delSetting(key)
end
return self
end
--- Flips `nil` or `false` to `true`, and `true` to `nil`.
--- e.g., a setting that defaults to false.
function DocSettings:flipNilOrFalse(key)
if self:nilOrFalse(key) then
self:saveSetting(key, true)
else
self:delSetting(key)
end
return self
end
--- Flips a setting between `true` and `nil`.
function DocSettings:flipTrue(key)
if self:isTrue(key) then
self:delSetting(key)
else
self:saveSetting(key, true)
end
return self
end
--- Flips a setting between `false` and `nil`.
function DocSettings:flipFalse(key)
if self:isFalse(key) then
self:delSetting(key)
else
self:saveSetting(key, false)
end
return self
end
-- Unconditionally makes a boolean setting `true`.
function DocSettings:makeTrue(key)
self:saveSetting(key, true)
return self
end
-- Unconditionally makes a boolean setting `false`.
function DocSettings:makeFalse(key)
self:saveSetting(key, false)
return self
end
--- Toggles a boolean setting
function DocSettings:toggle(key)
if self:nilOrFalse(key) then
self:saveSetting(key, true)
else
self:saveSetting(key, false)
end
return self
return new
end
--- Serializes settings and writes them to `metadata.lua`.
@ -307,8 +178,7 @@ function DocSettings:flush()
return
end
-- If we can write to sidecar_file, we do not need to write to history_file
-- anymore.
-- If we can write to sidecar_file, we do not need to write to history_file anymore.
local serials = {}
if self.sidecar_file then
table.insert(serials, self.sidecar_file)
@ -322,11 +192,10 @@ function DocSettings:flush()
for _, f in ipairs(serials) do
local directory_updated = false
if lfs.attributes(f, "mode") == "file" then
-- As an additional safety measure (to the ffiutil.fsync* calls
-- used below), we only backup the file to .old when it has
-- not been modified in the last 60 seconds. This should ensure
-- in the case the fsync calls are not supported that the OS
-- may have itself sync'ed that file content in the meantime.
-- As an additional safety measure (to the ffiutil.fsync* calls used below),
-- we only backup the file to .old when it has not been modified in the last 60 seconds.
-- This should ensure in the case the fsync calls are not supported
-- that the OS may have itself sync'ed that file content in the meantime.
local mtime = lfs.attributes(f, "modification")
if mtime < os.time() - 60 then
logger.dbg("Rename ", f, " to ", f .. ".old")
@ -364,18 +233,13 @@ function DocSettings:flush()
end
end
function DocSettings:close()
self:flush()
end
function DocSettings:getFilePath()
return self.filepath
end
--- Purges (removes) sidecar directory.
function DocSettings:purge(full)
-- Remove any of the old ones we may consider as candidates
-- in DocSettings:open()
-- Remove any of the old ones we may consider as candidates in DocSettings:open()
if self.history_file then
os.remove(self.history_file)
os.remove(self.history_file .. ".old")
@ -385,12 +249,10 @@ function DocSettings:purge(full)
end
if lfs.attributes(self.sidecar, "mode") == "directory" then
if full then
-- Asked to remove all the content of this .sdr directory,
-- whether it's ours or not
-- Asked to remove all the content of this .sdr directory, whether it's ours or not
ffiutil.purgeDir(self.sidecar)
else
-- Only remove the files we know we may have created
-- with our usual names.
-- Only remove the files we know we may have created with our usual names.
for f in lfs.dir(self.sidecar) do
local fullpath = self.sidecar.."/"..f
local to_remove = false
@ -398,8 +260,8 @@ function DocSettings:purge(full)
-- Currently, we only create a single file in there,
-- named metadata.suffix.lua (ie. metadata.epub.lua),
-- with possibly backups named metadata.epub.lua.old and
-- metadata.epub.lua.old_dom20180528, so all sharing the
-- same base: self.sidecar_file
-- metadata.epub.lua.old_dom20180528,
-- so all sharing the same base: self.sidecar_file
if util.stringStartsWith(fullpath, self.sidecar_file) then
to_remove = true
end
@ -414,8 +276,8 @@ function DocSettings:purge(full)
os.remove(self.sidecar)
end
end
-- We should have meet the candidate we used and remove it above. But in
-- case we didn't, remove it
-- We should have meet the candidate we used and remove it above.
-- But in case we didn't, remove it.
if self.filepath and lfs.attributes(self.filepath, "mode") == "file" then
os.remove(self.filepath)
end

@ -14,7 +14,6 @@ Note: CanvasContext is a singleton and it is not thread safe.
local Mupdf = require("ffi/mupdf")
local CanvasContext = {
should_restrict_JIT = false,
is_color_rendering_enabled = false,
is_bgr = false,
}
@ -24,7 +23,6 @@ Initialize CanvasContext with settings from device.
The following key is required for a device object:
* should_restrict_JIT: bool
* hasBGRFrameBuffer: function() -> boolean
* screen: object with following methods:
* getWidth() -> int
@ -51,7 +49,6 @@ function CanvasContext:init(device)
self.isEmulator = device.isEmulator
self.isKindle = device.isKindle
self.isPocketBook = device.isPocketBook
self.should_restrict_JIT = device.should_restrict_JIT
self.hasSystemFonts = device.hasSystemFonts
self:setColorRenderingEnabled(device.screen:isColorEnabled())

@ -18,7 +18,7 @@ local time = require("ui/time")
-- engine can be initialized only once, on first document opened
local engine_initialized = false
local CreDocument = Document:new{
local CreDocument = Document:extend{
-- this is defined in kpvcrlib/crengine/crengine/include/lvdocview.h
SCROLL_VIEW_MODE = 0,
PAGE_VIEW_MODE = 1,
@ -49,7 +49,7 @@ local CreDocument = Document:new{
-- require one to set FreeSans as fallback to get its nicer glyphes, which
-- would override Noto Sans CJK good symbol glyphs with smaller ones
-- (Noto Sans & Serif do not have these symbol glyphs).
fallback_fonts = {
fallback_fonts = { -- const
"Noto Sans CJK SC",
"Noto Naskh Arabic",
"Noto Sans Devanagari UI",
@ -65,8 +65,8 @@ local CreDocument = Document:new{
provider_name = "Cool Reader Engine",
hide_nonlinear_flows = false,
flows = {},
page_in_flow = {},
flows = nil, -- table
page_in_flow = nil, -- table
last_linear_page = nil,
}
@ -147,6 +147,9 @@ function CreDocument:init()
self:updateColorRendering()
self:engineInit()
self.flows = {}
self.page_in_flow = {}
local file_type = string.lower(string.match(self.file, ".+%.([^.]+)"))
if file_type == "zip" then
-- NuPogodi, 20.05.12: read the content of zip-file
@ -331,9 +334,11 @@ function CreDocument:close()
end
-- Only exists if the call cache is enabled
--[[
if self._callCacheDestroy then
self._callCacheDestroy()
end
--]]
end
end
@ -1510,14 +1515,27 @@ function CreDocument:setupCallCache()
-- Stores the key for said current tag
self._current_call_cache_tag = nil
end
--[[
--- @note: If explicitly destroying the references to the caches is necessary to get their content collected by the GC,
--- then you have a ref leak to this Document instance somewhere,
--- c.f., https://github.com/koreader/koreader/pull/7634#discussion_r627820424
--- Keep in mind that a *lot* of ReaderUI modules keep a ref to document, so it may be fairly remote!
--- A good contender for issues like these would be references being stored in the class object instead
--- of in instance objects because of inheritance rules. c.f., https://github.com/koreader/koreader/pull/9586,
--- which got rid of a giant leak of every ReaderUI module via the active_widgets array...
--- A simple testing methodology is to create a dummy buffer alongside self.buffer in drawCurrentView,
--- push it to the global cache via _callCacheSet, and trace the BlitBuffer gc method in ffi/blitbuffer.lua.
--- You'll probably want to stick a pair of collectgarbage() calls somewhere in the UI loop
--- (e.g., at the coda of UIManager:close) to trip a GC pass earlier than the one in DocumentRegistry:openDocument.
--- (Keep in mind that, in UIManager:close, widget is still in scope inside the function,
--- so you'll have to close another widget to truly collect it (here, ReaderUI)).
self._callCacheDestroy = function()
--- @note: Explicitly destroying the references to the caches is apparently necessary to get their content collected by the GC...
--- c.f., https://github.com/koreader/koreader/pull/7634#discussion_r627820424
self._global_call_cache = nil
self._tag_list_call_cache = nil
self._tag_call_cache = nil
self._current_call_cache_tag = nil
end
--]]
-- global cache
self._callCacheGet = function(key)
return self._global_call_cache[key]

@ -2,7 +2,7 @@ local Blitbuffer = require("ffi/blitbuffer")
local Document = require("document/document")
local DrawContext = require("ffi/drawcontext")
local DjvuDocument = Document:new{
local DjvuDocument = Document:extend{
_document = false,
-- libdjvulibre manages its own additional cache, default value is hard written in c module.
is_djvu = true,

@ -45,6 +45,7 @@ local function computeCacheSlots()
end
end
-- NOTE: This is a singleton!
local DocCache = Cache:new{
slots = computeCacheSlots(),
size = computeCacheSize(),

@ -16,13 +16,15 @@ This is an abstract interface to a document
local Document = {
-- file name
file = nil,
-- engine instance
_document = nil,
links = {},
links = nil, -- table
GAMMA_NO_GAMMA = 1.0,
-- override bbox from orignal page's getUsedBBox
bbox = {},
bbox = nil, -- table
-- flag to show whether the document was opened successfully
is_open = false,
@ -40,10 +42,15 @@ local Document = {
}
function Document:new(from_o)
local o = from_o or {}
function Document:extend(subclass_prototype)
local o = subclass_prototype or {}
setmetatable(o, self)
self.__index = self
return o
end
function Document:new(o)
o = self:extend(o)
if o._init then o:_init() end
if o.init then o:init() end
return o
@ -51,7 +58,9 @@ end
-- base document initialization should be called on each document init
function Document:_init()
self.configurable = Configurable:new()
self.links = {}
self.bbox = {}
self.configurable = Configurable:new{}
self.info = {
-- whether the document is pageable
has_pages = false,

@ -23,8 +23,8 @@ function DocumentRegistry:addProvider(extension, mimetype, provider, weight)
})
self.filetype_provider[extension] = true
-- We regard the first extension registered for a mimetype as canonical.
-- Provided we order the calls to addProvider() correctly, that means
-- epub instead of epub3, etc.
-- Provided we order the calls to addProvider() correctly,
-- that means epub instead of epub3, etc.
self.mimetype_ext[mimetype] = self.mimetype_ext[mimetype] or extension
end

@ -10,7 +10,7 @@ local ffi = require("ffi")
local C = ffi.C
local pdf = nil
local PdfDocument = Document:new{
local PdfDocument = Document:extend{
_document = false,
is_pdf = true,
dc_null = DrawContext.new(),

@ -3,7 +3,7 @@ local DrawContext = require("ffi/drawcontext")
local CanvasContext = require("document/canvascontext")
local pic = nil
local PicDocument = Document:new{
local PicDocument = Document:extend{
_document = false,
is_pic = true,
dc_null = DrawContext.new(),

@ -3,7 +3,7 @@ local CacheItem = require("cacheitem")
local Persist = require("persist")
local logger = require("logger")
local TileCacheItem = CacheItem:new{}
local TileCacheItem = CacheItem:extend{}
function TileCacheItem:onFree()
logger.dbg("TileCacheItem: free blitbuffer", self.bb)

@ -1,5 +1,7 @@
--[[--
A simple serialization function which won't do uservalues, functions, or loops.
If we ever need a more full-featured variant, the consensus seems to be https://github.com/pkulchenko/serpent ;).
]]
local isUbuntuTouch = os.getenv("UBUNTU_APPLICATION_ISOLATION") ~= nil
@ -15,7 +17,8 @@ local function _serialize(what, outt, indent, max_lv, history, pairs_func)
return
end
if type(what) == "table" then
local datatype = type(what)
if datatype == "table" then
history = history or {}
for up, item in ipairs(history) do
if item == what then
@ -43,9 +46,9 @@ local function _serialize(what, outt, indent, max_lv, history, pairs_func)
insert(outt, string.rep(indent_prefix, indent))
end
insert(outt, "}")
elseif type(what) == "string" then
elseif datatype == "string" then
insert(outt, string.format("%q", what))
elseif type(what) == "number" then
elseif datatype == "number" then
if isUbuntuTouch then
--- @fixme The `SDL_CreateRenderer` function in Ubuntu touch somehow
-- use a strange locale that formats number like this: 1.10000000000000g+02
@ -55,11 +58,11 @@ local function _serialize(what, outt, indent, max_lv, history, pairs_func)
else
insert(outt, tostring(what))
end
elseif type(what) == "boolean" then
elseif datatype == "boolean" then
insert(outt, tostring(what))
elseif type(what) == "function" then
elseif datatype == "function" then
insert(outt, tostring(what))
elseif type(what) == "nil" then
elseif datatype == "nil" then
insert(outt, "nil")
end
end

@ -2,7 +2,7 @@
Language-specific handling module.
This module defines a somewhat generic system by which language-specific
plugins can improve KoReader's support for languages that are not close enough
plugins can improve KOReader's support for languages that are not close enough
to European languages to "just work".
This was originally designed to improve KoReader's Japanese support through the
@ -29,10 +29,10 @@ local _ = require("gettext")
-- plugins when reloading different viewers.
local PluginListSingleton = {}
local LanguageSupport = WidgetContainer:new({
local LanguageSupport = WidgetContainer:extend{
name = "language_support",
plugins = PluginListSingleton,
})
}
--[[--
Registers a new language-specific plugin with given language_code.

@ -3,31 +3,29 @@ Handles append-mostly data such as KOReader's bookmarks and dictionary search hi
]]
local LuaSettings = require("luasettings")
local dbg = require("dbg")
local dump = require("dump")
local lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
local util = require("util")
local LuaData = LuaSettings:new{
local LuaData = LuaSettings:extend{
name = "",
max_backups = 9,
}
--- Creates a new LuaData instance.
function LuaData:open(file_path, o) -- luacheck: ignore 312
if o and type(o) ~= "table" then
if dbg.is_on then
error("LuaData: got "..type(o)..", table expected")
else
o = {}
end
function LuaData:open(file_path, name)
-- Backwards compat, just in case...
if type(name) == "table" then
name = name.name
end
-- always initiate a new instance
-- careful, `o` is already a table so we use parentheses
self = LuaData:new(o)
local new = {file=file_path, data={}}
-- NOTE: Beware, our new instance is new, but self is still LuaData!
local new = LuaData:extend{
name = name,
file = file_path,
data = {},
}
-- Some magic to allow for self-describing function names:
-- We'll use data_env both as the environment when loading the data, *and* its metatable,
@ -40,7 +38,7 @@ function LuaData:open(file_path, o) -- luacheck: ignore 312
local data_env = {}
data_env.__index = data_env
setmetatable(data_env, data_env)
data_env[self.name.."Entry"] = function(table)
data_env[new.name.."Entry"] = function(table)
if table.index then
-- We've got a deleted setting, overwrite with nil and be done with it.
if not table.data then
@ -81,7 +79,7 @@ function LuaData:open(file_path, o) -- luacheck: ignore 312
end
end
if not ok then
for i=1, self.max_backups, 1 do
for i=1, new.max_backups, 1 do
local backup_file = new.file..".old."..i
if lfs.attributes(backup_file, "mode") == "file" then
ok, err = loadfile(backup_file, "t", data_env)
@ -97,7 +95,7 @@ function LuaData:open(file_path, o) -- luacheck: ignore 312
end
end
return setmetatable(new, {__index = self})
return new
end
--- Saves a setting.

@ -11,7 +11,7 @@ local isAndroid, android = pcall(require, "android")
local lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
local LuaDefaults = LuaSettings:new{
local LuaDefaults = LuaSettings:extend{
ro = nil, -- will contain the defaults.lua k/v pairs (const)
rw = nil, -- will only contain non-defaults user-modified k/v pairs
}
@ -19,7 +19,9 @@ local LuaDefaults = LuaSettings:new{
--- Opens a settings file.
function LuaDefaults:open(path)
local file_path = path or DataStorage:getDataDir() .. "/defaults.custom.lua"
local new = {file = file_path}
local new = LuaDefaults:extend{
file = file_path,
}
local ok, stored
-- File being absent and returning an empty table is a use case,
@ -57,7 +59,7 @@ function LuaDefaults:open(path)
error("Failed reading " .. defaults_path)
end
return setmetatable(new, {__index = LuaDefaults})
return new
end
--- Reads a setting, optionally initializing it to a default.
@ -161,11 +163,10 @@ function LuaDefaults:flush()
if not self.file then return end
local directory_updated = false
if lfs.attributes(self.file, "mode") == "file" then
-- As an additional safety measure (to the ffiutil.fsync* calls
-- used below), we only backup the file to .old when it has
-- not been modified in the last 60 seconds. This should ensure
-- in the case the fsync calls are not supported that the OS
-- may have itself sync'ed that file content in the meantime.
-- As an additional safety measure (to the ffiutil.fsync* calls used below),
-- we only backup the file to .old when it has not been modified in the last 60 seconds.
-- This should ensure in the case the fsync calls are not supported
-- that the OS may have itself sync'ed that file content in the meantime.
local mtime = lfs.attributes(self.file, "modification")
if mtime < os.time() - 60 then
os.rename(self.file, self.file .. ".old")

@ -9,16 +9,19 @@ local logger = require("logger")
local LuaSettings = {}
function LuaSettings:new(o)
function LuaSettings:extend(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
-- NOTE: Instances are created via open, so we do *NOT* implement a new method, to avoid confusion.
--- Opens a settings file.
function LuaSettings:open(file_path)
local new = {file=file_path}
local new = LuaSettings:extend{
file = file_path,
}
local ok, stored
-- File being absent and returning an empty table is a use case,
@ -41,13 +44,13 @@ function LuaSettings:open(file_path)
end
end
return setmetatable(new, {__index = LuaSettings})
return new
end
--- @todo DocSettings can return a LuaSettings to use following awesome features.
function LuaSettings:wrap(data)
local new = {data = type(data) == "table" and data or {}}
return setmetatable(new, {__index = LuaSettings})
return self:extend{
data = type(data) == "table" and data or {},
}
end
--[[--Reads child settings.
@ -66,7 +69,7 @@ end
-- result "b"
]]
function LuaSettings:child(key)
return LuaSettings:wrap(self:readSetting(key))
return self:wrap(self:readSetting(key))
end
--[[-- Reads a setting, optionally initializing it to a default.
@ -251,11 +254,10 @@ function LuaSettings:flush()
if not self.file then return end
local directory_updated = false
if lfs.attributes(self.file, "mode") == "file" then
-- As an additional safety measure (to the ffiutil.fsync* calls
-- used below), we only backup the file to .old when it has
-- not been modified in the last 60 seconds. This should ensure
-- in the case the fsync calls are not supported that the OS
-- may have itself sync'ed that file content in the meantime.
-- As an additional safety measure (to the ffiutil.fsync* calls used below),
-- we only backup the file to .old when it has not been modified in the last 60 seconds.
-- This should ensure in the case the fsync calls are not supported
-- that the OS may have itself sync'ed that file content in the meantime.
local mtime = lfs.attributes(self.file, "modification")
if mtime < os.time() - 60 then
os.rename(self.file, self.file .. ".old")

@ -89,7 +89,7 @@ function PluginLoader:loadPlugins()
if type(plugins_disabled) ~= "table" then
plugins_disabled = {}
end
--disable obsolete plugins
-- disable obsolete plugins
for element in pairs(OBSOLETE_PLUGINS) do
plugins_disabled[element] = true
end

@ -1,5 +1,6 @@
-- PluginShare is a table for plugins to exchange data between each other. Plugins should maintain
-- their own protocols.
-- PluginShare is a table for plugins to exchange data between each other.
-- It is a singleton, which will persist across views (and, as such, across plugins lifecycle).
-- Plugins should maintain their own protocols.
return {
backgroundJobs = {},
}

@ -9,6 +9,7 @@ local realpath = ffiutil.realpath
local history_file = joinPath(DataStorage:getDataDir(), "history.lua")
-- This is a singleton
local ReadHistory = {
hist = {},
last_read_time = 0,
@ -70,7 +71,6 @@ local function timeFirstOrdering(l, r)
end
function ReadHistory:_indexing(start)
assert(self ~= nil)
--- @todo (Hzj_jie): Use binary search to find an item when deleting it.
for i = start, #self.hist, 1 do
self.hist[i].index = i
@ -78,7 +78,6 @@ function ReadHistory:_indexing(start)
end
function ReadHistory:_sort()
assert(self ~= nil)
local autoremove_deleted_items_from_history =
not G_reader_settings:nilOrFalse("autoremove_deleted_items_from_history")
if autoremove_deleted_items_from_history then
@ -98,7 +97,6 @@ end
-- Reduces total count in hist list to a reasonable number by removing last
-- several items.
function ReadHistory:_reduce()
assert(self ~= nil)
while #self.hist > 500 do
table.remove(self.hist, #self.hist)
end
@ -106,7 +104,6 @@ end
-- Flushes current history table into file.
function ReadHistory:_flush()
assert(self ~= nil)
local content = {}
for _, v in ipairs(self.hist) do
table.insert(content, {
@ -115,15 +112,16 @@ function ReadHistory:_flush()
})
end
local f = io.open(history_file, "w")
f:write("return " .. dump(content) .. "\n")
ffiutil.fsyncOpenedFile(f) -- force flush to the storage device
f:close()
if f then
f:write("return " .. dump(content) .. "\n")
ffiutil.fsyncOpenedFile(f) -- force flush to the storage device
f:close()
end
end
--- Reads history table from file.
-- @treturn boolean true if the history_file has been updated and reloaded.
function ReadHistory:_read(force_read)
assert(self ~= nil)
local history_file_modification_time = lfs.attributes(history_file, "modification")
if history_file_modification_time == nil
or (not force_read and (history_file_modification_time <= self.last_read_time)) then
@ -142,7 +140,6 @@ end
-- Reads history from legacy history folder
function ReadHistory:_readLegacyHistory()
assert(self ~= nil)
local history_dir = DataStorage:getHistoryDir()
for f in lfs.dir(history_dir) do
local path = joinPath(history_dir, f)
@ -162,7 +159,6 @@ function ReadHistory:_readLegacyHistory()
end
function ReadHistory:_init()
assert(self ~= nil)
self:reload()
end
@ -199,7 +195,6 @@ function ReadHistory:getPreviousFile(current_file)
end
function ReadHistory:getFileByDirectory(directory, recursive)
assert(self ~= nil)
local real_path = realpath(directory)
for i=1, #self.hist do
local ipath = realpath(ffiutil.dirname(self.hist[i].file))
@ -232,7 +227,6 @@ function ReadHistory:fileSettingsPurged(path)
end
function ReadHistory:clearMissing()
assert(self ~= nil)
for i = #self.hist, 1, -1 do
if self.hist[i].file == nil or lfs.attributes(self.hist[i].file, "mode") ~= "file" then
self:removeItem(self.hist[i], i)
@ -242,7 +236,6 @@ function ReadHistory:clearMissing()
end
function ReadHistory:removeItemByPath(path)
assert(self ~= nil)
for i = #self.hist, 1, -1 do
if self.hist[i].file == path then
self:removeItem(self.hist[i])
@ -253,7 +246,6 @@ function ReadHistory:removeItemByPath(path)
end
function ReadHistory:updateItemByPath(old_path, new_path)
assert(self ~= nil)
for i = #self.hist, 1, -1 do
if self.hist[i].file == old_path then
self.hist[i].file = new_path
@ -273,7 +265,6 @@ function ReadHistory:updateItemByPath(old_path, new_path)
end
function ReadHistory:removeItem(item, idx)
assert(self ~= nil)
table.remove(self.hist, item.index or idx)
os.remove(DocSettings:getHistoryPath(item.file))
self:_indexing(item.index or idx)
@ -282,7 +273,6 @@ function ReadHistory:removeItem(item, idx)
end
function ReadHistory:addItem(file, ts)
assert(self ~= nil)
if file ~= nil and lfs.attributes(file, "mode") == "file" then
local now = ts or os.time()
table.insert(self.hist, 1, buildEntry(now, file))
@ -303,7 +293,6 @@ end
--- Reloads history from history_file.
-- @treturn boolean true if history_file has been updated and reload happened.
function ReadHistory:reload(force_read)
assert(self ~= nil)
if self:_read(force_read) then
self:_readLegacyHistory()
self:_sort()

@ -90,9 +90,6 @@ socketutil.SINK_TIMEOUT_CODE = "sink timeout" -- from our own socketutil
-- NOTE: Use os.time() for simplicity's sake (we don't really need subsecond precision).
-- LuaSocket itself is already using gettimeofday anyway (although it does the maths, like ffi/util's getTimestamp).
-- Proper etiquette would have everyone using clock_gettime(CLOCK_MONOTONIC) for this kind of stuff,
-- but it's a tad more annoying to use because it's stuffed in librt in old glibc versions,
-- and I have no idea what macOS & Android do with it (but it is POSIX). Plus, win32.
--- Custom version of `ltn12.sink.table` that honors total_timeout
function socketutil.table_sink(t)
if socketutil.total_timeout < 0 then

@ -213,7 +213,7 @@ local HgFSM = {
final = nil,
fsm_state = nil,
fsm_prev_states = {},
fsm_prev_states = nil, -- array
do_not_del_in_medial = false,

@ -48,7 +48,7 @@ end
local _stack
local IME = {
code_map = {},
code_map = nil, -- hash, mandatory
key_map = nil, -- input key to code map
keys_string = "abcdefghijklmnopqrstuvwxyz",
iter_map = nil, -- next code when using wildcard
@ -351,4 +351,4 @@ function IME:wrappedAddChars(inputbox, char)
end
end
return IME
return IME

@ -15,18 +15,15 @@ function HookContainer:new(o)
end
function HookContainer:_assertIsValidName(name)
assert(self ~= nil)
assert(type(name) == "string")
assert(string.len(name) > 0)
end
function HookContainer:_assertIsValidFunction(func)
assert(self ~= nil)
assert(type(func) == "function" or type(func) == "table")
end
function HookContainer:_assertIsValidFunctionOrNil(func)
assert(self ~= nil)
if func == nil then return end
self:_assertIsValidFunction(func)
end

@ -5,7 +5,7 @@ local _ = require("ffi/zeromq_h")
local czmq = ffi.load("libs/libczmq.so.1")
local filemq = ffi.load("libs/libfmq.so.1")
local FileMessageQueue = MessageQueue:new{
local FileMessageQueue = MessageQueue:extend{
client = nil,
server = nil,
}

@ -7,10 +7,15 @@ local czmq = ffi.load("libs/libczmq.so.1")
local MessageQueue = {}
function MessageQueue:new(o)
o = o or {}
function MessageQueue:extend(subclass_prototype)
local o = subclass_prototype or {}
setmetatable(o, self)
self.__index = self
return o
end
function MessageQueue:new(o)
o = self:extend(o)
if o.init then o:init() end
self.messages = {}
return o

@ -7,7 +7,7 @@ local zmq = ffi.load("libs/libzmq.so.4")
local czmq = ffi.load("libs/libczmq.so.1")
local C = ffi.C
local StreamMessageQueue = MessageQueue:new{
local StreamMessageQueue = MessageQueue:extend{
host = nil,
port = nil,
}

@ -1,15 +1,15 @@
local BD = require("ui/bidi")
local Device = require("device")
local Event = require("ui/event")
local EventListener = require("ui/widget/eventlistener")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local NetworkMgr = require("ui/network/manager")
local UIManager = require("ui/uimanager")
local logger = require("logger")
local _ = require("gettext")
local T = require("ffi/util").template
local NetworkListener = InputContainer:new{}
local NetworkListener = EventListener:extend{}
function NetworkListener:onToggleWifi()
if not NetworkMgr:isWifiOn() then

@ -11,7 +11,7 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local _ = require("gettext")
local SwitchPlugin = WidgetContainer:new()
local SwitchPlugin = WidgetContainer:extend{}
function SwitchPlugin:extend(o)
o = o or {}

@ -6,17 +6,12 @@ local bit = require("bit")
local Font = require("ui/font")
local Cache = require("cache")
local Blitbuffer = require("ffi/blitbuffer")
local Device = require("device")
local logger = require("logger")
local band = bit.band
local bor = bit.bor
local lshift = bit.lshift
if Device.should_restrict_JIT then
jit.off(true, true)
end
--[[
@TODO: all these functions should probably be methods on Face objects
]]--

@ -54,12 +54,14 @@ end
local Screensaver = {
screensaver_provider = {
gif = true,
jpg = true,
jpeg = true,
png = true,
gif = true,
svg = true,
tif = true,
tiff = true,
webp = true,
},
default_screensaver_message = _("Sleeping"),
}

@ -16,7 +16,7 @@ local Screen = Device.screen
local DEFAULT_FULL_REFRESH_COUNT = 6
-- there is only one instance of this
-- This is a singleton
local UIManager = {
-- trigger a full refresh when counter reaches FULL_REFRESH_COUNT
FULL_REFRESH_COUNT =
@ -60,6 +60,7 @@ function UIManager:init()
}
self.poweroff_action = function()
self._entered_poweroff_stage = true
logger.info("Powering off the device...")
Device.orig_rotation_mode = Device.screen:getRotationMode()
self:broadcastEvent(Event:new("Close"))
Screen:setRotationMode(Screen.ORIENTATION_PORTRAIT)
@ -74,6 +75,7 @@ function UIManager:init()
end
self.reboot_action = function()
self._entered_poweroff_stage = true
logger.info("Rebooting the device...")
Device.orig_rotation_mode = Device.screen:getRotationMode()
self:broadcastEvent(Event:new("Close"))
Screen:setRotationMode(Screen.ORIENTATION_PORTRAIT)

@ -12,7 +12,7 @@ local Screen = Device.screen
local Size = require("ui/size")
local UIManager = require("ui/uimanager")
local BBoxWidget = InputContainer:new{
local BBoxWidget = InputContainer:extend{
page_bbox = nil,
screen_bbox = nil,
linesize = Size.line.thick,

@ -23,6 +23,7 @@ local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local Widget = require("ui/widget/widget")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Input = Device.input
local Screen = Device.screen
local logger = require("logger")
@ -30,7 +31,7 @@ local util = require("util")
local _ = require("gettext")
-- BookMapRow (reused by PageBrowserWidget)
local BookMapRow = InputContainer:new{
local BookMapRow = WidgetContainer:extend{
width = nil,
height = nil,
pages_frame_border = Size.border.default,
@ -102,7 +103,7 @@ end
function BookMapRow:init()
local _mirroredUI = BD.mirroredUILayout()
self.dimen = Geom:new{ w = self.width, h = self.height }
self.dimen = Geom:new{ x = 0, y = 0, w = self.width, h = self.height }
-- Keep one span_height under baseline (frame bottom border) for indicators (current page, bookmarks)
self.pages_frame_height = self.height - self.span_height
@ -517,7 +518,7 @@ function BookMapRow:paintTo(bb, x, y)
end
-- BookMapWidget: shows a map of content, including TOC, boomarks, read pages, non-linear flows...
local BookMapWidget = InputContainer:new{
local BookMapWidget = InputContainer:extend{
title = _("Book map"),
-- Focus page: show the BookMapRow containing this page
-- in the middle of screen
@ -538,6 +539,8 @@ function BookMapWidget:init()
-- Compute non-settings-dependant sizes and options
self.dimen = Geom:new{
x = 0,
y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}

@ -32,37 +32,32 @@ local T = require("ffi/util").template
local stats_book = {}
--[[
--Save into sdr folder addtional section
-- Stored in the sidecar metadata, in a dedicated table:
["summary"] = {
["rating"] = 5,
["note"] = "Some text",
["status"] = "Reading"
["modified"] = "24.01.2016"
},]]
local BookStatusWidget = FocusManager:new{
local BookStatusWidget = FocusManager:extend{
padding = Size.padding.fullscreen,
settings = nil,
thumbnail = nil,
props = nil,
star = {},
summary = {
rating = nil,
note = nil,
status = "",
modified = "",
},
star = nil, -- Button
summary = nil, -- hash
}
function BookStatusWidget:init()
self.layout = {}
-- What a blank, full summary table should look like
local new_summary = {
rating = nil,
note = nil,
status = "",
modified = "",
}
if self.settings then
-- What a blank, full summary table should look like
local new_summary = {
rating = nil,
note = nil,
status = "",
modified = "",
}
local summary = self.settings:readSetting("summary")
-- Check if the summary table we get is a full one, or a minimal one from CoverMenu...
if summary then
@ -77,6 +72,8 @@ function BookStatusWidget:init()
else
self.summary = new_summary
end
else
self.summary = new_summary
end
self.total_pages = self.ui.document:getPageCount()
stats_book = self:getStats()

@ -35,7 +35,7 @@ local logger = require("logger")
local DGENERIC_ICON_SIZE = G_defaults:readSetting("DGENERIC_ICON_SIZE")
local Button = InputContainer:new{
local Button = InputContainer:extend{
text = nil, -- mandatory (unless icon is provided)
text_func = nil,
icon = nil,

@ -12,7 +12,7 @@ local UIManager = require("ui/uimanager")
local _ = require("gettext")
local Screen = require("device").screen
local ButtonDialog = InputContainer:new{
local ButtonDialog = InputContainer:extend{
buttons = nil,
tap_close_callback = nil,
alpha = nil, -- passed to MovableContainer

@ -16,7 +16,7 @@ local VerticalSpan = require("ui/widget/verticalspan")
local _ = require("gettext")
local Screen = Device.screen
local ButtonDialogTitle = InputContainer:new{
local ButtonDialogTitle = InputContainer:extend{
title = nil,
title_align = nil,
title_face = Font:getFace("x_smalltfont"),

@ -11,7 +11,7 @@ local UIManager = require("ui/uimanager")
local _ = require("gettext")
local Screen = Device.screen
local ButtonProgressWidget = FocusManager:new{
local ButtonProgressWidget = FocusManager:extend{
width = Screen:scaleBySize(216),
height = Size.item.height_default,
padding = Size.padding.small,

@ -10,7 +10,7 @@ local VerticalSpan = require("ui/widget/verticalspan")
local Geom = require("ui/geometry")
local Screen = Device.screen
local ButtonTable = FocusManager:new{
local ButtonTable = FocusManager:extend{
width = nil,
buttons = {
{

@ -27,7 +27,7 @@ local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local CheckButton = InputContainer:new{
local CheckButton = InputContainer:extend{
callback = nil,
hold_callback = nil,
checkable = true, -- empty space when false

@ -17,11 +17,11 @@ Example:
local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer")
local Font = require("ui/font")
local InputContainer = require("ui/widget/container/inputcontainer")
local OverlapGroup = require("ui/widget/overlapgroup")
local TextWidget = require("ui/widget/textwidget")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local CheckMark = InputContainer:new{
local CheckMark = WidgetContainer:extend{
checkable = true,
checked = false,
enabled = true,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save