2014-10-03 08:11:53 +00:00
#!./luajit
2016-12-29 08:10:38 +00:00
io.stdout : 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-22 07:53:02 +00:00
io.stdout : flush ( )
2016-10-15 03:36:00 +00:00
2019-12-06 21:55:30 +00:00
-- Load default settings
2016-11-13 07:44:06 +00:00
require ( " defaults " )
2015-06-15 08:46:43 +00:00
local DataStorage = require ( " datastorage " )
pcall ( dofile , DataStorage : getDataDir ( ) .. " /defaults.persistent.lua " )
2014-09-25 14:22:30 +00:00
2019-12-06 21:55:30 +00:00
-- Set up Lua and ffi search paths
2016-11-13 07:44:06 +00:00
require ( " setupkoenv " )
2015-02-18 17:37:36 +00:00
2018-03-05 22:27:03 +00:00
io.stdout : write ( " [*] Version: " , require ( " version " ) : getCurrentRevision ( ) , " \n \n " )
io.stdout : flush ( )
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
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
if os.getenv ( " KO_RTL " ) then lang_locale = " ar_AA " 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
2019-03-29 19:12:09 +00:00
local dummy = require ( " ffi/posix_h " )
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 " ,
2020-12-12 01:27:18 +00:00
verbose = " d " ,
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 ( " " )
2014-06-05 06:58:53 +00:00
print ( " If you don't pass any path, the last viewed document 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
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
-- not a recognized option, should be a filename
argidx = argidx - 1
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 " )
2019-12-06 21:55:30 +00:00
-- DPI
2019-09-11 18:00:44 +00:00
local dpi_override = G_reader_settings : readSetting ( " screen_dpi " )
if dpi_override ~= nil then
Device : setScreenDPI ( dpi_override )
end
2019-12-06 21:55:30 +00:00
-- Night mode
2019-04-08 21:05:08 +00:00
if G_reader_settings : isTrue ( " night_mode " ) then
2016-03-21 23:30:45 +00:00
Device.screen : toggleNightMode ( )
2014-06-08 06:06:04 +00:00
end
2019-12-06 21:55:30 +00:00
-- Dithering
2019-04-18 21:26:53 +00:00
if Device : hasEinkScreen ( ) then
Device.screen : setupDithering ( )
if Device.screen . hw_dithering and G_reader_settings : isTrue ( " dev_no_hw_dither " ) then
2020-07-23 04:01:46 +00:00
Device.screen : toggleHWDithering ( false )
2019-04-18 21:26:53 +00:00
end
if Device.screen . sw_dithering and G_reader_settings : isTrue ( " dev_no_sw_dither " ) then
2020-07-23 04:01:46 +00:00
Device.screen : toggleSWDithering ( false )
end
-- NOTE: If device can HW dither (i.e., after setupDithering(), hw_dithering is true, but sw_dithering is false),
-- but HW dither is explicitly disabled, and SW dither enabled, don't leave SW dither disabled (i.e., re-enable sw_dithering)!
if Device : canHWDither ( ) and G_reader_settings : isTrue ( " dev_no_hw_dither " ) and G_reader_settings : nilOrFalse ( " dev_no_sw_dither " ) then
Device.screen : toggleSWDithering ( true )
2019-04-18 21:26:53 +00:00
end
end
2012-06-11 16:37:58 +00:00
2019-12-06 21:55:30 +00:00
-- Handle global settings migration
local SettingsMigration = require ( " ui/data/settings_migration " )
SettingsMigration : migrateSettings ( G_reader_settings )
-- Document renderers canvas
local CanvasContext = require ( " document/canvascontext " )
CanvasContext : init ( Device )
2020-01-02 13:00:55 +00:00
-- Touch screen (this may display some widget, on first install on Kobo Touch,
-- so have it done after CanvasContext:init() but before Bidi.setup() to not
-- have mirroring mess x/y probing).
if Device : needsTouchScreenProbe ( ) then
Device : touchScreenProbe ( )
end
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 " )
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
G_reader_settings : saveSetting ( " color_rendering " , true )
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
2019-12-06 21:55:30 +00:00
-- Helpers
local lfs = require ( " libs/libkoreader-lfs " )
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 ( )
local last_file = G_reader_settings : readSetting ( " lastfile " )
if lfs.attributes ( last_file , " mode " ) == " file " then
local ReaderUI = require ( " apps/reader/readerui " )
UIManager : nextTick ( function ( )
ReaderUI : showReader ( last_file )
end )
else
UIManager : show ( retryLastFile ( ) )
end
end ,
}
end
2017-05-16 09:11:11 +00:00
2019-09-01 13:54:41 +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
2019-12-06 21:55:30 +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 " )
local open_last = start_with == " last "
if open_last and last_file and lfs.attributes ( last_file , " mode " ) ~= " file " then
UIManager : show ( retryLastFile ( ) )
last_file = nil
else
local QuickStart = require ( " ui/quickstart " )
if not QuickStart : isShown ( ) then
open_last = true
last_file = QuickStart : getQuickStart ( )
end
end
-- Start app
local exit_code
2013-03-16 02:12:19 +00:00
if ARGV [ argidx ] and ARGV [ argidx ] ~= " " then
2017-10-08 14:33:59 +00:00
local file
2019-09-01 13:54:41 +00:00
local sanitized_path = getPathFromURI ( ARGV [ argidx ] )
if lfs.attributes ( sanitized_path , " mode " ) == " file " then
file = sanitized_path
2014-06-05 11:06:35 +00:00
elseif open_last and last_file then
2014-09-03 04:09:25 +00:00
file = last_file
end
2016-02-25 08:54:41 +00:00
-- if file is given in command line argument or open last document is set
-- true, the given file or the last file is opened in the reader
2019-09-01 13:54:41 +00:00
if file and file ~= " " then
2014-09-03 04:09:25 +00:00
local ReaderUI = require ( " apps/reader/readerui " )
2016-03-09 06:52:36 +00:00
UIManager : nextTick ( function ( )
ReaderUI : showReader ( file )
end )
2014-09-03 04:09:25 +00:00
-- we assume a directory is given in command line argument
-- the filemanger will show the files in that path
2014-03-13 13:52:43 +00:00
else
2014-09-03 04:09:25 +00:00
local FileManager = require ( " apps/filemanager/filemanager " )
2016-02-25 08:54:41 +00:00
local home_dir =
G_reader_settings : readSetting ( " home_dir " ) or ARGV [ argidx ]
2016-03-09 06:52:36 +00:00
UIManager : nextTick ( function ( )
2020-07-05 15:34:44 +00:00
FileManager : setRotationMode ( true )
2016-03-09 06:52:36 +00:00
FileManager : showFiles ( home_dir )
end )
2017-08-14 11:15:12 +00:00
-- always open history on top of filemanager so closing history
-- doesn't result in exit
if start_with == " history " then
local FileManagerHistory = require ( " apps/filemanager/filemanagerhistory " )
UIManager : nextTick ( function ( )
FileManagerHistory : onShowHist ( last_file )
end )
2020-08-26 18:44:56 +00:00
elseif start_with == " favorites " then
local FileManagerCollection = require ( " apps/filemanager/filemanagercollection " )
UIManager : nextTick ( function ( )
FileManagerCollection : new {
ui = FileManager.instance ,
} : onShowColl ( " favorites " )
end )
2018-09-12 19:42:24 +00:00
elseif start_with == " folder_shortcuts " then
local FileManagerShortcuts = require ( " apps/filemanager/filemanagershortcuts " )
UIManager : nextTick ( function ( )
2019-03-11 10:10:46 +00:00
FileManagerShortcuts : new {
ui = FileManager.instance ,
} : onShowFolderShortcutsDialog ( )
2018-09-12 19:42:24 +00:00
end )
2017-08-14 11:15:12 +00:00
end
2014-03-13 13:52:43 +00:00
end
2017-05-16 09:11:11 +00:00
exit_code = UIManager : run ( )
2014-01-17 18:41:44 +00:00
elseif last_file then
2014-09-03 04:09:25 +00:00
local ReaderUI = require ( " apps/reader/readerui " )
2016-03-09 06:52:36 +00:00
UIManager : nextTick ( function ( )
ReaderUI : showReader ( last_file )
end )
2017-05-16 09:11:11 +00:00
exit_code = UIManager : run ( )
2012-10-02 22:45:45 +00:00
else
2014-03-13 13:52:43 +00:00
return showusage ( )
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 ( )
2020-09-01 19:43:21 +00:00
-- Exit code can be shoddy on some platforms due to broken library dtors calling _exit(0) from os.exit(N)
local ko_exit = os.getenv ( " KO_EXIT_CODE " )
if ko_exit then
local fo = io.open ( ko_exit , " w+ " )
fo : write ( tostring ( exit_code ) )
fo : close ( )
end
2016-02-25 08:54:41 +00:00
local ReaderActivityIndicator =
require ( " apps/reader/modules/readeractivityindicator " )
2014-11-06 07:07:50 +00:00
2017-09-04 19:05:05 +00:00
-- Save any device settings before closing G_reader_settings
Device : saveSettings ( )
2014-11-06 07:07:50 +00:00
G_reader_settings : close ( )
-- Close lipc handles
ReaderActivityIndicator : coda ( )
-- shutdown hardware abstraction
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
2020-12-12 01:27:18 +00:00
local ret = exitReader ( )
2020-12-24 23:38:31 +00:00
-- Close the Lua state on exit
os.exit ( ret , true )