Merge branch 'master' of github.com:hwhw/kindlepdfviewer

Qingping Hou 12 years ago
commit f37d6a647f

15
.gitignore vendored

@ -12,6 +12,7 @@ crash.log
data
fonts
kpdfview
slider_watcher
*.o
kindlepdfviewer-*.zip
@ -24,3 +25,17 @@ kpvcrlib/CMakeCache.txt
kpvcrlib/CMakeFiles/
kpvcrlib/cmake_install.cmake
kpvcrlib/Makefile
popen-noshell/libpopen_noshell.a
popen-noshell/*.o
popen-noshell/.svn/
popen-noshell/CREDITS
popen-noshell/Makefile
popen-noshell/README
popen-noshell/performance_tests/
popen-noshell/popen_noshell.c
popen-noshell/popen_noshell.h
popen-noshell/popen_noshell_examples.c
popen-noshell/popen_noshell_tests.c
popen-noshell/popen_noshell_tests.cpp

@ -11,15 +11,18 @@ CRENGINEDIR=$(KPVCRLIBDIR)/crengine
FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype-2.4.10
LFSDIR=luafilesystem
POPENNSDIR=popen-noshell
# must point to directory with *.ttf fonts for crengine
TTF_FONTS_DIR=$(MUPDFDIR)/fonts
# set this to your ARM cross compiler:
HOST:=arm-none-linux-gnueabi
CC:=$(HOST)-gcc
CXX:=$(HOST)-g++
STRIP:=$(HOST)-strip
CHOST?=arm-none-linux-gnueabi
CC:=$(CHOST)-gcc
CXX:=$(CHOST)-g++
STRIP:=$(CHOST)-strip
AR:=$(CHOST)-ar
ifdef SBOX_UNAME_MACHINE
CC:=gcc
CXX:=g++
@ -27,12 +30,16 @@ endif
HOSTCC:=gcc
HOSTCXX:=g++
CFLAGS:=-O3 $(SYSROOT)
CXXFLAGS:=-O3 $(SYSROOT)
# Base CFLAGS, without arch. We'll need it for luajit, because its Makefiles do some tricky stuff to differentiate HOST/TARGET
BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer -fno-stack-protector -U_FORTIFY_SOURCE
# Use this for debugging:
#BASE_CFLAGS:=-O0 -g
ARM_ARCH:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp
HOST_ARCH:=-march=native
HOSTCFLAGS:=$(HOST_ARCH) $(BASE_CFLAGS)
CFLAGS:=$(BASE_CFLAGS)
CXXFLAGS:=$(BASE_CFLAGS) -fno-use-cxa-atexit
LDFLAGS:=-Wl,-O1 -Wl,--as-needed
ARM_CFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp
# use this for debugging:
#CFLAGS:=-O0 -g
DYNAMICLIBSTDCPP:=-lstdc++
ifdef STATICLIBSTDCPP
@ -56,9 +63,11 @@ ifdef EMULATE_READER
ifeq "$(shell uname -s -m)" "Darwin x86_64"
EMU_LDFLAGS += -pagezero_size 10000 -image_base 100000000
endif
CFLAGS+= $(HOST_ARCH)
CXXFLAGS+= $(HOST_ARCH)
else
CFLAGS+= $(ARM_CFLAGS)
CXXFLAGS+= $(ARM_CFLAGS)
CFLAGS+= $(ARM_ARCH)
CXXFLAGS+= $(ARM_ARCH)
endif
# standard includes
@ -88,16 +97,20 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \
LUALIB := $(LUADIR)/src/libluajit.a
all:kpdfview
POPENNSLIB := $(POPENNSDIR)/libpopen_noshell.a
all: kpdfview
kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS)
kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS)
$(CC) \
$(CFLAGS) \
kpdfview.o \
einkfb.o \
pdf.o \
blitbuffer.o \
drawcontext.o \
input.o \
$(POPENNSLIB) \
util.o \
ft.o \
lfs.o \
@ -110,10 +123,14 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft
cre.o \
$(CRENGINELIBS) \
$(STATICLIBSTDCPP) \
-o kpdfview -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP)
$(LDFLAGS) \
-o $@ -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP)
slider_watcher: slider_watcher.c
$(CC) $(CFLAGS) $< -o $@
slider_watcher.o: %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
slider_watcher: slider_watcher.o $(POPENNSLIB)
$(CC) $(CFLAGS) slider_watcher.o $(POPENNSLIB) -o $@
ft.o: %.o: %.c $(THIRDPARTYLIBS)
$(CC) -c $(KPDFREADER_CFLAGS) -I$(FREETYPEDIR)/include -I$(MUPDFDIR)/fitz $< -o $@
@ -131,7 +148,7 @@ lfs.o: $(LFSDIR)/src/lfs.c
$(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@
fetchthirdparty:
-rm -Rf mupdf/thirdparty
rm -rf mupdf/thirdparty
test -d mupdf && (cd mupdf; git checkout .) || echo warn: mupdf folder not found
test -d $(LUADIR) && (cd $(LUADIR); git checkout .) || echo warn: $(LUADIR) folder not found
git submodule init
@ -153,58 +170,66 @@ fetchthirdparty:
patch -N -p0 < ../../../kpvcrlib/jpeg_decompress_struct_size.patch
# MuPDF patch: use external fonts
cd mupdf && patch -N -p1 < ../mupdf.patch
test -f popen-noshell/popen_noshell.c || svn co http://popen-noshell.googlecode.com/svn/trunk/ popen-noshell
# popen_noshell patch: Make it build on recent TCs, and implement a simple Makefile for building it as a static lib
cd popen-noshell && test -f Makefile || patch -N -p0 < popen_noshell-buildfix.patch
clean:
-rm -f *.o kpdfview slider_watcher
rm -f *.o kpdfview slider_watcher
cleanthirdparty:
-make -C $(LUADIR) clean
-make -C $(MUPDFDIR) build="release" clean
-make -C $(CRENGINEDIR)/thirdparty/antiword clean
test -d $(CRENGINEDIR)/thirdparty/chmlib && make -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/thirdparty/libpng && (make -C $(CRENGINEDIR)/thirdparty/libpng clean) || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/crengine && (make -C $(CRENGINEDIR)/crengine clean) || echo warn: chmlib folder not found
test -d $(KPVCRLIBDIR) && (make -C $(KPVCRLIBDIR) clean) || echo warn: chmlib folder not found
-rm -rf $(DJVUDIR)/build
-rm -f $(MUPDFDIR)/fontdump.host
-rm -f $(MUPDFDIR)/cmapdump.host
$(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(CHOST)-" clean
$(MAKE) -C $(MUPDFDIR) build="release" clean
$(MAKE) -C $(CRENGINEDIR)/thirdparty/antiword clean
test -d $(CRENGINEDIR)/thirdparty/chmlib && $(MAKE) -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/thirdparty/libpng && ($(MAKE) -C $(CRENGINEDIR)/thirdparty/libpng clean) || echo warn: chmlib folder not found
test -d $(CRENGINEDIR)/crengine && ($(MAKE) -C $(CRENGINEDIR)/crengine clean) || echo warn: chmlib folder not found
test -d $(KPVCRLIBDIR) && ($(MAKE) -C $(KPVCRLIBDIR) clean) || echo warn: chmlib folder not found
rm -rf $(DJVUDIR)/build
rm -f $(MUPDFDIR)/fontdump.host
rm -f $(MUPDFDIR)/cmapdump.host
$(MAKE) -C $(POPENNSDIR) clean
$(MUPDFDIR)/fontdump.host:
make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump
$(MAKE) -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/fontdump
cp -a $(MUPDFLIBDIR)/fontdump $(MUPDFDIR)/fontdump.host
make -C mupdf clean
$(MAKE) -C mupdf clean
$(MUPDFDIR)/cmapdump.host:
make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump
$(MAKE) -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/cmapdump
cp -a $(MUPDFLIBDIR)/cmapdump $(MUPDFDIR)/cmapdump.host
make -C mupdf clean
$(MAKE) -C mupdf clean
$(MUPDFLIBS) $(THIRDPARTYLIBS): $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.host
# build only thirdparty libs, libfitz and pdf utils, which will care for libmupdf.a being built
CFLAGS="$(CFLAGS) -DNOBUILTINFONT" make -C mupdf build="release" CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1
CFLAGS="$(CFLAGS) -DNOBUILTINFONT" $(MAKE) -C mupdf build="release" CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1
$(DJVULIBS):
-mkdir $(DJVUDIR)/build
mkdir -p $(DJVUDIR)/build
ifdef EMULATE_READER
cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --disable-xmltools --disable-largefile
else
cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --host=$(HOST) --disable-xmltools --disable-largefile
cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --host=$(CHOST) --disable-xmltools --disable-largefile
endif
make -C $(DJVUDIR)/build
$(MAKE) -C $(DJVUDIR)/build
$(CRENGINELIBS):
cd $(KPVCRLIBDIR) && rm -rf CMakeCache.txt CMakeFiles && \
CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS)" cmake . && \
make
$(MAKE)
$(LUALIB):
ifdef EMULATE_READER
make -C $(LUADIR)
$(MAKE) -C $(LUADIR)
else
make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(HOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2"
# To recap: build its TARGET_CC from CROSS+CC, so we need HOSTCC in CC. Build its HOST/TARGET_CFLAGS based on CFLAGS, so we need a neutral CFLAGS without arch
$(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(HOSTCFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(CHOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2"
endif
thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS)
$(POPENNSLIB):
$(MAKE) -C $(POPENNSDIR) CC="$(CC)" AR="$(AR)"
thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) $(POPENNSLIB)
INSTALL_DIR=kindlepdfviewer
@ -215,8 +240,8 @@ customupdate: all
# ensure that build binary is for ARM
file kpdfview | grep ARM || exit 1
$(STRIP) --strip-unneeded kpdfview
-rm kindlepdfviewer-$(VERSION).zip
rm -Rf $(INSTALL_DIR)
rm -f kindlepdfviewer-$(VERSION).zip
rm -rf $(INSTALL_DIR)
mkdir -p $(INSTALL_DIR)/{history,screenshots}
echo $(VERSION) > $(INSTALL_DIR)/git-rev
cp -p README.md COPYING kpdfview $(LUA_FILES) $(INSTALL_DIR)
@ -226,5 +251,5 @@ customupdate: all
cp -r resources $(INSTALL_DIR)
mkdir $(INSTALL_DIR)/fonts/host
zip -9 -r kindlepdfviewer-$(VERSION).zip $(INSTALL_DIR) launchpad/ kite/
rm -Rf $(INSTALL_DIR)
rm -rf $(INSTALL_DIR)
@echo "copy kindlepdfviewer-$(VERSION).zip to /mnt/us/customupdates and install with shift+shift+I"

@ -168,7 +168,7 @@ function Commands:new(obj)
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
if G_charging_mode == false and G_screen_saver_mode == false then
Screen:saveCurrentBB()
InfoMessage:show("Going into screensaver... ", 0)
InfoMessage:inform("Going into screensaver... ", nil, 0, MSG_AUX)
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
fb:setOrientation(Screen.native_rotation_mode)
util.sleep(1)
@ -199,7 +199,7 @@ function Commands:new(obj)
Screen:saveCurrentBB()
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
fb:setOrientation(Screen.native_rotation_mode)
InfoMessage:show("Going into USB mode... ", 0)
InfoMessage:inform("Going into USB mode... ", nil, 0, MSG_AUX)
util.sleep(1)
os.execute("killall -cont cvm")
end

@ -1,7 +1,43 @@
require "widget"
require "font"
-- some definitions for developers
MSG_AUX = 1
MSG_WARN = 2
MSG_ERROR = 3
MSG_CONFIRM = 4
MSG_BUG = 5
InfoMessage = {
InfoMethod = { --[[
The items define how to inform user about various types of events, the values should be 0..3:
the lowest bit is responcible for showing popup windows,
while the 2nd bit allows using TTS-voice messages.
The current default values {1,1,1,1,1} correspond to previous kpdfviewer-settings
when every message is shown in popup window. ]]
1, -- auxiliary messages = 0 or 2 (nothing or TTS)
1, -- warnings = 1 or 2 (popup or TTS)
1, -- errors = 1 or 3 (popup or popup & TTS)
1, -- confirmations (must not be silent!) = 1 or 3 (popup or popup & TTS)
1, -- bugs (must not be silent!) = 1 or 3 (popup or popup & TTS)
},
-- images for various message types
Images = {
"resources/info-aux.png",
"resources/info-warn.png",
"resources/info-error.png",
"resources/info-confirm.png",
"resources/info-bug.png",
},
ImageFile = "resources/info-warn.png",
-- TTS-related parameters
TTSspeed = nil,
SoundVolume = nil,
--[[ as Kindle3-volume has nonlinear scale, one need to define the 'VolumeLevels'-values
TODO: test whether VolumeLevels are different for other sound-equipped Kindle models (K2, KDX)
by running self.VolumeLevels = self:getVolumeLevels() ]]
VolumeLevels = { 0, 1, 2, 4, 6, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77}
}
function InfoMessage:show(text,refresh_mode)
@ -14,7 +50,7 @@ function InfoMessage:show(text,refresh_mode)
HorizontalGroup:new({
align = "center",
ImageWidget:new({
file = "resources/info-i.png"
file = self.ImageFile
}),
Widget:new({
dimen = { w = 10, h = 0 }
@ -54,3 +90,191 @@ function showInfoMsgWithDelay(text, msec, refresh_mode)
Screen:restoreFromSavedBB()
fb:refresh(refresh_mode)
end
--[[ Unified function to inform user about smth. It is generally intended to replace showInfoMsgWithDelay() & InfoMessage:show().
Since the former function is used in Lua-code more often than the latter, I kept here the same sequence of parameters as used in
showInfoMsgWithDelay() + added two not obligatory parameters (see description below).
Thus, this trick allows multiple text replaces thoughout the whole Lua-code: 'showInfoMsgWithDelay(' to 'InfoMessage:inform('
Yet, it would be much better to accompany such replaces by adding the 'message_importance' and, if needed, by
'alternative_voice_message' that is not so restricted in length as 'text'
But replacing InfoMessage:show(...) by InfoMessage:inform(...) MUST be accompanied by adding the 2nd parameter -- either msec=nil or msec=0.
Adding new parameters -- 'message_importance' & 'alternative_voice_message' -- is also appreciated.
Brief description of the function parameters
-- text : is the text message for visual and (if 'alternative_voice_message' isn't defined) voice notification
-- msec : parameter to define visual notification method
msec=0: one calls InfoMessage:show(), otherwise one calls showInfoMsgWithDelay()
msec>0: with either predefines msec-value or
msec<0: autocalculated from the text length: one may eventually add user-configurable
parameter 'reading_speed' that would define the popup exposition for this regime
-- message_importance : parameter separating various messages on
1 - not obligatory messages that might be readily avoided
2 - warnings (important messages)
3 - errors
4 - confirmations
5 - bugs
-- alternative_voice_message: not obligatory parameter that allows to send longer messages to TTS-engine
if not defined, the default 'text' will be TTS-voiced
]]
function InfoMessage:inform(text, msec, refresh_mode, message_importance, alternative_voice_message)
-- temporary test for 'message_importance'; it might be further removed as soon
-- as every message will be properly marked by 'importance'
if not message_importance then message_importance = 5 end
local popup, voice = InfoMessage:getMethodForEvent(message_importance)
if voice then
alternative_voice_message = alternative_voice_message or text
say(alternative_voice_message)
-- here one may set pause -- it might be useful only if one sound message
-- is directly followed by another, otherwise it's just wasting of time.
--[[ if msec and msec ~=0 then
-- pause = 0.5sec + 40ms/character * string.len() / normalized_voice_speed
util.usleep(500000 + 40*alternative_voice_message:len*10000/self.TTSspeed)
end ]]
end
if not popup then return end -- to avoid drawing popup window
self.ImageFile = self.Images[message_importance] -- select proper image for window
if not msec or msec == 0 then
InfoMessage:show(text, refresh_mode)
else
if msec < 0 then msec = 500 + string.len(text) * 50 end
showInfoMsgWithDelay(text, msec, refresh_mode)
end
end
function InfoMessage:getMethodForEvent(event)
local popup, voice = true, true
if self.InfoMethod[event] %2 == 0 then popup = false end
if self.InfoMethod[event] < 2 then voice = false end
return popup, voice
end
-- GUI-methods for user to choose the way to inform about various events --
function InfoMessage:chooseMethodForEvent(event)
local popup, voice = self:getMethodForEvent(event)
local items_menu = SelectMenu:new{
menu_title = "Choose the way how to inform you",
item_array = {"Avoid any notifications",
"Show popup window",
"Use TTS-voice",
"Popup window and TTS-voice",
},
current_entry = (popup and 1 or 0) + (voice and 1 or 0) * 2,
}
local item_no = items_menu:choose(0, fb.bb:getHeight())
if item_no then
self.InfoMethod[event] = item_no - 1
-- just to illustrate the way how the selected method works; might be removed
self:inform("Event = "..event..", Method = "..self.InfoMethod[event], -1500, 1, event,
"You have chosen the method number "..self.InfoMethod[event].." for the event item number "..event)
end
end
function InfoMessage:chooseEventForMethod(event)
event = event or 0
local item_no = 0
local event_list = {
"Messages (e.g. 'Scanning folder...')",
"Warnings (e.g. 'Already first jump!')",
"Errors (e.g. 'Zip contains improper content!')",
"Confirmations (e.g. 'Press Y to confirm deleting')",
"Bugs",
}
while item_no ~= event and item_no < #event_list do
item_no = item_no + 1
end
local event_menu = SelectMenu:new{
menu_title = "Select the event type to tune",
item_array = event_list,
current_entry = item_no - 1,
}
item_no = event_menu:choose(0, G_height)
return item_no
end
function InfoMessage:chooseNotificatonMethods()
local event = 1 -- default: auxiliary messages
while event do
event = self:chooseEventForMethod(event)
if event then self:chooseMethodForEvent(event) end
end
end
---------------- audio-related functions ----------------
function InfoMessage:incrTTSspeed(direction) -- either +1 or -1
-- make sure new TTS-speed is within reasonable range
self.TTSspeed = math.max(self.TTSspeed + direction * 20, 40) -- min = 40%
self.TTSspeed = math.min(self.TTSspeed, 200) -- max = 200%
-- set new value & give an example for more convenient tuning
os.execute('lipc-set-prop com.lab126.tts TtsISpeed '..self.TTSspeed)
say("The current voice speed is "..self.TTSspeed.." percent.")
end
function InfoMessage:getTTSspeed()
local tmp = io.popen('lipc-get-prop com.lab126.tts TtsISpeed', "r")
local speed = tmp:read("*number")
tmp:close()
return speed or 100 -- nominal TTS-speed
end
function InfoMessage:incrSoundVolume(direction) -- either +1 or -1
-- make sure that new volume is within reasonable range
self.SoundVolume = math.max(self.SoundVolume + direction, 1)
self.SoundVolume = math.min(self.SoundVolume, #self.VolumeLevels)
-- set new value & give an example for more convenient tuning
os.execute('lipc-set-prop com.lab126.audio Volume '..(self.SoundVolume-1))
-- that is not exactly the volume percents, but more conventional values,
-- than abstract units returned by 'lipc-get-prop com.lab126.audio Volume'
local percents = math.floor(100*self.VolumeLevels[self.SoundVolume]/self.VolumeLevels[#self.VolumeLevels])
say("The current sound volume is "..percents.." percent.")
end
function InfoMessage:getSoundVolume()
local tmp = io.popen('lipc-get-prop com.lab126.audio Volume', "r")
local volume = tmp:read("*number")
tmp:close()
local i = 1
while self.VolumeLevels[i] < volume and i < #self.VolumeLevels do
i = i + 1
end
return i or 16 -- maximum volume
end
--[[ -- to determine self.VolumeLevels in various Kindle-models
function InfoMessage:getVolumeLevels()
local levels, v, i = {}, 0, 0
while i < 16 do -- proper K3-range 0..15 might be different for other models
os.execute('lipc-set-prop com.lab126.audio Volume '..i)
v = self:getSoundVolume()
table.insert(levels, v)
i = i + 1
end
return levels
end ]]
function say(text)
os.execute("say \""..text.."\"")
end
-- The read/write global InfoMessage settings. When properly tested, the
-- condition 'if FileChooser.filemanager_expert_mode == ...' might be deleted
function InfoMessage:initInfoMessageSettings()
if FileChooser.filemanager_expert_mode == FileChooser.ROOT_MODE then
InfoMessage.InfoMethod = G_reader_settings:readSetting("info_message_methods") or InfoMessage.InfoMethod
InfoMessage.TTSspeed = G_reader_settings:readSetting("tts_speed") or InfoMessage:getTTSspeed()
InfoMessage.SoundVolume = G_reader_settings:readSetting("sound_volume") or InfoMessage:getSoundVolume()
end
end
function InfoMessage:saveInfoMessageSettings()
if FileChooser.filemanager_expert_mode == FileChooser.ROOT_MODE then
G_reader_settings:saveSetting("info_message_methods", InfoMessage.InfoMethod)
G_reader_settings:saveSetting("sound_volume", InfoMessage.SoundVolume-1)
G_reader_settings:saveSetting("tts_speed", InfoMessage.TTSspeed)
end
end

@ -29,33 +29,27 @@ FileChooser = {
pagedirty = true,
markerdirty = false,
perpage,
clipboard = lfs.currentdir() .. "/clipboard", -- NO finishing slash
before_clipboard, -- NuPogodi, 30.09.12: to store the path where jump to clipboard was made from
-- NuPogodi, 04.09.2012: introduced modes that configures the filechoser
-- for users with various purposes & skills
-- modes that configures the filechoser for users with various purposes & skills
filemanager_expert_mode, -- default value is defined in reader.lua
-- the definitions
BEGINNERS_MODE = 1, -- the filemanager content is restricted by files with reader-related extensions; safe renaming (no extension)
ADVANCED_MODE = 2, -- no extension-based filtering; renaming with extensions; appreciable danger to crash crengine by improper docs
ROOT_MODE = 3, -- TODO: all functions (including non-stable and dangerous)
}
function getProperTitleLength(txt,font_face,max_width)
local tw = TextWidget:new({ text = txt, face = font_face})
-- 1st approximation for a point where to start title
local n = math.floor(string.len(txt) * (1 - max_width / tw:getSize().w)) - 2
n = math.max(n, 1)
while tw:getSize().w >= max_width do
tw:free()
tw = TextWidget:new({ text = string.sub(txt,n,-1), face = font_face})
n = n + 1
-- NuPogodi, 29.09.12: simplified the code
function getProperTitleLength(txt, font_face, max_width)
while sizeUtf8Text(0, G_width, font_face, txt, true).x > max_width do
txt = txt:sub(2, -1)
end
return string.sub(txt,n-1,-1)
return txt
end
function BatteryLevel()
-- NuPogodi, 18.05.12: This command seems to work even without Amazon Kindle framework
local p = io.popen("gasgauge-info -s 2> /dev/null", "r") -- io.popen() _never_ fails!
local battery = p:read("*a") or "?"
if battery == "" then battery = "?" end
@ -63,36 +57,30 @@ function BatteryLevel()
return string.gsub(battery, "[\n\r]+", "")
end
-- NuPogodi, 29.09.12: avoid using widgets
function DrawTitle(text,lmargin,y,height,color,font_face)
local r = 6 -- radius for round corners
color = 3 -- redefine to ignore the input for background color
fb.bb:paintRect(1, 1, fb.bb:getWidth() - 2, height - r, color)
blitbuffer.paintBorder(fb.bb, 1, height/2, fb.bb:getWidth() - 2, height/2, height/2, color, r)
-- to have a horisontal gap between text & background rectangle
t = BatteryLevel() .. os.date(" %H:%M")
local tw = TextWidget:new({ text = t, face = font_face})
twidth = tw:getSize().w
renderUtf8Text(fb.bb, fb.bb:getWidth()-twidth-lmargin, height-10, font_face, t, true)
tw:free()
tw = TextWidget:new({ text = text, face = font_face})
local max_width = fb.bb:getWidth() - 2*lmargin - twidth
if tw:getSize().w < max_width then
fb.bb:paintRect(1, 1, G_width-2, height - r, color)
blitbuffer.paintBorder(fb.bb, 1, height/2, G_width-2, height/2, height/2, color, r)
local t = BatteryLevel() .. os.date(" %H:%M")
r = sizeUtf8Text(0, G_width, font_face, t, true).x
renderUtf8Text(fb.bb, G_width-r-lmargin, height-10, font_face, t, true)
r = G_width - r - 2 * lmargin - 10 -- let's leave small gap
if sizeUtf8Text(0, G_width, font_face, text, true).x <= r then
renderUtf8Text(fb.bb, lmargin, height-10, font_face, text, true)
else
local w = renderUtf8Text(fb.bb, lmargin, height-10, font_face, "...", true)
local txt = getProperTitleLength(text, font_face, max_width-w)
renderUtf8Text(fb.bb, w+lmargin, height-10, font_face, txt, true)
t = renderUtf8Text(fb.bb, lmargin, height-10, font_face, "...", true)
text = getProperTitleLength(text, font_face, r-t)
renderUtf8Text(fb.bb, lmargin+t, height-10, font_face, text, true)
end
tw:free()
end
function DrawFooter(text,font_face,h)
local y = G_height - 7
-- NuPogodi, 29.09.12: just dirty fix to have the same footer everywhere
-- just dirty fix to have the same footer everywhere
local x = FileChooser.margin_H --(G_width / 2) - 50
renderUtf8Text(fb.bb, x, y, font_face, text.." - Press H for help", true)
renderUtf8Text(fb.bb, x, y, font_face, text.." - Press H for help", true)
end
function DrawFileItem(name,x,y,image)
@ -106,11 +94,11 @@ function DrawFileItem(name,x,y,image)
-- then drawing filenames
local cface = Font:getFace("cfont", 22)
local xleft = x + iw:getSize().w + 9 -- the gap between icon & filename
local width = fb.bb:getWidth() - xleft - x
local width = G_width - xleft - x
-- now printing the name
if sizeUtf8Text(xleft, fb.bb:getWidth() - x, cface, name, true).x < width then
if sizeUtf8Text(xleft, G_width - x, cface, name, true).x < width then
renderUtf8Text(fb.bb, xleft, y, cface, name, true)
else
else
local lgap = sizeUtf8Text(0, width, cface, " ...", true).x
local handle = renderUtf8TextWidth(fb.bb, xleft, y, cface, name, true, width - lgap - x)
renderUtf8Text(fb.bb, handle.x + lgap + x, y, cface, " ...", true)
@ -162,6 +150,10 @@ end
function FileChooser:setPath(newPath)
local curr_path = self.path
if self.before_clipboard then -- back from clipboard
newPath = self.before_clipboard
self.before_clipboard = nil
end
self.path = getAbsolutePath(newPath)
local readdir_ok, exc = pcall(self.readDir,self)
if(not readdir_ok) then
@ -173,8 +165,20 @@ function FileChooser:setPath(newPath)
if self.items == 0 then
return nil
end
self.page = 1
self.current = 1
-- NuPogodi, 02.10.12: 1) changing the current item position ONLY IF the path was changed
-- 2) trying to set marker under the folder that was just left by ".."
if self.path ~= curr_path then
local i = 2
while i <= #self.dirs and not string.find(curr_path, self.dirs[i]) do
i = i + 1
end
if i <= #self.dirs then -- found
self.current, self.page = gotoTargetItem(i, self.items, self.current, self.page, self.perpage)
else -- set defaults
self.page = 1
self.current = 1
end
end
return true
end
end
@ -210,7 +214,7 @@ function FileChooser:choose(ypos, height)
local msg = self.exception_message and self.exception_message:match("[^%:]+:%d+: (.*)") or self.path
self.exception_message = nil
-- draw header
DrawTitle(msg,self.margin_H,ypos,self.title_H,4,tface)
DrawTitle(msg,self.margin_H,ypos,self.title_H,3,tface)
self.markerdirty = true
end
@ -260,7 +264,7 @@ function FileChooser:choose(ypos, height)
end -- while
end
-- NuPogodi, 20.05.12: add available commands
-- add available commands
function FileChooser:addAllCommands()
self.commands = Commands:new{}
@ -270,35 +274,8 @@ function FileChooser:addAllCommands()
self.pagedirty = true
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"goto next page",
function(self)
if self.page < (self.items / self.perpage) then
if self.current + self.page*self.perpage > self.items then
self.current = self.items - self.page*self.perpage
end
self.page = self.page + 1
self.pagedirty = true
else
self.current = self.items - (self.page-1)*self.perpage
self.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"goto previous page",
function(self)
if self.page > 1 then
self.page = self.page - 1
self.pagedirty = true
else
self.current = 1
self.markerdirty = true
end
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"goto next item",
"next item",
function(self)
if self.current == self.perpage then
if self.page < (self.items / self.perpage) then
@ -316,7 +293,7 @@ function FileChooser:addAllCommands()
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"goto previous item",
"previous item",
function(self)
if self.current == 1 then
if self.page > 1 then
@ -330,16 +307,69 @@ function FileChooser:addAllCommands()
end
end
)
self.commands:add({KEY_FW_RIGHT, KEY_I}, nil, "joypad right",
-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(self)
local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
self.current, self.page, self.markerdirty, self.pagedirty =
gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
if self.page < (self.items / self.perpage) then
if self.current + self.page*self.perpage > self.items then
self.current = self.items - self.page*self.perpage
end
self.page = self.page + 1
self.pagedirty = true
else
self.current = self.items - (self.page-1)*self.perpage
self.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(self)
if self.page > 1 then
self.page = self.page - 1
self.pagedirty = true
else
self.current = 1
self.markerdirty = true
end
end
)
self.commands:add(KEY_G, nil, "G", -- NuPogodi, 01.10.12: goto page No.
"goto page",
function(self)
local n = math.ceil(self.items / self.perpage)
local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
if pcall(function () page = math.floor(page) end) -- convert string to number
and page ~= self.page and page > 0 and page <= n then
self.page = page
if self.current + (page-1)*self.perpage > self.items then
self.current = self.items - (page-1)*self.perpage
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"show document information",
function(self)
local folder = self.dirs[self.perpage*(self.page-1)+self.current]
if folder then
if folder == ".." then
showInfoMsgWithDelay("<UP-DIR> ", 1000, 1)
warningUnsupportedFunction()
else
folder = self.path.."/"..folder
if FileInfo:show(folder) == "goto" then
if FileInfo:show(folder) == "goto" then
self:setPath(folder)
end
end
@ -365,39 +395,29 @@ function FileChooser:addAllCommands()
self.pagedirty = true
end
)
-- NuPogodi, 23.05.12: modified to delete both files and empty folders
-- modified to delete both files and empty folders
self.commands:add(KEY_DEL, nil, "Del",
"delete selected item",
function(self)
local pos = self.perpage*(self.page-1)+self.current
local folder = self.dirs[pos]
if folder == ".." then
showInfoMsgWithDelay(".. cannot be deleted! ",1500,1)
elseif folder then
InfoMessage:show("Press \'Y\' to confirm",0)
if self:ReturnKey() == KEY_Y then
if lfs.rmdir(self.path.."/"..folder) then
table.remove(self.dirs, offset)
self:setPath(self.path)
else
showInfoMsgWithDelay("Cannot be deleted!",1500,1)
end
local confirm = "Please, press key Y to confirm deleting"
if pos > #self.dirs then -- file
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
self:deleteFileAtPosition(pos)
else
InfoMessage:inform("Press 'Y' to confirm ", nil, 0, MSG_CONFIRM, confirm)
if self:ReturnKey() == KEY_Y then self:deleteFileAtPosition(pos) end
end
else
InfoMessage:show("Press \'Y\' to confirm",0)
if self:ReturnKey() == KEY_Y then
pos = pos - #self.dirs
local fullpath = self.path.."/"..self.files[pos]
-- delete the file itself
os.remove(fullpath)
-- and its history file, if any
os.remove(DocToHistory(fullpath))
-- to avoid showing just deleted file
table.remove(self.files, pos)
self.items = self.items - 1
self.current = self.current - 1
elseif self.dirs[pos] == ".." then
warningUnsupportedFunction()
else -- other folders
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
self:deleteFolderAtPosition(pos)
else
InfoMessage:inform("Press 'Y' to confirm ", nil, 0, MSG_CONFIRM, confirm)
if self:ReturnKey() == KEY_Y then self:deleteFolderAtPosition(pos) end
end
end -- if folder == ".."
end
self.pagedirty = true
end -- function
)
@ -427,14 +447,48 @@ function FileChooser:addAllCommands()
end
end
)
-- NuPogodi, 04.09.12: menu to switch the filechooser mode
self.commands:add(KEY_M, MOD_ALT, "M",
"set mode for filemanager",
function(self)
self:changeFileChooserMode()
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F",
-- NuPogodi, 25.09.12: new functions to tune the way how to inform user about the reader events
local popup_text = "Unstable... For experts only! "
local voice_text = "This function is still under development and available only for experts and beta testers."
self.commands:add(KEY_I, nil, "I",
"change the way to inform about events",
function(self)
if self.filemanager_expert_mode == self.ROOT_MODE then
InfoMessage:chooseNotificatonMethods()
self.pagedirty = true
else
InfoMessage:inform(popup_text, -1, 1, MSG_WARN, voice_text)
end
end
)
self.commands:addGroup("Vol-/+", {Keydef:new(KEY_VPLUS,nil), Keydef:new(KEY_VMINUS,nil)},
"decrease/increase sound volume",
function(self)
if self.filemanager_expert_mode == self.ROOT_MODE then
InfoMessage:incrSoundVolume(keydef.keycode == KEY_VPLUS and 1 or -1)
else
InfoMessage:inform(popup_text, -1, 1, MSG_WARN, voice_text)
end
end
)
self.commands:addGroup(MOD_SHIFT.."Vol-/+", {Keydef:new(KEY_VPLUS,MOD_SHIFT), Keydef:new(KEY_VMINUS,MOD_SHIFT)},
"decrease/increase TTS-engine speed",
function(self)
if self.filemanager_expert_mode == self.ROOT_MODE then
InfoMessage:incrTTSspeed(keydef.keycode == KEY_VPLUS and 1 or -1)
else
InfoMessage:inform(popup_text, -1, 1, MSG_WARN, voice_text)
end
end
)
------------ end of changes (NuPogodi, 25.09.12) ------------
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
Font:chooseFonts()
@ -447,7 +501,7 @@ function FileChooser:addAllCommands()
HelpPage:show(0, G_height, self.commands)
self.pagedirty = true
end
)
)
self.commands:add(KEY_L, nil, "L",
"show last documents",
function(self)
@ -462,16 +516,17 @@ function FileChooser:addAllCommands()
function(self)
local keywords = InputBox:input(0, 0, "Search:")
if keywords then
InfoMessage:show("Searching... ",0)
InfoMessage:inform("Searching... ", nil, 1, MSG_AUX)
FileSearcher:init( self.path )
FileSearcher:choose(keywords)
end
self.pagedirty = true
end -- function
end
)
self.commands:add(KEY_C, MOD_SHIFT, "C",
"copy file to \'clipboard\'",
"copy file to 'clipboard'",
function(self)
-- TODO (NuPogodi, 27.09.12): overwrite?
local file = self:FullFileName()
if file then
lfs.mkdir(self.clipboard)
@ -479,29 +534,34 @@ function FileChooser:addAllCommands()
local fn = self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
os.execute("cp "..self:InQuotes(DocToHistory(file)).." "
..self:InQuotes(DocToHistory(self.clipboard.."/"..fn)) )
showInfoMsgWithDelay("File copied to clipboard ", 1000, 1)
InfoMessage:inform("File copied to clipboard ", 1000, 1, MSG_WARN,
"The file has been copied to clipboard.")
end
end
)
)
self.commands:add(KEY_X, MOD_SHIFT, "X",
"move file to \'clipboard\'",
"move file to 'clipboard'",
function(self)
-- TODO (NuPogodi, 27.09.12): overwrite?
local file = self:FullFileName()
if file then
lfs.mkdir(self.clipboard)
local fn = self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
os.rename(file, self.clipboard.."/"..fn)
os.rename(DocToHistory(file), DocToHistory(self.clipboard.."/"..fn))
InfoMessage:show("File moved to clipboard ", 0)
InfoMessage:inform("File moved to clipboard ", nil, 0, MSG_WARN,
"The file has been moved to clipboard.")
self:setPath(self.path)
self.pagedirty = true
end
end
)
self.commands:add(KEY_V, MOD_SHIFT, "V",
"paste file(s) from \'clipboard\'",
"paste file(s) from 'clipboard'",
function(self)
InfoMessage:show("moving file(s) from clipboard ", 0)
-- TODO (NuPogodi, 27.09.12): first test whether the clipboard is empty & answer respectively
-- TODO (NuPogodi, 27.09.12): overwrite?
InfoMessage:inform("Moving files from clipboard...", nil, 0, MSG_AUX)
for f in lfs.dir(self.clipboard) do
if lfs.attributes(self.clipboard.."/"..f, "mode") == "file" then
os.rename(self.clipboard.."/"..f, self.path.."/"..f)
@ -513,11 +573,15 @@ function FileChooser:addAllCommands()
end
)
self.commands:add(KEY_B, MOD_SHIFT, "B",
"show content of \'clipboard\'",
"show content of 'clipboard'",
function(self)
-- NuPogodi, 30.09.12: exit back from clipboard to last folder by '..'
local current_path = self.path
lfs.mkdir(self.clipboard)
self:setPath(self.clipboard)
-- TODO: exit back from clipboard to last folder - Redefine Exit on FW_Right?
if self.clipboard ~= self.path then
self:setPath(self.clipboard)
self.before_clipboard = current_path
end
self.pagedirty = true
end
)
@ -536,13 +600,12 @@ function FileChooser:addAllCommands()
self.commands:add(KEY_K, MOD_SHIFT, "K",
"run calculator",
function(self)
local CalcBox = InputBox:new{ calcmode = true }
local CalcBox = InputBox:new{ inputmode = MODE_CALC }
CalcBox:input(0, 0, "Calc ")
self.pagedirty = true
end
)
self.commands:add(KEY_HOME, nil, "Home",
"exit",
self.commands:addGroup("Home, Alt + Back", { Keydef:new(KEY_HOME, nil),Keydef:new(KEY_BACK, MOD_ALT)}, "exit",
function(self)
return "break"
end
@ -551,19 +614,14 @@ end
-- returns full filename or nil (if folder)
function FileChooser:FullFileName()
local file
local folder = self.dirs[self.perpage*(self.page-1)+self.current]
if folder == ".." then
showInfoMsgWithDelay("<UP-DIR> ",1000,1)
elseif folder then
showInfoMsgWithDelay("<DIR> ",1000,1)
else
file=self.path.."/"..self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
if self.current > #self.dirs then
return self.path.."/"..self.files[self.perpage*(self.page-1)+self.current - #self.dirs]
end
return file
warningUnsupportedFunction()
return nil
end
-- returns the keycode of released key and (if debug) shows the keycode on screen
function FileChooser:ReturnKey(debug)
-- returns the keycode of released key
function FileChooser:ReturnKey()
while true do
ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
@ -571,7 +629,6 @@ function FileChooser:ReturnKey(debug)
break
end
end
if debug then showInfoMsgWithDelay("Keycode = "..ev.code,1000,1) end
return ev.code
end
@ -582,11 +639,11 @@ end
--[[ NuPogodi, 04.09.2012: to make it more easy for users with various purposes and skills.
ATM, one may leave only silent toggling between BEGINNERS_MODE <> ADVANCED_MODE
-- But, in future, one more (the so called ROOT_MODE) might also be rather useful.
Shitch this mode on should allow developers & beta-testers to use some unstable
Switching this mode on should allow developers & beta-testers to use some unstable
and/or dangerous functions able to crash the reader. ]]
function FileChooser:changeFileChooserMode()
local face_list = { "safe mode for beginners", "advanced mode for experienced users", "expert mode for beta-testers & developers" }
local face_list = { "Safe mode for beginners", "Advanced mode for experienced users", "Expert mode for beta-testers & developers" }
local modes_menu = SelectMenu:new{
menu_title = "Select proper mode to manage files",
item_array = face_list,
@ -594,30 +651,58 @@ function FileChooser:changeFileChooserMode()
}
local m = modes_menu:choose(0, G_height)
if m and m ~= self.filemanager_expert_mode then
--[[ TODO: to allow multiline-rendering for info messages & to include detailed description of the selected mode
local msg = "Press 'Y' to accept new mode..."
if m==self.BEGINNERS_MODE then
msg = "You have selected safe mode for beginners: the filemanager shows only files with the reader-related extensions (*.pdf, *.djvu, etc.); "..
"safe renaming (no extensions); unstable or dangerous functions are NOT included. "..msg
elseif m==self.ADVANCED_MODE then
msg = "You have selected advanced mode for experienced users: the filemanager shows all files; "..
"you may rename not only their names, but also the extensions; the files with unknown extensions would be sent to CREReader "..
"and could crash the reader. Please, use it in your own risk. "..msg
else -- ROOT_MODE
msg = "You have selected the most advanced and dangerous mode. I hope You know what you are doing. God bless You. "..msg
end
InfoMessage:show(msg, 1)
if self:ReturnKey() == KEY_Y then ]]
if (self.filemanager_expert_mode == self.BEGINNERS_MODE and m > self.BEGINNERS_MODE)
or (m == self.BEGINNERS_MODE and self.filemanager_expert_mode > self.BEGINNERS_MODE) then
self.filemanager_expert_mode = m -- make sure that new mode is set before...
self:setPath(self.path) -- refreshing the folder content
self:setPath(self.path) -- refreshing the folder content
else
self.filemanager_expert_mode = m
end
G_reader_settings:saveSetting("filemanager_expert_mode", self.filemanager_expert_mode)
-- end
end
-- NuPogodi, 26.09.2012: temporary place; when properly tested, might be commented / deleted the following line
InfoMessage:initInfoMessageSettings()
self.pagedirty = true
end
-- NuPogodi, 28.09.12: two following functions are extracted just to make the code more compact
function FileChooser:deleteFolderAtPosition(pos)
if lfs.rmdir(self.path.."/"..self.dirs[pos]) then
table.remove(self.dirs, pos) -- to avoid showing just deleted file
self.items = #self.dirs + #self.files
self.current, self.page = gotoTargetItem(pos, self.items, pos, self.page, self.perpage)
else
InfoMessage:inform("Folder can't be deleted! ", 1500, 1, MSG_ERROR,
"This folder can not be deleted! Please, make sure that it is empty.")
end
end
function FileChooser:deleteFileAtPosition(pos)
local fullpath = self.path.."/"..self.files[pos-#self.dirs]
os.remove(fullpath) -- delete the file itself
os.remove(DocToHistory(fullpath)) -- and its history file, if any
table.remove(self.files, pos-#self.dirs) -- to avoid showing just deleted file
self.items = self.items - 1
self.current, self.page = gotoTargetItem(pos, self.items, pos, self.page, self.perpage)
end
-- NuPogodi, 01.10.12: jump to defined item in the itemlist
function gotoTargetItem(target_item, all_items, current_item, current_page, perpage)
target_item = math.max(math.min(target_item, all_items), 1)
local target_page = math.ceil(target_item/perpage)
local target_curr = (target_item -1) % perpage + 1
local pagedirty, markerdirty = false, false
if target_page ~= current_page then
current_page = target_page
pagedirty = true
markerdirty = true
elseif target_curr ~= current_item then
markerdirty = true
end
return target_curr, current_page, markerdirty, pagedirty
end
function warningUnsupportedFunction()
InfoMessage:inform("Unsupported function! ", 2000, 1, MSG_WARN,
"The requested function is not supported.")
end

@ -6,16 +6,13 @@ require "inputbox"
require "dialog"
require "filesearcher"
require "settings"
require "dialog"
FileHistory = {
-- title height
title_H = 40,
-- spacing between lines
spacing = 36,
-- foot height
foot_H = 28,
-- horisontal margin
margin_H = 10,
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 28, -- foot height
margin_H = 10, -- horisontal margin
-- state buffer
history_files = {},
@ -25,6 +22,7 @@ FileHistory = {
page = 0,
current = 1,
oldcurrent = 1,
commands = nil,
}
function FileHistory:init(history_path)
@ -33,14 +31,16 @@ function FileHistory:init(history_path)
else
self:setPath("./history")
end
self:addAllCommands()
-- to initialize only once
if not self.commands then self:addAllCommands() end
end
function FileHistory:setPath(newPath)
self.path = newPath
self:readDir("-c ")
self.items = #self.files
if self.items == 0 then
if self.items == 1 then
return nil
end
self.page = 1
@ -49,24 +49,22 @@ function FileHistory:setPath(newPath)
end
function FileHistory:readDir(order_criteria)
self.history_files = {}
self.files = {}
self.history_files = { {dir=self.path, name=".."} }
self.files = { {dir=self.path, name=".."} }
local p = io.popen("ls "..order_criteria.."-1 "..self.path)
for f in p:lines() do
-- insert history files
file_entry = {dir=self.path, name=f}
table.insert(self.history_files, file_entry)
table.insert(self.history_files, {dir=self.path, name=f})
-- and corresponding path & file items
file_entry = {dir=HistoryToPath(f), name=HistoryToName(f)}
table.insert(self.files, file_entry)
table.insert(self.files, {dir=HistoryToPath(f), name=HistoryToName(f)})
end
p:close()
end
function FileHistory:setSearchResult(keywords)
self.result = {}
self.result = { {dir=self.path, name=".."} }
if keywords == "" or keywords == " " then
-- show all history
-- show all history
self.result = self.files
else
-- select history files with keywords in the filename
@ -80,6 +78,7 @@ function FileHistory:setSearchResult(keywords)
self.items = #self.result
self.page = 1
self.current = 1
return self.items
end
function FileHistory:prevItem()
@ -113,28 +112,6 @@ end
function FileHistory:addAllCommands()
self.commands = Commands:new{}
-- search among last documents
self.commands:add(KEY_S, nil, "S",
"search among files",
function(self)
old_keywords = self.keywords
self.keywords = InputBox:input(G_height - 100, 100,
"Search:", old_keywords)
if self.keywords then
self:setSearchResult(self.keywords)
else
self.keywords = old_keywords
end
self.pagedirty = true
end
)
self.commands:add(KEY_L, nil, "L",
"last documents",
function(self)
self:setSearchResult("")
self.pagedirty = true
end
)
self.commands:add(KEY_H, nil, "H",
"show help page",
function(self)
@ -142,26 +119,29 @@ function FileHistory:addAllCommands()
self.pagedirty = true
end
)
self.commands:add({KEY_FW_RIGHT, KEY_I}, nil, "joypad right",
"document details",
function(self)
file_entry = self.result[self.perpage*(self.page-1)+self.current]
FileInfo:show(file_entry.dir,file_entry.name)
self.pagedirty = true
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"goto previous item",
"previous item",
function(self)
self:prevItem()
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"goto next item",
"next item",
function(self)
self:nextItem()
end
)
-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
local numeric_keydefs, i = {}
for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
"item at position 0%, 10% .. 90%, 100%",
function(self)
local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
self.current, self.page, self.markerdirty, self.pagedirty =
gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
@ -189,7 +169,58 @@ function FileHistory:addAllCommands()
end
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F",
self.commands:add(KEY_G, nil, "G", -- NuPogodi, 01.10.12: goto page No.
"goto page",
function(self)
local n = math.ceil(self.items / self.perpage)
local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
if pcall(function () page = math.floor(page) end) -- convert string to number
and page ~= self.page and page > 0 and page <= n then
self.page = page
if self.current + (page-1)*self.perpage > self.items then
self.current = self.items - (page-1)*self.perpage
end
end
self.pagedirty = true
end
)
self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
"document details",
function(self)
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
if file_entry.name == ".." then
warningUnsupportedFunction()
return
end -- do not show details
FileInfo:show(file_entry.dir,file_entry.name)
self.pagedirty = true
end
)
self.commands:add(KEY_S, nil, "S",
"invoke search inputbox",
function(self)
-- NuPogodi, 30.09.12: be sure that something is found
local old_keywords = self.keywords
local old_data = self.result
local old_page, old_current = self.page, self.current
self.keywords = InputBox:input(G_height - 100, 100, "Search:", old_keywords)
if self.keywords then
self:setSearchResult(self.keywords)
end
if #self.result < 2 then
InfoMessage:inform("No hits! Try another keyword. ", 2000, 1, MSG_WARN,
"The search has given no results! Please, try another keyword.")
-- restoring the original data
self.result = old_data
self.items = #self.result
self.keywords = old_keywords
self.page = old_page
self.current = old_current
end
self.pagedirty = true
end
)
self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
"change font faces",
function(self)
Font:chooseFonts()
@ -197,35 +228,42 @@ function FileHistory:addAllCommands()
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
"open selected item",
"open selected document",
function(self)
if #self.result == 0 then
showInfoMsgWithDelay("No files to open", 1500, 1)
return
end
file_entry = self.result[self.perpage*(self.page-1)+self.current]
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
if file_entry.name == ".." then return "break" end -- quit
file_full_path = file_entry.dir .. "/" .. file_entry.name
openFile(file_full_path)
--reset height and item index if screen has been rotated
local item_no = self.perpage * (self.page - 1) + self.current
self.perpage = math.floor(G_height / self.spacing) - 2
self.current = item_no % self.perpage
self.page = math.floor(item_no / self.perpage) + 1
self.pagedirty = true
end
)
self.commands:add({KEY_DEL}, nil, "Del",
"delete history entry",
function(self)
file_entry = self.result[self.perpage*(self.page-1)+self.current]
if not file_entry then return end
local file_entry = self.result[self.perpage*(self.page-1)+self.current]
if file_entry.name == ".." then
warningUnsupportedFunction()
return
end -- do not delete
local file_to_del = file_entry.dir .. "/" .. file_entry.name
os.remove(DocToHistory(file_to_del))
-- to avoid showing just deleted file
self:init()
self:setSearchResult(self.keywords)
if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
os.remove(DocToHistory(file_to_del))
self:init()
self:setSearchResult(self.keywords)
else
InfoMessage:inform("Press 'Y' to confirm ", nil, 0, MSG_CONFIRM,
"Please, press key Y to delete the book history")
if FileChooser:ReturnKey() == KEY_Y then
os.remove(DocToHistory(file_to_del))
self:init()
self:setSearchResult(self.keywords)
end
end
self.pagedirty = true
end
)
@ -235,7 +273,7 @@ function FileHistory:addAllCommands()
self.pagedirty = true
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "Back",
self.commands:add({KEY_BACK, KEY_HOME}, nil, "Back, '..', Home",
"back",
function(self)
return "break"
@ -248,7 +286,11 @@ function FileHistory:choose(keywords)
self.pagedirty = true
self.markerdirty = false
self:setSearchResult(keywords)
-- NuPogodi, 30.09.12: immediate quit (no redraw), if empty
if self:setSearchResult(keywords) < 2 then -- only ".."
InfoMessage:inform("No reading history! ", 2000, 1, MSG_WARN, "The reading history is empty!")
return nil
end
while true do
local cface = Font:getFace("cfont", 22)
@ -258,37 +300,25 @@ function FileHistory:choose(keywords)
if self.pagedirty then
self.markerdirty = true
fb.bb:paintRect(0, 0, G_width, G_height, 0)
-- draw header
local header = "Last Documents"
if self.keywords ~= "" and self.keywords ~= " " then
--header = header .. " (filter: \'" .. string.upper(self.keywords) .. "\')"
header = "Search Results for \'"..string.upper(self.keywords).."\'"
end
DrawTitle(header,self.margin_H,0,self.title_H,4,tface)
DrawTitle(header,self.margin_H,0,self.title_H,3,tface)
-- draw found results
local c
if self.items == 0 then -- nothing found
y = self.title_H + self.spacing * 2
renderUtf8Text(fb.bb, self.margin_H, y, cface,
"Sorry, no files found.", true)
self.markerdirty = false
else -- found something, draw it
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c) + 4
local ftype = string.lower(string.match(self.result[i].name, ".+%.([^.]+)") or "")
DrawFileItem(self.result[i].name,self.margin_H,y,ftype)
end
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c) + 4
local ftype = string.lower(string.match(self.result[i].name, ".+%.([^.]+)") or "")
DrawFileItem(self.result[i].name,self.margin_H,y,ftype)
end
end
-- draw footer
all_page = math.ceil(self.items/self.perpage)
DrawFooter("Page "..self.page.." of "..all_page,fface,self.foot_H)
end
if self.markerdirty then

@ -9,8 +9,6 @@ Font = {
hpkfont = "droid/DroidSansMono.ttf", -- help page: font for displaying keys
hfont = "droid/DroidSans.ttf", -- help page: font for displaying help messages
infont = "droid/DroidSansMono.ttf", -- inputbox: use mono for better distance controlling
-- pgfont = "droid/DroidSans.ttf", -- was in use in heppage to render footer
-- to be repalced by ffont
},
fontdir = os.getenv("FONTDIR") or "./fonts",
-- face table

@ -15,7 +15,11 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "popen-noshell/popen_noshell.h"
#include <err.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
@ -29,9 +33,7 @@
#include "input.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#define OUTPUT_SIZE 21
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
#define CODE_USB_PLUG_IN 10010
@ -41,7 +43,17 @@
#define NUM_FDS 4
int inputfds[4] = { -1, -1, -1, -1 };
int slider_pid = -1;
pid_t slider_pid = -1;
struct popen_noshell_pass_to_pclose pclose_arg;
void slider_handler(int sig)
{
/* Kill lipc-wait-event properly on exit */
if(pclose_arg.pid != 0) {
// Be a little more gracious, lipc seems to handle SIGINT properly
kill(pclose_arg.pid, SIGINT);
}
}
int findFreeFdSlot() {
int i;
@ -73,10 +85,13 @@ static int openInputDevice(lua_State *L) {
return luaL_error(L, "cannot fork() slider event listener");
}
if(childpid == 0) {
// We send a SIGTERM to this child on exit, trap it to kill lipc properly.
signal(SIGTERM, slider_handler);
FILE *fp;
char std_out[OUTPUT_SIZE] = "";
char std_out[256];
int status;
struct input_event ev;
int ret;
__u16 key_code = 10000;
close(pipefd[0]);
@ -85,17 +100,22 @@ static int openInputDevice(lua_State *L) {
ev.code = key_code;
ev.value = 1;
/* listen power slider events */
while(1) {
fp = popen("exec lipc-wait-event com.lab126.powerd goingToScreenSaver,outOfScreenSaver,charging,notCharging", "r");
/* @TODO 07.06 2012 (houqp)
* plugin and out event can only be watched by:
lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn
*/
if(fgets(std_out, OUTPUT_SIZE, fp) == NULL) {
break;
}
pclose(fp);
/* listen power slider events (listen for ever for multiple events) */
char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver,charging,notCharging", (char *) NULL};
/* @TODO 07.06 2012 (houqp)
* plugin and out event can only be watched by:
lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn
*/
fp = popen_noshell("lipc-wait-event", (const char * const *)argv, "r", &pclose_arg, 0);
if (!fp) {
err(EXIT_FAILURE, "popen_noshell()");
}
/* Flush to get rid of buffering issues? */
fflush(fp);
while(fgets(std_out, sizeof(std_out)-1, fp)) {
if(std_out[0] == 'g') {
ev.code = CODE_IN_SAVER;
} else if(std_out[0] == 'o') {
@ -116,10 +136,26 @@ static int openInputDevice(lua_State *L) {
/* generate event */
if(write(pipefd[1], &ev, sizeof(struct input_event)) == -1) {
break;
printf("Failed to generate event.\n");
}
}
exit(0); /* cannot be reached?! */
status = pclose_noshell(&pclose_arg);
if (status == -1) {
err(EXIT_FAILURE, "pclose_noshell()");
} else {
printf("lipc-wait-event exited with status %d.\n", status);
if WIFEXITED(status) {
printf("lipc-wait-event exited normally with status: %d.\n", WEXITSTATUS(status));
}
if WIFSIGNALED(status) {
printf("lipc-wait-event terminated by signal: %d.\n", WTERMSIG(status));
}
}
// We're done, go away :).
_exit(EXIT_SUCCESS);
} else {
close(pipefd[1]);
inputfds[fd] = pipefd[0];
@ -149,7 +185,7 @@ static int closeInputDevices(lua_State *L) {
for(i=0; i<NUM_FDS; i++) {
if(inputfds[i] != -1) {
ioctl(inputfds[i], EVIOCGRAB, 0);
close(i);
close(inputfds[i]);
}
}
if(slider_pid != -1) {
@ -223,7 +259,7 @@ static int waitForInput(lua_State *L) {
SDL_WaitEvent(&event);
else {
while (SDL_GetTicks()-ticks <= usecs/1000) {
if (SDL_PollEvent(&event)) break;
if (SDL_PollEvent(&event)) break;
SDL_Delay(10);
}
if (SDL_GetTicks()-ticks > usecs/1000)

@ -3,6 +3,9 @@ require "rendertext"
require "keys"
require "graphics"
MODE_CALC = 1
MODE_TERM = 2
----------------------------------------------------
-- General inputbox
----------------------------------------------------
@ -37,7 +40,7 @@ InputBox = {
shiftmode = true, -- toggle chars <-> capitals, lowest bit in (layout-2)
symbolmode = false, -- toggle chars <-> symbols, middle bit in (layout-2)
utf8mode = false, -- toggle english <-> national, highest bit in (layout-2)
calcmode = false, -- toggle calculator mode
inputmode, -- define mode: input <> calculator <> terminal
calcfunctions = nil, -- math functions for calculator helppage
}
@ -128,7 +131,7 @@ function InputBox:input(ypos, height, title, d_text, is_hint)
-- my own position, at the bottom screen edge
ypos = fb.bb:getHeight() - 165
-- some corrections for calculator mode
if self.calcmode then
if self.inputmode == MODE_CALC then
self:setCalcMode()
end
@ -366,7 +369,7 @@ function InputBox:CharlistToString()
end
function InputBox:addAllCommands()
-- if already initialized, we (re)define only calcmode-dependent commands
-- if already initialized, we (re)define only inputmode-dependent commands
if self.commands then
self:ModeDependentCommands()
self:DrawVirtualKeyboard()
@ -378,7 +381,7 @@ function InputBox:addAllCommands()
self:addCharCommands(self.layout)
-- adding the rest commands (independent of the selected layout)
self.commands:add(KEY_H, MOD_ALT, "H",
"show helppage",
"show help page",
function(self)
self:showHelpPage(self.commands)
end
@ -436,7 +439,7 @@ function InputBox:addAllCommands()
end
)
self.commands:addGroup("up/down", { Keydef:new(KEY_FW_DOWN, nil), Keydef:new(KEY_FW_UP, nil) },
"goto previous/next VK-layout",
"previous/next VK-layout",
function(self)
if keydef.keycode == KEY_FW_DOWN then
if self.layout == self.max_layout then self:addCharCommands(self.min_layout)
@ -469,10 +472,10 @@ function InputBox:addAllCommands()
self:addCharCommands()
end
)
-- NuPogodi, 02.06.12: calcmode-dependent commands are collected
-- NuPogodi, 02.06.12: inputmode-dependent commands are collected
self:ModeDependentCommands() -- here
self.commands:add({KEY_BACK, KEY_HOME}, nil, "Back",
self.commands:add({KEY_BACK, KEY_HOME}, nil, "Back, Home",
"back",
function(self)
self.input_string = nil
@ -552,9 +555,8 @@ function InputBox:showHelpPage(list, title)
self.cursor:clear() -- hide cursor
fb.bb:dimRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg)
fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h)
-- now start the helppage with own list of commands and own title
HelpPage:show(0, fb.bb:getHeight()-165, list, title)
-- on the helppage-exit, making inactive helpage
-- on the help page-exit, making inactive helpage
fb.bb:dimRect(0, 40, fb.bb:getWidth(), fb.bb:getHeight()-205, self.input_bg)
-- and active input slot
self:refreshText()
@ -595,13 +597,13 @@ end
-- define whether we need to calculate the result or to return 'self.input_string'
function InputBox:ModeDependentCommands()
if self.calcmode then
if self.inputmode == MODE_CALC then
-- define what to do with the input_string
self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "joypad center",
self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "Enter",
"calculate the result",
function(self)
if #self.input_string == 0 then
showInfoMsgWithDelay("No input ", 1000, 1)
InfoMessage:inform("No input! ", 1000, 1, MSG_WARN, "There is nothing to calculate")
else
local s = self:PrepareStringToCalc()
if pcall(function () f = assert(loadstring("r = tostring("..s..")")) end) and pcall(f) then
@ -618,7 +620,7 @@ function InputBox:ModeDependentCommands()
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25, self.input_slot_w, self.h-25)
else
showInfoMsgWithDelay("Invalid input ", 1000, 1)
InfoMessage:inform("Invalid input! ", 1000, 1, MSG_WARN)
end -- if pcall
end
end -- function
@ -633,7 +635,7 @@ function InputBox:ModeDependentCommands()
end
)
else -- return input_string & close input box
self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "joypad center",
self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "Enter",
"submit input content",
function(self)
if self.input_string == "" then
@ -644,7 +646,7 @@ function InputBox:ModeDependentCommands()
)
-- delete calculator-specific help
self.commands:del(KEY_M, MOD_ALT, "M")
end -- if self.calcmode
end -- if self.inputmode
end
----------------------------------------------------

@ -1,3 +1,3 @@
#!/bin/sh
/mnt/us/launchpad/kpdf.sh
/mnt/us/kindlepdfviewer/kpdf.sh

@ -1,3 +1,3 @@
#!/bin/sh
/mnt/us/launchpad/kpdf.sh /mnt/us/documents
/mnt/us/kindlepdfviewer/kpdf.sh /mnt/us/documents

@ -0,0 +1,37 @@
#!/bin/sh
export LC_ALL="en_US.UTF-8"
echo unlock > /proc/keypad
echo unlock > /proc/fiveway
# we're always starting from our working directory
cd /mnt/us/kindlepdfviewer/
# bind-mount system fonts
if ! grep /mnt/us/kindlepdfviewer/fonts/host /proc/mounts; then
mount -o bind /usr/java/lib/fonts /mnt/us/kindlepdfviewer/fonts/host
fi
# check if we are supposed to shut down the Amazon framework
if test "$1" == "--framework_stop"; then
shift 1
/etc/init.d/framework stop
fi
# stop cvm
killall -stop cvm
# finally call reader
./reader.lua "$1" 2> /mnt/us/kindlepdfviewer/crash.log || cat /mnt/us/kindlepdfviewer/crash.log
# unmount system fonts
if grep /mnt/us/kindlepdfviewer/fonts/host /proc/mounts; then
umount /mnt/us/kindlepdfviewer/fonts/host
fi
# always try to continue cvm
killall -cont cvm || /etc/init.d/framework start
# cleanup hanging process
killall lipc-wait-event

@ -39,7 +39,7 @@
lua_State *L;
int main(int argc, char **argv) {
int i, err;
int i;
if(argc < 2) {
fprintf(stderr, "needs config file as first argument.\n");

@ -1,11 +1,11 @@
[Actions]
# start kindlepdfviewer with filebrowser in /mnt/us/documents
P D = !/mnt/us/launchpad/kpdf.sh /mnt/us/documents
P D = !/mnt/us/kindlepdfviewer/kpdf.sh /mnt/us/documents
# start kindlepdfviewer with last document
P P = !/mnt/us/launchpad/kpdf.sh
P P = !/mnt/us/kindlepdfviewer/kpdf.sh
# start kindlepdfviewer without framework in /mnt/us/documents
P K = !/mnt/us/launchpad/kpdf.sh --framework_stop /mnt/us/documents
P K = !/mnt/us/kindlepdfviewer/kpdf.sh --framework_stop /mnt/us/documents
# start kindlepdfviewer without framework on last read document
P L = !/mnt/us/launchpad/kpdf.sh --framework_stop
P L = !/mnt/us/kindlepdfviewer/kpdf.sh --framework_stop
# restart amazon framework - when it got irritated
P R = !/etc/init.d/framework restart

@ -31,7 +31,3 @@ fi
# always try to continue cvm
killall -cont cvm || /etc/init.d/framework start
# cleanup hanging process
killall lipc-wait-event

@ -0,0 +1,86 @@
Index: CREDITS
===================================================================
--- CREDITS (revision 0)
+++ CREDITS (working copy)
@@ -0,0 +1 @@
+Taken from http://code.google.com/p/popen-noshell/
Property changes on: CREDITS
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: Makefile
===================================================================
--- Makefile (revision 0)
+++ Makefile (working copy)
@@ -0,0 +1,17 @@
+SRCS=popen_noshell.c
+
+OBJS:=$(SRCS:%.c=%.o)
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+all: libpopen_noshell.a
+
+libpopen_noshell.a: $(OBJS)
+ $(AR) rcs $@ $(OBJS)
+
+clean:
+ rm -rf *.o
+ rm -rf libpopen_noshell.a
+
+.PHONY: clean
Property changes on: Makefile
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: popen_noshell.c
===================================================================
--- popen_noshell.c (revision 8)
+++ popen_noshell.c (working copy)
@@ -16,6 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses>.
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include "popen_noshell.h"
#include <errno.h>
#include <unistd.h>
@@ -28,10 +32,6 @@
#include <sys/wait.h>
#include <stdlib.h>
#include <inttypes.h>
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
#include <sched.h>
/*
@@ -249,7 +249,7 @@
* The above malloc() + align implementation is taken from:
* http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
*/
-
+
#ifndef POPEN_NOSHELL_VALGRIND_DEBUG
pid = clone(fn, stack_aligned, CLONE_VM | SIGCHLD, arg);
#else
@@ -358,7 +358,7 @@
pclose_arg->fp = fp;
pclose_arg->pid = pid;
-
+
return fp; // we should never end up here
}

@ -42,7 +42,7 @@ function openFile(filename)
reader = ext:getReader(file_type)
if reader then
InfoMessage:show("Opening document... ", 0)
InfoMessage:inform("Opening document... ", nil, 0, MSG_AUX)
reader:preLoadSettings(filename)
local ok, err = reader:open(filename)
if ok then
@ -54,9 +54,9 @@ function openFile(filename)
else
if err then
Debug("openFile(): "..err)
showInfoMsgWithDelay(err:sub(1,30), 2000, 1)
InfoMessage:inform(err:sub(1,30), 2000, 1, MSG_ERROR)
else
showInfoMsgWithDelay("Error opening document ", 2000, 1)
InfoMessage:inform("Error opening document! ", 2000, 1, MSG_ERROR)
end
end
end
@ -140,6 +140,8 @@ end
-- set up the mode to manage files
FileChooser.filemanager_expert_mode = G_reader_settings:readSetting("filemanager_expert_mode") or 1
InfoMessage:initInfoMessageSettings()
-- initialize global settings shared among all readers
UniReader:initGlobalSettings(G_reader_settings)
-- initialize specific readers
@ -171,6 +173,7 @@ end
-- save reader settings
G_reader_settings:saveSetting("fontmap", Font.fontmap)
InfoMessage:saveInfoMessageSettings()
G_reader_settings:close()
-- @TODO dirty workaround, find a way to force native system poll

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

@ -38,7 +38,6 @@ Codes for rotation modes:
0
--]]
Screen = {
cur_rotation_mode = 0,
-- these two variabls are used to help switching from framework to reader
@ -118,7 +117,8 @@ function Screen:screenshot()
local diff = nsecs - secs + (nusecs - usecs)/1000000
--self:fb2bmp("/dev/fb0", lfs.currentdir().."/screenshots/"..os.date("%Y%m%d%H%M%S")..".bmp", true, "bzip2 ")
--self:fb2pgm("/dev/fb0", lfs.currentdir().."/screenshots/"..os.date("%Y%m%d%H%M%S")..".pgm", "bzip2 ", 4)
showInfoMsgWithDelay(string.format("Screenshot is ready in %.2fs ", diff), 2000, 1)
local msg = "Screenshot is ready in "
InfoMessage:inform(msg..string.format("%.2fs ", diff), 2000, 1, MSG_WARN, msg..math.ceil(diff*1000).." milliseconds")
end
-- NuPogodi (02.07.2012): added the functions to save the fb-content in common graphic files - bmp & pgm.

@ -5,22 +5,14 @@ require "font"
require "commands"
SelectMenu = {
-- font for displaying item names
fsize = 22,
-- font for page title
tfsize = 25,
-- font for paging display
ffsize = 16,
-- font for item shortcut
fsize = 22, -- font for displaying item names
tfsize = 25, -- font for page title
ffsize = 16,-- font for paging display
-- title height
title_H = 40,
-- spacing between lines
spacing = 36,
-- foot height
foot_H = 27,
-- horisontal margin
margin_H = 10,
title_H = 40, -- title height
spacing = 36, -- spacing between lines
foot_H = 27, -- foot height
margin_H = 10, -- horisontal margin
current_entry = 0,
menu_title = "No Title",
@ -114,7 +106,7 @@ function SelectMenu:addAllCommands()
end
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, "next",
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(sm)
if sm.page < (sm.items / sm.perpage) then
@ -129,7 +121,7 @@ function SelectMenu:addAllCommands()
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "prev",
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(sm)
if sm.page > 1 then
@ -188,7 +180,7 @@ function SelectMenu:addAllCommands()
table.insert(KEY_Q_to_P, Keydef:new(i, nil, ""))
end
self.commands:addGroup("Q to P", KEY_Q_to_P,
"Select item with Q to P key as shortcut",
"select item with Q to P key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_Q + 1 ], sm.perpage)
@ -199,7 +191,7 @@ function SelectMenu:addAllCommands()
table.insert(KEY_A_to_L, Keydef:new(i, nil, ""))
end
self.commands:addGroup("A to L", KEY_A_to_L,
"Select item with A to L key as shortcut",
"select item with A to L key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_A + 11 ], sm.perpage)
@ -210,55 +202,55 @@ function SelectMenu:addAllCommands()
table.insert(KEY_Z_to_M, Keydef:new(i, nil, ""))
end
self.commands:addGroup("Z to M", KEY_Z_to_M,
"Select item with Z to M key as shortcut",
"select item with Z to M key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_Z + 21 ], sm.perpage)
end
)
self.commands:add(KEY_SLASH, nil, "/",
"Select item with / key as shortcut",
"select item with / key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("/", sm.perpage)
end
)
self.commands:add(KEY_DOT, nil, ".",
"Select item with dot key as shortcut",
"select item with dot key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut(".", sm.perpage)
end
)
self.commands:add(KEY_SYM, nil, "Sym",
"Select item with Sym key as shortcut",
"select item with Sym key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("Sym", sm.perpage)
end
)
self.commands:add(KEY_ENTER, nil, "Enter",
"Select item with Enter key as shortcut",
"select item with Enter key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("Ent", sm.perpage)
end
)
self.commands:add(KEY_BACK, nil, "Back",
"Exit menu",
function(sm)
return "break"
end
)
self.commands:add(KEY_H,MOD_ALT,"H",
"show help page",
function(sm)
HelpPage:show(0, G_height, sm.commands)
sm.pagedirty = true
end)
self.commands:add({KEY_BACK,KEY_HOME}, nil, "Back, Home",
"exit menu",
function(sm)
return "break"
end
)
end
function SelectMenu:clearCommands()
self.commands = Commands:new{}
self.commands:add(KEY_BACK, nil, "",
"Exit menu",
self.commands:add({KEY_BACK,KEY_HOME}, nil, "Back, Home",
"exit menu",
function(sm)
return "break"
end)
@ -352,7 +344,7 @@ function SelectMenu:choose(ypos, height)
end -- for c=1, self.perpage
end -- if self.items == 0
local footer = "Page "..self.page.." of "..(math.ceil(self.items / self.perpage)).." Press Alt-H for help"
local footer = "Page "..self.page.." of "..(math.ceil(self.items / self.perpage)).." - Press Alt-H for help"
renderUtf8Text(fb.bb, self.margin_H, height-7, fface, footer, true)
end

@ -100,6 +100,7 @@ function Debug(...)
end
end
print("#"..line)
return true -- debug enabled
end
-- simple serialization function, won't do uservalues, functions, loops

@ -16,8 +16,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "popen-noshell/popen_noshell.h"
#include <err.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
@ -25,18 +28,19 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>
#define OUTPUT_SIZE 21
#define EVENT_PIPE "/tmp/event_slider"
#define CODE_IN_SAVER 10000
#define CODE_OUT_SAVER 10001
int
main ( int argc, char *argv[] )
{
int fd, ret;
int fd;
FILE *fp;
char std_out[OUTPUT_SIZE] = "";
char std_out[256];
int status;
struct popen_noshell_pass_to_pclose pclose_arg;
struct input_event ev;
__u16 key_code = 10000;
@ -51,7 +55,7 @@ main ( int argc, char *argv[] )
/* open npipe for writing */
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if(fd < 0) {
printf("Open %s falied: %s\n", argv[1], strerror(errno));
printf("Open %s failed: %s\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
@ -60,15 +64,18 @@ main ( int argc, char *argv[] )
ev.code = key_code;
ev.value = 1;
while(1) {
/* listen power slider events */
memset(std_out, 0, OUTPUT_SIZE);
fp = popen("lipc-wait-event -s 0 com.lab126.powerd goingToScreenSaver,outOfScreenSaver", "r");
ret = fread(std_out, OUTPUT_SIZE, 1, fp);
pclose(fp);
/* listen power slider events */
char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver", (char *) NULL};
fp = popen_noshell("lipc-wait-event", (const char * const *)chargv, "r", &pclose_arg, 0);
if (!fp) {
err(EXIT_FAILURE, "popen_noshell()");
}
while(fgets(std_out, sizeof(std_out)-1, fp)) {
/* printf("Got line: %s", std_out); */
/* fill event struct */
gettimeofday(&ev.time, NULL);
if(std_out[0] == 'g') {
ev.code = CODE_IN_SAVER;
} else if(std_out[0] == 'o') {
@ -77,9 +84,29 @@ main ( int argc, char *argv[] )
printf("Unrecognized event.\n");
exit(EXIT_FAILURE);
}
/* fill event struct */
gettimeofday(&ev.time, NULL);
/* printf("Send event %d\n", ev.code); */
/* generate event */
ret = write(fd, &ev, sizeof(struct input_event));
if(write(fd, &ev, sizeof(struct input_event)) == -1) {
printf("Failed to generate event.\n");
}
}
status = pclose_noshell(&pclose_arg);
if (status == -1) {
err(EXIT_FAILURE, "pclose_noshell()");
} else {
printf("Power slider event listener child exited with status %d.\n", status);
if WIFEXITED(status) {
printf("Child exited normally with status: %d.\n", WEXITSTATUS(status));
}
if WIFSIGNALED(status) {
printf("Child terminated by signal: %d.\n", WTERMSIG(status));
}
}
close(fd);

@ -1049,10 +1049,11 @@ function UniReader:drawOrCache(no, preCache)
-- #4 goal: we render next page, too. (TODO)
local pg_w = G_width / ( self.doc:getPages() )
local page_indicator = function()
fb.bb:invertRect( pg_w*(no-1),0, pg_w,10)
fb:refresh(1, pg_w*(no-1),0, pg_w,10)
Debug('page_indicator',no)
local page_indicator = function()
if Debug('page_indicator',no) then
fb.bb:invertRect( pg_w*(no-1),0, pg_w,10)
fb:refresh(1, pg_w*(no-1),0, pg_w,10)
end
end
page_indicator()

Loading…
Cancel
Save