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.
pull/9597/head
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{ local FileManager = InputContainer:extend{
title = _("KOReader"), title = _("KOReader"),
active_widgets = nil, -- array
root_path = lfs.currentdir(), root_path = lfs.currentdir(),
clipboard = nil, -- for single file operations clipboard = nil, -- for single file operations

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

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

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

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

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

@ -21,11 +21,10 @@ local SetDefaultsWidget = CenterContainer:extend{
} }
function SetDefaultsWidget:init() 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() self.dimen = Screen:getSize()
-- Don't refresh the FM behind us. May leave stray bits of overflowed InputDialog behind in the popout border space. -- Don't refresh the FM behind us. May leave stray bits of overflowed InputDialog behind in the popout border space.
self.covers_fullscreen = true self.covers_fullscreen = true
CenterContainer.init(self)
-- Then deal with our child widgets and our internal variables -- Then deal with our child widgets and our internal variables
self.screen_width = Screen:getWidth() self.screen_width = Screen:getWidth()

@ -1,17 +1,17 @@
local BD = require("ui/bidi") local BD = require("ui/bidi")
local ButtonDialog = require("ui/widget/buttondialog") local ButtonDialog = require("ui/widget/buttondialog")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog") local InputDialog = require("ui/widget/inputdialog")
local Menu = require("ui/widget/menu") local Menu = require("ui/widget/menu")
local Screen = require("device").screen local Screen = require("device").screen
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local lfs = require("libs/libkoreader-lfs") local lfs = require("libs/libkoreader-lfs")
local util = require("ffi/util") local util = require("ffi/util")
local _ = require("gettext") local _ = require("gettext")
local T = util.template local T = util.template
local FileManagerShortcuts = InputContainer:extend{ local FileManagerShortcuts = WidgetContainer:extend{
folder_shortcuts = G_reader_settings:readSetting("folder_shortcuts", {}), 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 -- additionally handles a location stack for each visited page or
-- page view change (when scrolling in a same page) -- page view change (when scrolling in a same page)
local ReaderBack = EventListener:new{ local ReaderBack = EventListener:extend{
location_stack = {}, location_stack = nil, -- array
-- a limit not intended to be a practical limit but just a failsafe -- a limit not intended to be a practical limit but just a failsafe
max_stack = 5000, max_stack = 5000,
} }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -27,7 +27,7 @@ local function copyPageState(page_state)
end end
local ReaderPaging = InputContainer:new{ local ReaderPaging = InputContainer:extend{
pan_rate = 30, -- default 30 ops, will be adjusted in readerui pan_rate = 30, -- default 30 ops, will be adjusted in readerui
current_page = 0, current_page = 0,
number_of_pages = 0, number_of_pages = 0,
@ -37,7 +37,7 @@ local ReaderPaging = InputContainer:new{
page_flipping_mode = false, page_flipping_mode = false,
bookmark_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() function ReaderPaging:init()

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

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

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

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

@ -3,10 +3,10 @@ local ButtonDialog = require("ui/widget/buttondialog")
local CheckButton = require("ui/widget/checkbutton") local CheckButton = require("ui/widget/checkbutton")
local Device = require("device") local Device = require("device")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog") local InputDialog = require("ui/widget/inputdialog")
local Notification = require("ui/widget/notification") local Notification = require("ui/widget/notification")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger") local logger = require("logger")
local _ = require("gettext") local _ = require("gettext")
local Screen = Device.screen 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 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 direction = 0, -- 0 for search forward, 1 for search backward
case_insensitive = true, -- default to case insensitive case_insensitive = true, -- default to case insensitive

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

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

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

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

@ -2,10 +2,10 @@ local BD = require("ui/bidi")
local ConfirmBox = require("ui/widget/confirmbox") local ConfirmBox = require("ui/widget/confirmbox")
local Event = require("ui/event") local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local Math = require("optmath") local Math = require("optmath")
local Notification = require("ui/widget/notification") 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 lfs = require("libs/libkoreader-lfs")
local optionsutil = require("ui/data/optionsutil") local optionsutil = require("ui/data/optionsutil")
local _ = require("gettext") local _ = require("gettext")
@ -13,7 +13,7 @@ local C_ = _.pgettext
local Screen = require("device").screen local Screen = require("device").screen
local T = require("ffi/util").template 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. -- @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_menu_title = C_("CSS", "Style"),
css = nil, css = nil,

@ -2,9 +2,9 @@ local BD = require("ui/bidi")
local Device = require("device") local Device = require("device")
local Event = require("ui/event") local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local MultiConfirmBox = require("ui/widget/multiconfirmbox") local MultiConfirmBox = require("ui/widget/multiconfirmbox")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger") local logger = require("logger")
local util = require("util") local util = require("util")
local _ = require("gettext") local _ = require("gettext")
@ -12,7 +12,7 @@ local C_ = _.pgettext
local T = require("ffi/util").template local T = require("ffi/util").template
local Screen = Device.screen 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 -- This is used to migrate old hyph settings, and to show the currently
-- used hyph dict language in the hyphenation menu. -- 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. -- and some `if NORM then` branches can be simplified.
local NORM = false local NORM = false
local ReaderUserHyph = WidgetContainer:new{ local ReaderUserHyph = WidgetContainer:extend{
-- return values from setUserHyphenationDict (crengine's UserHyphDict::init()) -- return values from setUserHyphenationDict (crengine's UserHyphDict::init())
USER_DICT_RELOAD = 0, USER_DICT_RELOAD = 0,
USER_DICT_NOCHANGE = 1, USER_DICT_NOCHANGE = 1,

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

@ -31,7 +31,7 @@ function ReaderWikipedia:init()
self.wiki_languages = {} self.wiki_languages = {}
self.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
if not wikipedia_history then 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
end end

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

@ -66,9 +66,9 @@ local _ = require("gettext")
local Screen = require("device").screen local Screen = require("device").screen
local T = ffiUtil.template local T = ffiUtil.template
local ReaderUI = InputContainer:new{ local ReaderUI = InputContainer:extend{
name = "ReaderUI", name = "ReaderUI",
active_widgets = {}, active_widgets = nil, -- array
-- if we have a parent container, it must be referenced for now -- if we have a parent container, it must be referenced for now
dialog = nil, dialog = nil,
@ -104,6 +104,8 @@ function ReaderUI:registerPostReadyCallback(callback)
end end
function ReaderUI:init() function ReaderUI:init()
self.active_widgets = {}
-- cap screen refresh on pan to 2 refreshes per second -- cap screen refresh on pan to 2 refreshes per second
local pan_rate = Screen.low_pan_rate and 2.0 or 30.0 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 md5 = require("ffi/sha2").md5
local util = require("util") local util = require("util")
local CanvasContext = require("document/canvascontext")
if CanvasContext.should_restrict_JIT then
jit.off(true, true)
end
local Cache = { local Cache = {
-- Cache configuration: -- Cache configuration:
-- Max storage space, in bytes... -- 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). --- 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. --- 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 {} o = o or {}
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
return o return o
end 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. -- 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). -- 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, end,
} }
local Device = Generic:new{ local Device = Generic:extend{
isAndroid = yes, isAndroid = yes,
model = android.prop.product, model = android.prop.product,
hasKeys = yes, hasKeys = yes,
@ -111,21 +111,6 @@ local Device = Generic:new{
android.dictLookup(text, app, action) android.dictLookup(text, app, action)
end end
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() function Device:init()

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

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

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

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

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

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

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

@ -18,6 +18,7 @@ require("ffi/posix_h")
local function yes() return true end local function yes() return true end
local function no() return false end local function no() return false end
local function NOP() return end
local function koboEnableWifi(toggle) local function koboEnableWifi(toggle)
if toggle == true then if toggle == true then
@ -131,7 +132,7 @@ local function getRTCName()
end end
end end
local Kobo = Generic:new{ local Kobo = Generic:extend{
model = "Kobo", model = "Kobo",
isKobo = yes, isKobo = yes,
isTouchDevice = yes, -- all of them are isTouchDevice = yes, -- all of them are
@ -192,21 +193,21 @@ local Kobo = Generic:new{
} }
-- Kobo Touch A/B: -- Kobo Touch A/B:
local KoboTrilogyAB = Kobo:new{ local KoboTrilogyAB = Kobo:extend{
model = "Kobo_trilogy_AB", model = "Kobo_trilogy_AB",
touch_kobo_mk3_protocol = true, touch_kobo_mk3_protocol = true,
hasKeys = yes, hasKeys = yes,
hasMultitouch = no, hasMultitouch = no,
} }
-- Kobo Touch C: -- Kobo Touch C:
local KoboTrilogyC = Kobo:new{ local KoboTrilogyC = Kobo:extend{
model = "Kobo_trilogy_C", model = "Kobo_trilogy_C",
hasKeys = yes, hasKeys = yes,
hasMultitouch = no, hasMultitouch = no,
} }
-- Kobo Mini: -- Kobo Mini:
local KoboPixie = Kobo:new{ local KoboPixie = Kobo:extend{
model = "Kobo_pixie", model = "Kobo_pixie",
display_dpi = 200, display_dpi = 200,
hasMultitouch = no, hasMultitouch = no,
@ -215,7 +216,7 @@ local KoboPixie = Kobo:new{
} }
-- Kobo Aura One: -- Kobo Aura One:
local KoboDaylight = Kobo:new{ local KoboDaylight = Kobo:extend{
model = "Kobo_daylight", model = "Kobo_daylight",
hasFrontlight = yes, hasFrontlight = yes,
touch_phoenix_protocol = true, touch_phoenix_protocol = true,
@ -229,8 +230,10 @@ local KoboDaylight = Kobo:new{
} }
-- Kobo Aura H2O: -- Kobo Aura H2O:
local KoboDahlia = Kobo:new{ local KoboDahlia = Kobo:extend{
model = "Kobo_dahlia", model = "Kobo_dahlia",
canToggleChargingLED = no, -- Possibly weird interactions with Nickel
led_uses_channel_3 = true,
hasFrontlight = yes, hasFrontlight = yes,
touch_phoenix_protocol = true, touch_phoenix_protocol = true,
-- There's no slot 0, the first finger gets assigned slot 1, and the second slot 2. -- 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: -- Kobo Aura HD:
local KoboDragon = Kobo:new{ local KoboDragon = Kobo:extend{
model = "Kobo_dragon", model = "Kobo_dragon",
hasFrontlight = yes, hasFrontlight = yes,
hasMultitouch = no, hasMultitouch = no,
@ -251,7 +254,7 @@ local KoboDragon = Kobo:new{
} }
-- Kobo Glo: -- Kobo Glo:
local KoboKraken = Kobo:new{ local KoboKraken = Kobo:extend{
model = "Kobo_kraken", model = "Kobo_kraken",
hasFrontlight = yes, hasFrontlight = yes,
hasMultitouch = no, hasMultitouch = no,
@ -259,7 +262,7 @@ local KoboKraken = Kobo:new{
} }
-- Kobo Aura: -- Kobo Aura:
local KoboPhoenix = Kobo:new{ local KoboPhoenix = Kobo:extend{
model = "Kobo_phoenix", model = "Kobo_phoenix",
hasFrontlight = yes, hasFrontlight = yes,
touch_phoenix_protocol = true, touch_phoenix_protocol = true,
@ -273,7 +276,7 @@ local KoboPhoenix = Kobo:new{
} }
-- Kobo Aura H2O2: -- Kobo Aura H2O2:
local KoboSnow = Kobo:new{ local KoboSnow = Kobo:extend{
model = "Kobo_snow", model = "Kobo_snow",
hasFrontlight = yes, hasFrontlight = yes,
touch_snow_protocol = true, touch_snow_protocol = true,
@ -289,7 +292,7 @@ local KoboSnow = Kobo:new{
-- Kobo Aura H2O2, Rev2: -- Kobo Aura H2O2, Rev2:
--- @fixme Check if the Clara fix actually helps here... (#4015) --- @fixme Check if the Clara fix actually helps here... (#4015)
local KoboSnowRev2 = Kobo:new{ local KoboSnowRev2 = Kobo:extend{
model = "Kobo_snow_r2", model = "Kobo_snow_r2",
isMk7 = yes, isMk7 = yes,
hasFrontlight = yes, hasFrontlight = yes,
@ -303,7 +306,7 @@ local KoboSnowRev2 = Kobo:new{
} }
-- Kobo Aura second edition: -- Kobo Aura second edition:
local KoboStar = Kobo:new{ local KoboStar = Kobo:extend{
model = "Kobo_star", model = "Kobo_star",
hasFrontlight = yes, hasFrontlight = yes,
touch_phoenix_protocol = true, touch_phoenix_protocol = true,
@ -311,7 +314,7 @@ local KoboStar = Kobo:new{
} }
-- Kobo Aura second edition, Rev 2: -- Kobo Aura second edition, Rev 2:
local KoboStarRev2 = Kobo:new{ local KoboStarRev2 = Kobo:extend{
model = "Kobo_star_r2", model = "Kobo_star_r2",
isMk7 = yes, isMk7 = yes,
hasFrontlight = yes, hasFrontlight = yes,
@ -320,7 +323,7 @@ local KoboStarRev2 = Kobo:new{
} }
-- Kobo Glo HD: -- Kobo Glo HD:
local KoboAlyssum = Kobo:new{ local KoboAlyssum = Kobo:extend{
model = "Kobo_alyssum", model = "Kobo_alyssum",
hasFrontlight = yes, hasFrontlight = yes,
touch_phoenix_protocol = true, touch_phoenix_protocol = true,
@ -329,14 +332,14 @@ local KoboAlyssum = Kobo:new{
} }
-- Kobo Touch 2.0: -- Kobo Touch 2.0:
local KoboPika = Kobo:new{ local KoboPika = Kobo:extend{
model = "Kobo_pika", model = "Kobo_pika",
touch_phoenix_protocol = true, touch_phoenix_protocol = true,
main_finger_slot = 1, main_finger_slot = 1,
} }
-- Kobo Clara HD: -- Kobo Clara HD:
local KoboNova = Kobo:new{ local KoboNova = Kobo:extend{
model = "Kobo_nova", model = "Kobo_nova",
isMk7 = yes, isMk7 = yes,
canToggleChargingLED = yes, canToggleChargingLED = yes,
@ -362,7 +365,7 @@ local KoboNova = Kobo:new{
-- i.e., this will affect KSM users. -- i.e., this will affect KSM users.
-- c.f., https://github.com/koreader/koreader/pull/4414#issuecomment-449652335 -- 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... -- 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", model = "Kobo_frost",
isMk7 = yes, isMk7 = yes,
canToggleChargingLED = yes, canToggleChargingLED = yes,
@ -387,7 +390,7 @@ local KoboFrost = Kobo:new{
-- Kobo Libra: -- Kobo Libra:
-- NOTE: Assume the same quirks as the Forma apply. -- NOTE: Assume the same quirks as the Forma apply.
local KoboStorm = Kobo:new{ local KoboStorm = Kobo:extend{
model = "Kobo_storm", model = "Kobo_storm",
isMk7 = yes, isMk7 = yes,
canToggleChargingLED = yes, canToggleChargingLED = yes,
@ -418,7 +421,7 @@ local KoboStorm = Kobo:new{
-- Kobo Nia: -- Kobo Nia:
--- @fixme: Mostly untested, assume it's Clara-ish for now. --- @fixme: Mostly untested, assume it's Clara-ish for now.
local KoboLuna = Kobo:new{ local KoboLuna = Kobo:extend{
model = "Kobo_luna", model = "Kobo_luna",
isMk7 = yes, isMk7 = yes,
canToggleChargingLED = yes, canToggleChargingLED = yes,
@ -428,7 +431,7 @@ local KoboLuna = Kobo:new{
} }
-- Kobo Elipsa -- Kobo Elipsa
local KoboEuropa = Kobo:new{ local KoboEuropa = Kobo:extend{
model = "Kobo_europa", model = "Kobo_europa",
isSunxi = yes, isSunxi = yes,
hasEclipseWfm = yes, hasEclipseWfm = yes,
@ -448,7 +451,7 @@ local KoboEuropa = Kobo:new{
} }
-- Kobo Sage -- Kobo Sage
local KoboCadmus = Kobo:new{ local KoboCadmus = Kobo:extend{
model = "Kobo_cadmus", model = "Kobo_cadmus",
isSunxi = yes, isSunxi = yes,
hasEclipseWfm = yes, hasEclipseWfm = yes,
@ -481,7 +484,7 @@ local KoboCadmus = Kobo:new{
} }
-- Kobo Libra 2: -- Kobo Libra 2:
local KoboIo = Kobo:new{ local KoboIo = Kobo:extend{
model = "Kobo_io", model = "Kobo_io",
isMk7 = yes, isMk7 = yes,
hasEclipseWfm = yes, hasEclipseWfm = yes,
@ -513,7 +516,7 @@ local KoboIo = Kobo:new{
} }
-- Kobo Clara 2E: -- Kobo Clara 2E:
local KoboGoldfinch = Kobo:new{ local KoboGoldfinch = Kobo:extend{
model = "Kobo_goldfinch", model = "Kobo_goldfinch",
isMk7 = yes, isMk7 = yes,
hasEclipseWfm = yes, hasEclipseWfm = yes,
@ -682,15 +685,15 @@ function Kobo:init()
self.default_cpu_governor = getCPUGovernor(self.cpu_governor_knob) self.default_cpu_governor = getCPUGovernor(self.cpu_governor_knob)
-- NOP unsupported methods -- NOP unsupported methods
if not self.default_cpu_governor then if not self.default_cpu_governor then
self.performanceCPUGovernor = function() end self.performanceCPUGovernor = NOP
self.defaultCPUGovernor = function() end self.defaultCPUGovernor = NOP
end end
-- And while we're on CPU-related endeavors... -- And while we're on CPU-related endeavors...
self.cpu_count = self:isSMP() and getCPUCount() or 1 self.cpu_count = self:isSMP() and getCPUCount() or 1
-- NOP unsupported methods -- NOP unsupported methods
if self.cpu_count == 1 then if self.cpu_count == 1 then
self.enableCPUCores = function() end self.enableCPUCores = NOP
end end
-- Automagically set this so we never have to remember to do it manually ;p -- 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, dodgy_rtc = dodgy_rtc,
} }
-- Let generic properly setup the standard stuff
Generic.init(self) Generic.init(self)
-- Various HW Buttons, Switches & Synthetic NTX events -- Various HW Buttons, Switches & Synthetic NTX events
@ -768,14 +772,14 @@ function Kobo:init()
-- See if the device supports key repeat -- See if the device supports key repeat
if not self:getKeyRepeat() then if not self:getKeyRepeat() then
-- NOP unsupported methods -- NOP unsupported methods
self.disableKeyRepeat = function() end self.disableKeyRepeat = NOP
self.restoreKeyRepeat = function() end self.restoreKeyRepeat = NOP
end end
-- NOP unsupported methods -- NOP unsupported methods
if not self:canToggleChargingLED() then if not self:canToggleChargingLED() then
self.toggleChargingLED = function() end self.toggleChargingLED = NOP
self.setupChargingLED = function() end self.setupChargingLED = NOP
end end
-- We have no way of querying the current state of the charging LED, so, start from scratch. -- 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 -- 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), -- (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. -- 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 -- c.f., drivers/misc/ntx_misc_light.c
local f = io.open("/sys/devices/platform/ntx_led/lit", "we") local f = io.open("/sys/devices/platform/ntx_led/lit", "we")
if not f then if not f then
logger.err("cannot open /sys/devices/platform/ntx_led/lit for writing!") logger.err("cannot open /sys/devices/platform/ntx_led/lit for writing!")
return false return false
end 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) & -- 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 ;). -- 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. -- NOTE: Technically, Nickel forces a toggle off before that, too.
-- But since we do that on startup, it shouldn't be necessary here... -- But since we do that on startup, it shouldn't be necessary here...
if self.led_uses_channel_3 then if self.led_uses_channel_3 then
f:write("ch 3") f:write("ch 3\n", "cur 1\n", "dc 63\n")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 63")
f:flush()
end end
f:write("ch 4") f:write("ch 4\n", "cur 1\n", "dc 63\n")
f:flush()
f:write("cur 1")
f:flush()
f:write("dc 63")
f:flush()
else else
f:write("ch 3") for ch = 3, 5 do
f:flush() f:write("ch " .. tostring(ch) .. "\n", "cur 1\n", "dc 0\n")
f:write("cur 1") end
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()
end end
f:close() f:close()

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

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

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

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

@ -21,7 +21,7 @@ WakeupMgr base class.
--]] --]]
local WakeupMgr = { local WakeupMgr = {
dev_rtc = "/dev/rtc0", -- RTC device 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. 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). 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 return o
end end
function WakeupMgr:init()
self._task_queue = {}
end
-- This is a dummy task we use when working around i.MX5 RTC issues. -- 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... -- We need to be able to recognize it so that we can deal with it in removeTasks...
function WakeupMgr.DummyTaskCallback() function WakeupMgr.DummyTaskCallback()

@ -5,13 +5,14 @@ in the so-called sidecar directory
]] ]]
local DataStorage = require("datastorage") local DataStorage = require("datastorage")
local LuaSettings = require("luasettings")
local dump = require("dump") local dump = require("dump")
local ffiutil = require("ffi/util") local ffiutil = require("ffi/util")
local lfs = require("libs/libkoreader-lfs") local lfs = require("libs/libkoreader-lfs")
local logger = require("logger") local logger = require("logger")
local util = require("util") local util = require("util")
local DocSettings = {} local DocSettings = LuaSettings:extend{}
local HISTORY_DIR = DataStorage:getHistoryDir() local HISTORY_DIR = DataStorage:getHistoryDir()
@ -102,18 +103,20 @@ end
-- @treturn DocSettings object -- @treturn DocSettings object
function DocSettings:open(docfile) function DocSettings:open(docfile)
--- @todo (zijiehe): Remove history_path, use only sidecar. --- @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 new.sidecar = sidecar
DocSettings:ensureSidecar(sidecar) DocSettings:ensureSidecar(sidecar)
-- If there is a file which has a same name as the sidecar directory, or -- If there is a file which has a same name as the sidecar directory,
-- the file system is read-only, we should not waste time to read it. -- or the file system is read-only, we should not waste time to read it.
if lfs.attributes(sidecar, "mode") == "directory" then if lfs.attributes(sidecar, "mode") == "directory" then
-- New sidecar file name is metadata.{file last suffix}.lua. So we -- New sidecar file name is metadata.{file last suffix}.lua.
-- can handle two files with only different suffixes. -- So we can handle two files with only different suffixes.
new.sidecar_file = self:getSidecarFile(docfile) new.sidecar_file = new:getSidecarFile(docfile)
new.legacy_sidecar_file = sidecar.."/".. new.legacy_sidecar_file = sidecar.."/"..
ffiutil.basename(docfile)..".lua" ffiutil.basename(docfile)..".lua"
end end
@ -163,139 +166,7 @@ function DocSettings:open(docfile)
new.data = {} new.data = {}
end end
return setmetatable(new, {__index = DocSettings}) return new
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
end end
--- Serializes settings and writes them to `metadata.lua`. --- Serializes settings and writes them to `metadata.lua`.
@ -307,8 +178,7 @@ function DocSettings:flush()
return return
end end
-- If we can write to sidecar_file, we do not need to write to history_file -- If we can write to sidecar_file, we do not need to write to history_file anymore.
-- anymore.
local serials = {} local serials = {}
if self.sidecar_file then if self.sidecar_file then
table.insert(serials, self.sidecar_file) table.insert(serials, self.sidecar_file)
@ -322,11 +192,10 @@ function DocSettings:flush()
for _, f in ipairs(serials) do for _, f in ipairs(serials) do
local directory_updated = false local directory_updated = false
if lfs.attributes(f, "mode") == "file" then if lfs.attributes(f, "mode") == "file" then
-- As an additional safety measure (to the ffiutil.fsync* calls -- As an additional safety measure (to the ffiutil.fsync* calls used below),
-- used below), we only backup the file to .old when it has -- we only backup the file to .old when it has not been modified in the last 60 seconds.
-- not been modified in the last 60 seconds. This should ensure -- This should ensure in the case the fsync calls are not supported
-- in the case the fsync calls are not supported that the OS -- that the OS may have itself sync'ed that file content in the meantime.
-- may have itself sync'ed that file content in the meantime.
local mtime = lfs.attributes(f, "modification") local mtime = lfs.attributes(f, "modification")
if mtime < os.time() - 60 then if mtime < os.time() - 60 then
logger.dbg("Rename ", f, " to ", f .. ".old") logger.dbg("Rename ", f, " to ", f .. ".old")
@ -364,18 +233,13 @@ function DocSettings:flush()
end end
end end
function DocSettings:close()
self:flush()
end
function DocSettings:getFilePath() function DocSettings:getFilePath()
return self.filepath return self.filepath
end end
--- Purges (removes) sidecar directory. --- Purges (removes) sidecar directory.
function DocSettings:purge(full) function DocSettings:purge(full)
-- Remove any of the old ones we may consider as candidates -- Remove any of the old ones we may consider as candidates in DocSettings:open()
-- in DocSettings:open()
if self.history_file then if self.history_file then
os.remove(self.history_file) os.remove(self.history_file)
os.remove(self.history_file .. ".old") os.remove(self.history_file .. ".old")
@ -385,12 +249,10 @@ function DocSettings:purge(full)
end end
if lfs.attributes(self.sidecar, "mode") == "directory" then if lfs.attributes(self.sidecar, "mode") == "directory" then
if full then if full then
-- Asked to remove all the content of this .sdr directory, -- Asked to remove all the content of this .sdr directory, whether it's ours or not
-- whether it's ours or not
ffiutil.purgeDir(self.sidecar) ffiutil.purgeDir(self.sidecar)
else else
-- Only remove the files we know we may have created -- Only remove the files we know we may have created with our usual names.
-- with our usual names.
for f in lfs.dir(self.sidecar) do for f in lfs.dir(self.sidecar) do
local fullpath = self.sidecar.."/"..f local fullpath = self.sidecar.."/"..f
local to_remove = false local to_remove = false
@ -398,8 +260,8 @@ function DocSettings:purge(full)
-- Currently, we only create a single file in there, -- Currently, we only create a single file in there,
-- named metadata.suffix.lua (ie. metadata.epub.lua), -- named metadata.suffix.lua (ie. metadata.epub.lua),
-- with possibly backups named metadata.epub.lua.old and -- with possibly backups named metadata.epub.lua.old and
-- metadata.epub.lua.old_dom20180528, so all sharing the -- metadata.epub.lua.old_dom20180528,
-- same base: self.sidecar_file -- so all sharing the same base: self.sidecar_file
if util.stringStartsWith(fullpath, self.sidecar_file) then if util.stringStartsWith(fullpath, self.sidecar_file) then
to_remove = true to_remove = true
end end
@ -414,8 +276,8 @@ function DocSettings:purge(full)
os.remove(self.sidecar) os.remove(self.sidecar)
end end
end end
-- We should have meet the candidate we used and remove it above. But in -- We should have meet the candidate we used and remove it above.
-- case we didn't, remove it -- But in case we didn't, remove it.
if self.filepath and lfs.attributes(self.filepath, "mode") == "file" then if self.filepath and lfs.attributes(self.filepath, "mode") == "file" then
os.remove(self.filepath) os.remove(self.filepath)
end end

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

@ -18,7 +18,7 @@ local time = require("ui/time")
-- engine can be initialized only once, on first document opened -- engine can be initialized only once, on first document opened
local engine_initialized = false local engine_initialized = false
local CreDocument = Document:new{ local CreDocument = Document:extend{
-- this is defined in kpvcrlib/crengine/crengine/include/lvdocview.h -- this is defined in kpvcrlib/crengine/crengine/include/lvdocview.h
SCROLL_VIEW_MODE = 0, SCROLL_VIEW_MODE = 0,
PAGE_VIEW_MODE = 1, 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 -- require one to set FreeSans as fallback to get its nicer glyphes, which
-- would override Noto Sans CJK good symbol glyphs with smaller ones -- would override Noto Sans CJK good symbol glyphs with smaller ones
-- (Noto Sans & Serif do not have these symbol glyphs). -- (Noto Sans & Serif do not have these symbol glyphs).
fallback_fonts = { fallback_fonts = { -- const
"Noto Sans CJK SC", "Noto Sans CJK SC",
"Noto Naskh Arabic", "Noto Naskh Arabic",
"Noto Sans Devanagari UI", "Noto Sans Devanagari UI",
@ -65,8 +65,8 @@ local CreDocument = Document:new{
provider_name = "Cool Reader Engine", provider_name = "Cool Reader Engine",
hide_nonlinear_flows = false, hide_nonlinear_flows = false,
flows = {}, flows = nil, -- table
page_in_flow = {}, page_in_flow = nil, -- table
last_linear_page = nil, last_linear_page = nil,
} }
@ -147,6 +147,9 @@ function CreDocument:init()
self:updateColorRendering() self:updateColorRendering()
self:engineInit() self:engineInit()
self.flows = {}
self.page_in_flow = {}
local file_type = string.lower(string.match(self.file, ".+%.([^.]+)")) local file_type = string.lower(string.match(self.file, ".+%.([^.]+)"))
if file_type == "zip" then if file_type == "zip" then
-- NuPogodi, 20.05.12: read the content of zip-file -- NuPogodi, 20.05.12: read the content of zip-file
@ -331,9 +334,11 @@ function CreDocument:close()
end end
-- Only exists if the call cache is enabled -- Only exists if the call cache is enabled
--[[
if self._callCacheDestroy then if self._callCacheDestroy then
self._callCacheDestroy() self._callCacheDestroy()
end end
--]]
end end
end end
@ -1510,14 +1515,27 @@ function CreDocument:setupCallCache()
-- Stores the key for said current tag -- Stores the key for said current tag
self._current_call_cache_tag = nil self._current_call_cache_tag = nil
end 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() 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._global_call_cache = nil
self._tag_list_call_cache = nil self._tag_list_call_cache = nil
self._tag_call_cache = nil self._tag_call_cache = nil
self._current_call_cache_tag = nil self._current_call_cache_tag = nil
end end
--]]
-- global cache -- global cache
self._callCacheGet = function(key) self._callCacheGet = function(key)
return self._global_call_cache[key] return self._global_call_cache[key]

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

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

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

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

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

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

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

@ -1,5 +1,7 @@
--[[-- --[[--
A simple serialization function which won't do uservalues, functions, or loops. 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 local isUbuntuTouch = os.getenv("UBUNTU_APPLICATION_ISOLATION") ~= nil
@ -15,7 +17,8 @@ local function _serialize(what, outt, indent, max_lv, history, pairs_func)
return return
end end
if type(what) == "table" then local datatype = type(what)
if datatype == "table" then
history = history or {} history = history or {}
for up, item in ipairs(history) do for up, item in ipairs(history) do
if item == what then 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)) insert(outt, string.rep(indent_prefix, indent))
end end
insert(outt, "}") insert(outt, "}")
elseif type(what) == "string" then elseif datatype == "string" then
insert(outt, string.format("%q", what)) insert(outt, string.format("%q", what))
elseif type(what) == "number" then elseif datatype == "number" then
if isUbuntuTouch then if isUbuntuTouch then
--- @fixme The `SDL_CreateRenderer` function in Ubuntu touch somehow --- @fixme The `SDL_CreateRenderer` function in Ubuntu touch somehow
-- use a strange locale that formats number like this: 1.10000000000000g+02 -- 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 else
insert(outt, tostring(what)) insert(outt, tostring(what))
end end
elseif type(what) == "boolean" then elseif datatype == "boolean" then
insert(outt, tostring(what)) insert(outt, tostring(what))
elseif type(what) == "function" then elseif datatype == "function" then
insert(outt, tostring(what)) insert(outt, tostring(what))
elseif type(what) == "nil" then elseif datatype == "nil" then
insert(outt, "nil") insert(outt, "nil")
end end
end end

@ -2,7 +2,7 @@
Language-specific handling module. Language-specific handling module.
This module defines a somewhat generic system by which language-specific 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". to European languages to "just work".
This was originally designed to improve KoReader's Japanese support through the This was originally designed to improve KoReader's Japanese support through the
@ -29,10 +29,10 @@ local _ = require("gettext")
-- plugins when reloading different viewers. -- plugins when reloading different viewers.
local PluginListSingleton = {} local PluginListSingleton = {}
local LanguageSupport = WidgetContainer:new({ local LanguageSupport = WidgetContainer:extend{
name = "language_support", name = "language_support",
plugins = PluginListSingleton, plugins = PluginListSingleton,
}) }
--[[-- --[[--
Registers a new language-specific plugin with given language_code. 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 LuaSettings = require("luasettings")
local dbg = require("dbg")
local dump = require("dump") local dump = require("dump")
local lfs = require("libs/libkoreader-lfs") local lfs = require("libs/libkoreader-lfs")
local logger = require("logger") local logger = require("logger")
local util = require("util") local util = require("util")
local LuaData = LuaSettings:new{ local LuaData = LuaSettings:extend{
name = "", name = "",
max_backups = 9, max_backups = 9,
} }
--- Creates a new LuaData instance. --- Creates a new LuaData instance.
function LuaData:open(file_path, o) -- luacheck: ignore 312 function LuaData:open(file_path, name)
if o and type(o) ~= "table" then -- Backwards compat, just in case...
if dbg.is_on then if type(name) == "table" then
error("LuaData: got "..type(o)..", table expected") name = name.name
else
o = {}
end
end 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: -- 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, -- 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 = {} local data_env = {}
data_env.__index = data_env data_env.__index = data_env
setmetatable(data_env, 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 if table.index then
-- We've got a deleted setting, overwrite with nil and be done with it. -- We've got a deleted setting, overwrite with nil and be done with it.
if not table.data then if not table.data then
@ -81,7 +79,7 @@ function LuaData:open(file_path, o) -- luacheck: ignore 312
end end
end end
if not ok then 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 local backup_file = new.file..".old."..i
if lfs.attributes(backup_file, "mode") == "file" then if lfs.attributes(backup_file, "mode") == "file" then
ok, err = loadfile(backup_file, "t", data_env) ok, err = loadfile(backup_file, "t", data_env)
@ -97,7 +95,7 @@ function LuaData:open(file_path, o) -- luacheck: ignore 312
end end
end end
return setmetatable(new, {__index = self}) return new
end end
--- Saves a setting. --- Saves a setting.

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -6,17 +6,12 @@ local bit = require("bit")
local Font = require("ui/font") local Font = require("ui/font")
local Cache = require("cache") local Cache = require("cache")
local Blitbuffer = require("ffi/blitbuffer") local Blitbuffer = require("ffi/blitbuffer")
local Device = require("device")
local logger = require("logger") local logger = require("logger")
local band = bit.band local band = bit.band
local bor = bit.bor local bor = bit.bor
local lshift = bit.lshift 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 @TODO: all these functions should probably be methods on Face objects
]]-- ]]--

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

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

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

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

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

@ -35,7 +35,7 @@ local logger = require("logger")
local DGENERIC_ICON_SIZE = G_defaults:readSetting("DGENERIC_ICON_SIZE") 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 = nil, -- mandatory (unless icon is provided)
text_func = nil, text_func = nil,
icon = nil, icon = nil,

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

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

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

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

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

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

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

Loading…
Cancel
Save