2014-10-03 08:11:53 +00:00
#!./luajit
Assorted bag'o tweaks & fixes (#9569)
* UIManager: Support more specialized update modes for corner-cases:
* A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor).
* NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*).
* UIManager: Assorted code cleanups & simplifications.
* Logger & dbg: Unify logging style, and code cleanups.
* SDL: Unbreak suspend/resume outside of the emulator (fix #9567).
* NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay).
* OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573)
* WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!).
* Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit.
* UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo).
* UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes).
* Kindle: ID the upcoming Scribe.
* Bump base (https://github.com/koreader/koreader-base/pull/1524)
2022-10-02 01:01:49 +00:00
-- Enforce line-buffering for stdout (this is the default if it points to a tty, but we redirect to a file on most platforms).
2022-10-14 16:44:36 +00:00
io.stdout : setvbuf ( " line " )
Logger: Use serpent instead of dump (#9588)
* Persist: support serpent, and use by default over dump (as we assume consistency > readability in Persist).
* Logger/Dbg: Use serpent instead of dump to dump tables (it's slightly more compact, honors __tostring, and will tag tables with their ref, which can come in handy when debugging).
* Dbg: Don't duplicate Logger's log function, just use it directly.
* Fontlist/ConfigDialog: Use serpent for the debug dump.
* Call `os.setlocale(C, "numeric")` on startup instead of peppering it around dump calls. It's process-wide, so it didn't make much sense.
* Trapper: Use LuaJIT's serde facilities instead of dump. They're more reliable in the face of funky input, much faster, and in this case, the data never makes it to human eyes, so a human-readable format didn't gain us anything.
2022-10-06 00:21:03 +00:00
-- Enforce a reliable locale for numerical representations
os.setlocale ( " C " , " numeric " )
Assorted bag'o tweaks & fixes (#9569)
* UIManager: Support more specialized update modes for corner-cases:
* A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor).
* NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*).
* UIManager: Assorted code cleanups & simplifications.
* Logger & dbg: Unify logging style, and code cleanups.
* SDL: Unbreak suspend/resume outside of the emulator (fix #9567).
* NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay).
* OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573)
* WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!).
* Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit.
* UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo).
* UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes).
* Kindle: ID the upcoming Scribe.
* Bump base (https://github.com/koreader/koreader-base/pull/1524)
2022-10-02 01:01:49 +00:00
io.write ( [ [
2016-10-15 03:36:00 +00:00
---------------------------------------------
launching ...
_ _____ ____ _
| |/ / _ \ | _ \ ___ __ _ __ | | ___ _ __
| ' / | | | |_) / _ \ / _` |/ _` |/ _ \ ' __ |
| . \ | _ | | _ < __ / ( _ | | ( _ | | __ / |
| _ | \ _ \ ___ /| _ | \ _ \ ___ | \ __ , _ | \ __ , _ | \ ___ | _ |
2018-03-05 22:27:03 +00:00
It ' s a scroll... It ' s a codex ... It ' s KOReader!
[ * ] Current time : ] ] , os.date ( " %x-%X " ) , " \n " )
2016-10-15 03:36:00 +00:00
2022-06-25 20:46:43 +00:00
-- Set up Lua and ffi search paths
require ( " setupkoenv " )
-- Apply startup user patches and execute startup user scripts
local userpatch = require ( " userpatch " )
userpatch.applyPatches ( userpatch.early_once )
userpatch.applyPatches ( userpatch.early )
2023-03-05 14:21:56 +00:00
local Version = require ( " version " )
io.write ( " [*] Version: " , Version : getCurrentRevision ( ) , " \n \n " )
2018-03-05 22:27:03 +00:00
2022-09-27 23:10:50 +00:00
-- Load default settings
G_defaults = require ( " luadefaults " ) : open ( )
2019-12-06 21:55:30 +00:00
-- Read settings and check for language override
-- Has to be done before requiring other files because
2014-01-18 22:04:14 +00:00
-- they might call gettext on load
2022-09-27 23:10:50 +00:00
local DataStorage = require ( " datastorage " )
2016-06-12 18:28:44 +00:00
G_reader_settings = require ( " luasettings " ) : open (
DataStorage : getDataDir ( ) .. " /settings.reader.lua " )
2020-12-23 16:06:08 +00:00
-- Apply the JIT opt tweaks ASAP when the C BB is disabled,
-- because we want to avoid the jit.flush() from bb:enableCBB,
-- which only makes the mcode allocation issues worse on Android...
local is_cbb_enabled = G_reader_settings : nilOrFalse ( " dev_no_c_blitter " )
if not is_cbb_enabled then
jit.opt . start ( " loopunroll=45 " )
end
2014-01-19 17:59:27 +00:00
local lang_locale = G_reader_settings : readSetting ( " language " )
2019-12-06 21:55:33 +00:00
-- Allow quick switching to Arabic for testing RTL/UI mirroring
2022-12-02 17:39:47 +00:00
if os.getenv ( " KO_RTL " ) then lang_locale = " ar " end
2016-11-13 07:44:06 +00:00
local _ = require ( " gettext " )
2014-01-19 17:59:27 +00:00
if lang_locale then
2014-03-13 13:52:43 +00:00
_.changeLang ( lang_locale )
2014-01-18 22:04:14 +00:00
end
2020-09-22 21:26:05 +00:00
-- Try to turn the C blitter on/off, and synchronize setting so that UI config reflects real state
local bb = require ( " ffi/blitbuffer " )
2020-12-23 16:06:08 +00:00
bb : setUseCBB ( is_cbb_enabled )
is_cbb_enabled = bb : enableCBB ( G_reader_settings : nilOrFalse ( " dev_no_c_blitter " ) )
2020-09-22 21:26:05 +00:00
G_reader_settings : saveSetting ( " dev_no_c_blitter " , not is_cbb_enabled )
2019-03-29 19:12:09 +00:00
2019-12-06 21:55:30 +00:00
-- Should check DEBUG option in arg and turn on DEBUG before loading other
2019-09-11 18:00:44 +00:00
-- modules, otherwise DEBUG in some modules may not be printed.
local dbg = require ( " dbg " )
if G_reader_settings : isTrue ( " debug " ) then dbg : turnOn ( ) end
if G_reader_settings : isTrue ( " debug " ) and G_reader_settings : isTrue ( " debug_verbose " ) then dbg : setVerbose ( true ) end
2019-02-18 16:01:00 +00:00
2019-12-06 21:55:30 +00:00
-- Option parsing:
2013-10-18 20:38:07 +00:00
local longopts = {
2014-03-13 13:52:43 +00:00
debug = " d " ,
2023-02-08 00:22:59 +00:00
verbose = " v " ,
2014-03-13 13:52:43 +00:00
profile = " p " ,
help = " h " ,
2012-06-11 16:37:58 +00:00
}
2014-09-03 04:09:25 +00:00
local function showusage ( )
2014-06-05 06:58:53 +00:00
print ( " usage: ./reader.lua [OPTION] ... path " )
print ( " Read all the books on your E-Ink reader " )
2014-03-13 13:52:43 +00:00
print ( " " )
2014-06-05 06:58:53 +00:00
print ( " -d start in debug mode " )
2016-08-12 06:05:18 +00:00
print ( " -v debug in verbose mode " )
2014-06-05 11:06:35 +00:00
print ( " -p enable Lua code profiling " )
2014-06-05 06:58:53 +00:00
print ( " -h show this usage help " )
2014-03-13 13:52:43 +00:00
print ( " " )
2014-06-05 06:58:53 +00:00
print ( " If you give the name of a directory instead of a file path, a file " )
print ( " chooser will show up and let you select a file " )
2014-03-13 13:52:43 +00:00
print ( " " )
2021-01-07 19:38:10 +00:00
print ( " If you don't pass any path, the File Manager will be opened " )
2014-03-13 13:52:43 +00:00
print ( " " )
2014-06-05 11:23:54 +00:00
print ( " This software is licensed under the AGPLv3. " )
2014-06-05 06:58:53 +00:00
print ( " See http://github.com/koreader/koreader for more info. " )
2012-06-11 16:37:58 +00:00
end
2021-01-07 19:38:10 +00:00
local function getPathFromURI ( str )
local hexToChar = function ( x )
return string.char ( tonumber ( x , 16 ) )
end
local unescape = function ( url )
return url : gsub ( " %%(%x%x) " , hexToChar )
end
local prefix = " file:// "
if str : sub ( 1 , # prefix ) ~= prefix then
return str
end
return unescape ( str ) : sub ( # prefix + 1 )
end
local lfs = require ( " libs/libkoreader-lfs " )
local file
local directory
2014-11-06 07:07:50 +00:00
local Profiler = nil
2014-10-03 08:11:53 +00:00
local ARGV = arg
2012-11-01 02:02:53 +00:00
local argidx = 1
2013-08-06 14:53:44 +00:00
while argidx <= # ARGV do
2014-03-13 13:52:43 +00:00
local arg = ARGV [ argidx ]
argidx = argidx + 1
if arg == " -- " then break end
-- parse longopts
if arg : sub ( 1 , 2 ) == " -- " then
local opt = longopts [ arg : sub ( 3 ) ]
if opt ~= nil then arg = " - " .. opt end
end
-- code for each option
if arg == " -h " then
return showusage ( )
elseif arg == " -d " then
2016-10-25 07:08:47 +00:00
dbg : turnOn ( )
2016-08-12 06:05:18 +00:00
elseif arg == " -v " then
2016-10-25 07:08:47 +00:00
dbg : setVerbose ( true )
2014-03-13 13:52:43 +00:00
elseif arg == " -p " then
2014-05-01 03:58:05 +00:00
Profiler = require ( " jit.p " )
Profiler.start ( " la " )
2014-03-13 13:52:43 +00:00
else
2021-01-07 19:38:10 +00:00
-- not a recognized option, should be a filename or directory
local sanitized_path = getPathFromURI ( arg )
local mode = lfs.attributes ( sanitized_path , " mode " )
if mode == " file " then
file = sanitized_path
elseif mode == " directory " or mode == " link " then
directory = sanitized_path
end
2014-03-13 13:52:43 +00:00
break
end
2012-06-11 16:37:58 +00:00
end
2019-12-06 21:55:30 +00:00
-- Setup device
2019-09-11 18:00:44 +00:00
local Device = require ( " device " )
2012-06-11 16:37:58 +00:00
2019-12-06 21:55:30 +00:00
-- Document renderers canvas
local CanvasContext = require ( " document/canvascontext " )
CanvasContext : init ( Device )
2023-03-05 14:21:56 +00:00
-- Update the version log file if there was an update or the device has changed
Version : updateVersionLog ( Device.model )
2021-04-13 15:54:11 +00:00
-- Handle one time migration stuff (settings, deprecation, ...) in case of an upgrade...
2023-08-02 16:57:14 +00:00
do
dofile ( " frontend/ui/data/onetime_migration.lua " )
end
2021-04-13 15:54:11 +00:00
2019-12-06 21:55:33 +00:00
-- UI mirroring for RTL languages, and text shaping configuration
local Bidi = require ( " ui/bidi " )
Bidi.setup ( lang_locale )
-- Avoid loading UIManager and widgets before here, as they may
-- cache Bidi mirroring settings. Check that with:
-- for name, _ in pairs(package.loaded) do print(name) end
2019-12-06 21:55:30 +00:00
-- User fonts override
local fontmap = G_reader_settings : readSetting ( " fontmap " )
if fontmap ~= nil then
local Font = require ( " ui/font " )
for k , v in pairs ( fontmap ) do
Font.fontmap [ k ] = v
end
end
local UIManager = require ( " ui/uimanager " )
2022-06-25 20:46:43 +00:00
-- Apply developer patches
userpatch.applyPatches ( userpatch.late )
2017-10-02 13:17:17 +00:00
-- Inform once about color rendering on newly supported devices
-- (there are some android devices that may not have a color screen,
-- and we are not (yet?) able to guess that fact)
2019-04-08 21:05:08 +00:00
if Device : hasColorScreen ( ) and not G_reader_settings : has ( " color_rendering " ) then
2017-10-02 13:17:17 +00:00
-- enable it to prevent further display of this message
2021-03-06 21:44:18 +00:00
G_reader_settings : makeTrue ( " color_rendering " )
2017-10-02 13:17:17 +00:00
local InfoMessage = require ( " ui/widget/infomessage " )
UIManager : show ( InfoMessage : new {
text = _ ( " Documents will be rendered in color on this device. \n If your device is grayscale, you can disable color rendering in the screen sub-menu for reduced memory usage. " ) ,
} )
end
2020-02-18 01:24:48 +00:00
-- Conversely, if color is enabled on a Grayscale screen (e.g., after importing settings from a color device), warn that it'll break stuff and adversely affect performance.
if G_reader_settings : isTrue ( " color_rendering " ) and not Device : hasColorScreen ( ) then
local ConfirmBox = require ( " ui/widget/confirmbox " )
UIManager : show ( ConfirmBox : new {
text = _ ( " Color rendering is mistakenly enabled on your grayscale device. \n This will subtly break some features, and adversely affect performance. " ) ,
cancel_text = _ ( " Ignore " ) ,
cancel_callback = function ( )
return
end ,
ok_text = _ ( " Disable " ) ,
ok_callback = function ( )
local Event = require ( " ui/event " )
G_reader_settings : delSetting ( " color_rendering " )
CanvasContext : setColorRenderingEnabled ( false )
UIManager : broadcastEvent ( Event : new ( " ColorRenderingUpdate " ) )
end ,
} )
end
2021-01-07 19:38:10 +00:00
-- Get which file to start with
local last_file = G_reader_settings : readSetting ( " lastfile " )
local start_with = G_reader_settings : readSetting ( " start_with " ) or " filemanager "
2019-12-06 21:55:30 +00:00
-- Helpers
local function retryLastFile ( )
local ConfirmBox = require ( " ui/widget/confirmbox " )
return ConfirmBox : new {
text = _ ( " Cannot open last file. \n This could be because it was deleted or because external storage is still being mounted. \n Do you want to retry? " ) ,
ok_callback = function ( )
2021-01-07 19:38:10 +00:00
if lfs.attributes ( last_file , " mode " ) ~= " file " then
2019-12-06 21:55:30 +00:00
UIManager : show ( retryLastFile ( ) )
end
end ,
2021-01-07 19:38:10 +00:00
cancel_callback = function ( )
start_with = " filemanager "
end ,
2019-12-06 21:55:30 +00:00
}
end
2017-05-16 09:11:11 +00:00
2021-01-07 19:38:10 +00:00
-- Start app
local exit_code
if file then
local ReaderUI = require ( " apps/reader/readerui " )
2022-12-11 22:50:28 +00:00
ReaderUI : showReader ( file )
2021-01-07 19:38:10 +00:00
exit_code = UIManager : run ( )
elseif directory then
local FileManager = require ( " apps/filemanager/filemanager " )
2022-12-11 22:50:28 +00:00
FileManager : showFiles ( directory )
2021-01-07 19:38:10 +00:00
exit_code = UIManager : run ( )
2019-12-06 21:55:30 +00:00
else
local QuickStart = require ( " ui/quickstart " )
if not QuickStart : isShown ( ) then
2021-01-07 19:38:10 +00:00
start_with = " last "
2019-12-06 21:55:30 +00:00
last_file = QuickStart : getQuickStart ( )
end
2021-01-07 19:38:10 +00:00
if start_with == " last " and last_file and lfs.attributes ( last_file , " mode " ) ~= " file " then
UIManager : show ( retryLastFile ( ) )
2022-12-11 22:50:28 +00:00
-- We'll want to return from this without actually quitting,
-- so this is a slightly mangled UIManager:run() call to coerce the main loop into submission...
-- We'll call :run properly in either of the following branches once returning.
UIManager : runOnce ( )
2014-09-03 04:09:25 +00:00
end
2021-01-07 19:38:10 +00:00
if start_with == " last " and last_file then
2014-09-03 04:09:25 +00:00
local ReaderUI = require ( " apps/reader/readerui " )
2022-12-11 22:50:28 +00:00
-- Instantiate RD
ReaderUI : showReader ( last_file )
2021-01-07 19:38:10 +00:00
exit_code = UIManager : run ( )
2014-03-13 13:52:43 +00:00
else
2014-09-03 04:09:25 +00:00
local FileManager = require ( " apps/filemanager/filemanager " )
2022-12-11 22:50:28 +00:00
local home_dir = G_reader_settings : readSetting ( " home_dir " ) or Device.home_dir or lfs.currentdir ( )
-- Instantiate FM
FileManager : showFiles ( home_dir )
ReaderUI: Saner FM/RD lifecycle
* Ensure that going from one to the other tears down the former and
its plugins before instantiating the latter and its plugins.
UIManager: Unify Event sending & broadcasting
* Make the two behave the same way (walk the widget stack from top to
bottom), and properly handle the window stack shrinking shrinking
*and* growing.
Previously, broadcasting happened bottom-to-top and didn't really
handle the list shrinking/growing, while sending only handled the list
shrinking by a single element, and hopefully that element being the one
the event was just sent to.
These two items combined allowed us to optimize suboptimal
refresh behavior with Menu and other Menu classes when
opening/closing a document.
e.g., the "opening document" Notification is now properly regional,
and the "open last doc" option no longer flashes like a crazy person
anymore.
Plugins: Allow optimizing Menu refresh with custom menus, too.
Requires moving Menu's close_callback *after* onMenuSelect, which, eh,
probably makes sense, and is probably harmless in the grand scheme of
things.
2021-05-01 16:53:04 +00:00
-- Always open FM modules on top of filemanager, so closing 'em doesn't result in an exit
-- because of an empty widget stack, and so they can interact with the FM instance as expected.
2017-08-14 11:15:12 +00:00
if start_with == " history " then
2024-02-24 07:24:50 +00:00
FileManager.instance . history : onShowHist ( )
2020-08-26 18:44:56 +00:00
elseif start_with == " favorites " then
2024-02-24 07:24:50 +00:00
FileManager.instance . collections : onShowColl ( )
2018-09-12 19:42:24 +00:00
elseif start_with == " folder_shortcuts " then
2024-02-24 07:24:50 +00:00
FileManager.instance . folder_shortcuts : onShowFolderShortcutsDialog ( )
2017-08-14 11:15:12 +00:00
end
2021-01-07 19:38:10 +00:00
exit_code = UIManager : run ( )
2014-03-13 13:52:43 +00:00
end
2012-10-02 22:45:45 +00:00
end
2019-12-06 21:55:30 +00:00
-- Exit
2014-11-06 07:07:50 +00:00
local function exitReader ( )
2023-08-19 11:34:50 +00:00
-- Shutdown hardware abstraction (it'll also flush G_reader_settings to disk)
2014-11-06 07:07:50 +00:00
Device : exit ( )
if Profiler then Profiler.stop ( ) end
2017-05-16 09:11:11 +00:00
if type ( exit_code ) == " number " then
2020-12-12 01:27:18 +00:00
return exit_code
2017-05-16 09:11:11 +00:00
else
2020-12-24 23:38:31 +00:00
return true
2017-05-16 09:11:11 +00:00
end
2014-11-06 07:07:50 +00:00
end
2022-06-25 20:46:43 +00:00
-- Apply before_exit patches and execute user scripts
userpatch.applyPatches ( userpatch.before_exit )
local reader_retval = exitReader ( )
-- Apply exit user patches and execute user scripts
userpatch.applyPatches ( userpatch.on_exit )
2020-12-24 23:38:31 +00:00
-- Close the Lua state on exit
2022-06-25 20:46:43 +00:00
os.exit ( reader_retval , true )