mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Merge pull request #210 from houqp/new_ui_code
k4 framebuffer support rewrite & screen saver, usb plugin support
This commit is contained in:
@@ -92,7 +92,7 @@ static int blitFullToBuffer(lua_State *L) {
|
||||
BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer");
|
||||
BlitBuffer *src = (BlitBuffer*) luaL_checkudata(L, 2, "blitbuffer");
|
||||
|
||||
if(src->w != dst->w || src->h != dst->h) {
|
||||
if(src->w != dst->w || src->h != dst->h || src->pitch != dst->pitch) {
|
||||
return luaL_error(L, "blitbuffer size must be framebuffer size!");
|
||||
}
|
||||
|
||||
|
||||
70
einkfb.c
70
einkfb.c
@@ -15,6 +15,7 @@
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -26,6 +27,7 @@
|
||||
static int openFrameBuffer(lua_State *L) {
|
||||
const char *fb_device = luaL_checkstring(L, 1);
|
||||
FBInfo *fb = (FBInfo*) lua_newuserdata(L, sizeof(FBInfo));
|
||||
uint8_t *fb_map_address = NULL;
|
||||
|
||||
luaL_getmetatable(L, "einkfb");
|
||||
|
||||
@@ -73,13 +75,38 @@ static int openFrameBuffer(lua_State *L) {
|
||||
}
|
||||
|
||||
/* mmap the framebuffer */
|
||||
fb->buf->data = mmap(0, fb->finfo.smem_len,
|
||||
fb->buf->pitch = fb->finfo.line_length;
|
||||
fb_map_address = mmap(0, fb->finfo.smem_len,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0);
|
||||
if(fb->buf->data == MAP_FAILED) {
|
||||
if(fb_map_address == MAP_FAILED) {
|
||||
return luaL_error(L, "cannot mmap framebuffer");
|
||||
}
|
||||
memset(fb->buf->data, 0, fb->finfo.smem_len);
|
||||
fb->buf->pitch = fb->finfo.line_length;
|
||||
if (fb->vinfo.bits_per_pixel != 4) {
|
||||
/* for 8bpp K4, we create a shadow 4bpp blitbuffer
|
||||
* K4 uses 16 scale 8bpp framebuffer, so we still cheat it as 4bpp */
|
||||
fb->buf->pitch = fb->buf->pitch / 2;
|
||||
|
||||
fb->buf->data = (uint8_t *)calloc(fb->buf->pitch * fb->vinfo.yres, sizeof(uint8_t));
|
||||
if (!fb->buf->data) {
|
||||
return luaL_error(L, "failed to allocate memory for framebuffer's shadow blitbuffer!");
|
||||
}
|
||||
fb->buf->allocated = 1;
|
||||
|
||||
fb->real_buf = (BlitBuffer *)malloc(sizeof(BlitBuffer));
|
||||
if (!fb->buf->data) {
|
||||
return luaL_error(L, "failed to allocate memory for framebuffer's blitbuffer!");
|
||||
}
|
||||
fb->real_buf->pitch = fb->finfo.line_length;
|
||||
fb->real_buf->w = fb->vinfo.xres;
|
||||
fb->real_buf->h = fb->vinfo.yres;
|
||||
fb->real_buf->allocated = 0;
|
||||
fb->real_buf->data = fb_map_address;
|
||||
} else {
|
||||
/* for K2, K3 and DXG, we map framebuffer to fb->buf->data directly */
|
||||
fb->real_buf = NULL;
|
||||
fb->buf->data = fb_map_address;
|
||||
fb->buf->allocated = 0;
|
||||
}
|
||||
#else
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
return luaL_error(L, "cannot initialize SDL.");
|
||||
@@ -98,7 +125,7 @@ static int openFrameBuffer(lua_State *L) {
|
||||
#endif
|
||||
fb->buf->w = fb->vinfo.xres;
|
||||
fb->buf->h = fb->vinfo.yres;
|
||||
fb->buf->allocated = 0;
|
||||
memset(fb->buf->data, 0, fb->buf->pitch * fb->buf->h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -114,7 +141,12 @@ static int closeFrameBuffer(lua_State *L) {
|
||||
// should be save if called twice
|
||||
if(fb->buf != NULL && fb->buf->data != NULL) {
|
||||
#ifndef EMULATE_READER
|
||||
munmap(fb->buf->data, fb->finfo.smem_len);
|
||||
if (fb->vinfo.bits_per_pixel != 4) {
|
||||
munmap(fb->real_buf->data, fb->finfo.smem_len);
|
||||
free(fb->buf->data);
|
||||
} else {
|
||||
munmap(fb->buf->data, fb->finfo.smem_len);
|
||||
}
|
||||
close(fb->fd);
|
||||
#else
|
||||
free(fb->buf->data);
|
||||
@@ -133,24 +165,25 @@ static int einkUpdate(lua_State *L) {
|
||||
// for Kindle e-ink display
|
||||
int fxtype = luaL_optint(L, 2, 0);
|
||||
#ifndef EMULATE_READER
|
||||
int i = 0, j = 0, h = 0, w = 0;
|
||||
int i = 0, j = 0, h = 0, w = 0, pitch = 0;
|
||||
uint8_t *fb_buf = NULL;
|
||||
|
||||
/* dulplicate 4bpp to 8bpp */
|
||||
/* copy bitmap from 4bpp shadow blitbuffer to framebuffer */
|
||||
if (fb->vinfo.bits_per_pixel != 4) {
|
||||
fb_buf = fb->buf->data;
|
||||
h = fb->buf->h;
|
||||
w = fb->buf->w;
|
||||
pitch = fb->buf->pitch;
|
||||
|
||||
for (i = (h-1); i > 0; i--) {
|
||||
for (j = (w-1)/2; j > 0; j--) {
|
||||
fb_buf[i*w + j*2] = fb_buf[i*w + j];
|
||||
fb_buf[i*w + j*2] &= 0xF0;
|
||||
fb_buf[i*w + j*2] |= fb_buf[i*w + j*2]>>4 & 0x0F;
|
||||
fb->real_buf->data[i*w + j*2] = fb_buf[i*pitch + j];
|
||||
fb->real_buf->data[i*w + j*2] &= 0xF0;
|
||||
fb->real_buf->data[i*w + j*2] |= fb_buf[i*pitch + j]>>4 & 0x0F;
|
||||
|
||||
fb_buf[i*w + j*2 + 1] = fb_buf[i*w + j];
|
||||
fb_buf[i*w + j*2 + 1] &= 0x0F;
|
||||
fb_buf[i*w + j*2 + 1] |= fb_buf[i*w + j*2 + 1]<<4 & 0xF0;
|
||||
fb->real_buf->data[i*w + j*2 + 1] = fb_buf[i*pitch + j];
|
||||
fb->real_buf->data[i*w + j*2 + 1] &= 0x0F;
|
||||
fb->real_buf->data[i*w + j*2 + 1] |= fb_buf[i*pitch + j]<<4 & 0xF0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,15 +196,6 @@ static int einkUpdate(lua_State *L) {
|
||||
myarea.buffer = NULL;
|
||||
myarea.which_fx = fxtype ? fx_update_partial : fx_update_full;
|
||||
ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea);
|
||||
|
||||
/* revert 8bpp to 4bpp */
|
||||
if (fb->vinfo.bits_per_pixel != 4) {
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w/2; j++) {
|
||||
fb_buf[i*w + j] = (fb_buf[i*w + j*2] & 0xF0) | (fb_buf[i*w + j*2 + 1] & 0x0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// for now, we only do fullscreen blits in emulation mode
|
||||
if (fxtype == 0) {
|
||||
|
||||
1
einkfb.h
1
einkfb.h
@@ -38,6 +38,7 @@ struct fb_var_screeninfo {
|
||||
typedef struct FBInfo {
|
||||
int fd;
|
||||
BlitBuffer *buf;
|
||||
BlitBuffer *real_buf;
|
||||
#ifdef EMULATE_READER
|
||||
SDL_Surface *screen;
|
||||
#else
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
function util.isKindle4()
|
||||
Device = {
|
||||
screen_saver_mode = false,
|
||||
charging_mode = false,
|
||||
}
|
||||
|
||||
function Device:isKindle4()
|
||||
re_val = os.execute("cat /proc/cpuinfo | grep MX50")
|
||||
if re_val == 0 then
|
||||
return true
|
||||
@@ -7,7 +12,7 @@ function util.isKindle4()
|
||||
end
|
||||
end
|
||||
|
||||
function util.isKindle3()
|
||||
function Device:isKindle3()
|
||||
re_val = os.execute("cat /proc/cpuinfo | grep MX35")
|
||||
if re_val == 0 then
|
||||
return true
|
||||
@@ -16,7 +21,7 @@ function util.isKindle3()
|
||||
end
|
||||
end
|
||||
|
||||
function util.isKindle2()
|
||||
function Device:isKindle2()
|
||||
re_val = os.execute("cat /proc/cpuinfo | grep MX3")
|
||||
if re_val == 0 then
|
||||
return true
|
||||
@@ -24,3 +29,64 @@ function util.isKindle2()
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function Device:intoScreenSaver()
|
||||
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == false and self.screen_saver_mode == false then
|
||||
Screen:saveCurrentBB()
|
||||
msg = InfoMessage:new{"Going into screensaver... "}
|
||||
UIManager:show(msg)
|
||||
|
||||
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
|
||||
Screen.fb:setOrientation(Screen.native_rotation_mode)
|
||||
util.sleep(1)
|
||||
os.execute("killall -cont cvm")
|
||||
self.screen_saver_mode = true
|
||||
|
||||
UIManager:close(msg)
|
||||
end
|
||||
end
|
||||
|
||||
function Device:outofScreenSaver()
|
||||
--os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt")
|
||||
if self.screen_saver_mode == true and self.charging_mode == false then
|
||||
util.usleep(1500000)
|
||||
os.execute("killall -stop cvm")
|
||||
Screen.fb:setOrientation(Screen.kpv_rotation_mode)
|
||||
Screen:restoreFromSavedBB()
|
||||
Screen.fb:refresh(0)
|
||||
end
|
||||
self.screen_saver_mode = false
|
||||
end
|
||||
|
||||
function Device:usbPlugIn()
|
||||
--os.execute("echo 'usb in' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == false and self.screen_saver_mode == false then
|
||||
Screen:saveCurrentBB()
|
||||
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
|
||||
Screen.fb:setOrientation(Screen.native_rotation_mode)
|
||||
msg = InfoMessage:new{"Going into USB mode... "}
|
||||
UIManager:show(msg)
|
||||
util.sleep(1)
|
||||
UIManager:close(msg)
|
||||
os.execute("killall -cont cvm")
|
||||
end
|
||||
self.charging_mode = true
|
||||
end
|
||||
|
||||
function Device:usbPlugOut()
|
||||
--os.execute("echo 'usb out' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == true and self.screen_saver_mode == false then
|
||||
util.usleep(1500000)
|
||||
os.execute("killall -stop cvm")
|
||||
Screen.fb:setOrientation(Screen.kpv_rotation_mode)
|
||||
Screen:restoreFromSavedBB()
|
||||
Screen.fb:refresh(0)
|
||||
end
|
||||
|
||||
--@TODO signal filemanager for file changes 13.06 2012 (houqp)
|
||||
--FileChooser:setPath(FileChooser.path)
|
||||
--FileChooser.pagedirty = true
|
||||
|
||||
self.charging_mode = false
|
||||
end
|
||||
|
||||
@@ -76,7 +76,7 @@ function FocusManager:onFocusMove(args)
|
||||
current_item:handleEvent(Event:new("Unfocus"))
|
||||
self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus"))
|
||||
-- trigger a repaint (we need to be the registered widget!)
|
||||
UIManager:setDirty(self)
|
||||
UIManager:setDirty(self, "partial")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
@@ -139,6 +139,11 @@ Input = {
|
||||
[191] = "RPgFwd", -- K[3] & k[4]
|
||||
[193] = "LPgFwd", -- K[3] only
|
||||
[194] = "Press", -- K[3] & k[4]
|
||||
|
||||
[10000] = "IntoSS", -- go into screen saver
|
||||
[10001] = "OutOfSS", -- go out of screen saver
|
||||
[10020] = "Charging",
|
||||
[10021] = "NotCharging",
|
||||
},
|
||||
sdl_event_map = {
|
||||
[10] = "1", [11] = "2", [12] = "3", [13] = "4", [14] = "5", [15] = "6", [16] = "7", [17] = "8", [18] = "9", [19] = "0",
|
||||
@@ -224,7 +229,7 @@ function Input:init()
|
||||
-- SDL key codes
|
||||
self.event_map = self.sdl_event_map
|
||||
else
|
||||
input.open("slider")
|
||||
input.open("fake_events")
|
||||
input.open("/dev/input/event0")
|
||||
input.open("/dev/input/event1")
|
||||
|
||||
@@ -232,12 +237,12 @@ function Input:init()
|
||||
local f=lfs.attributes("/dev/input/event2")
|
||||
if f then
|
||||
input.open("/dev/input/event2")
|
||||
if util.isKindle3() then
|
||||
if Device:isKindle3() then
|
||||
print("Auto-detected Kindle 3")
|
||||
end
|
||||
end
|
||||
|
||||
if util.isKindle4() then
|
||||
if Device:isKindle4() then
|
||||
print("Auto-detected Kindle 4")
|
||||
self:adjustKindle4EventMap()
|
||||
end
|
||||
@@ -283,6 +288,20 @@ function Input:waitEvent(timeout_us, timeout_s)
|
||||
keycode = self.rotation_map[self.rotation][keycode]
|
||||
end
|
||||
|
||||
if keycode == "IntoSS" then
|
||||
Device:intoScreenSaver()
|
||||
return
|
||||
elseif keycode == "OutOfSS" then
|
||||
Device:outofScreenSaver()
|
||||
return
|
||||
elseif keycode == "Charging" then
|
||||
Device:usbPlugIn()
|
||||
return
|
||||
elseif keycode == "NotCharging" then
|
||||
Device:usbPlugOut()
|
||||
return
|
||||
end
|
||||
|
||||
-- handle modifier keys
|
||||
if self.modifiers[keycode] ~= nil then
|
||||
if ev.value == EVENT_VALUE_KEY_PRESS then
|
||||
|
||||
@@ -118,7 +118,7 @@ function MenuItem:init()
|
||||
end
|
||||
|
||||
function MenuItem:onFocus()
|
||||
self._underline_container.color = 10
|
||||
self._underline_container.color = 15
|
||||
self.key_events = self.active_key_events
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -94,7 +94,7 @@ function Screen:setRotationMode(mode)
|
||||
end
|
||||
|
||||
function Screen:saveCurrentBB()
|
||||
local width, height = self:getWidth(), self.getHeight()
|
||||
local width, height = self:getWidth(), self:getHeight()
|
||||
|
||||
if not self.saved_bb then
|
||||
self.saved_bb = Blitbuffer.new(width, height)
|
||||
@@ -103,7 +103,7 @@ function Screen:saveCurrentBB()
|
||||
self.saved_bb:free()
|
||||
self.saved_bb = Blitbuffer.new(width, height)
|
||||
end
|
||||
self.saved_bb:blitFullFrom(fb.bb)
|
||||
self.saved_bb:blitFullFrom(self.fb.bb)
|
||||
end
|
||||
|
||||
function Screen:restoreFromSavedBB()
|
||||
|
||||
@@ -14,7 +14,7 @@ Input:init()
|
||||
-- there is only one instance of this
|
||||
UIManager = {
|
||||
-- change this to set refresh type for next refresh
|
||||
refresh_type = 1, -- defaults to 1 initially but will be set to 0 after each refresh
|
||||
refresh_type = 1, -- defaults to 1 initially and will be set to 1 after each refresh
|
||||
|
||||
_running = true,
|
||||
_window_stack = {},
|
||||
@@ -70,8 +70,15 @@ function UIManager:scheduleIn(seconds, action)
|
||||
end
|
||||
|
||||
-- register a widget to be repainted
|
||||
function UIManager:setDirty(widget)
|
||||
self._dirty[widget] = true
|
||||
function UIManager:setDirty(widget, refresh_type)
|
||||
if not refresh_type then
|
||||
refresh_type = "full"
|
||||
elseif refresh_type == 0 then
|
||||
refresh_type = "full"
|
||||
elseif refresh_type == 1 then
|
||||
refresh_type = "partial"
|
||||
end
|
||||
self._dirty[widget] = refresh_type
|
||||
end
|
||||
|
||||
-- signal to quit
|
||||
@@ -144,21 +151,34 @@ function UIManager:run()
|
||||
|
||||
-- repaint dirty widgets
|
||||
local dirty = false
|
||||
local update_area = Geom:new{}
|
||||
for _, widget in ipairs(self._window_stack) do
|
||||
if self._dirty[widget.widget] then
|
||||
widget_dimen = widget.widget:getSize()
|
||||
if widget_dimen then
|
||||
widget_area = Geom:new{
|
||||
x = widget.x, y = widget.y,
|
||||
w = widget_dimen.w, h = widget_dimen.h}
|
||||
update_area = update_area:combine(widget_area)
|
||||
end
|
||||
widget.widget:paintTo(Screen.fb.bb, widget.x, widget.y)
|
||||
if self._dirty[widget.widget] == "full" then
|
||||
self.refresh_type = 0
|
||||
end
|
||||
-- and remove from list after painting
|
||||
self._dirty[widget.widget] = nil
|
||||
-- trigger repaint
|
||||
dirty = true
|
||||
end
|
||||
end
|
||||
-- @TODO make use of update_area on refresh 19.06 2012 (houqp)
|
||||
--DEBUG(update_area)
|
||||
|
||||
if dirty then
|
||||
-- refresh FB
|
||||
Screen.fb:refresh(self.refresh_type) -- TODO: refresh explicitly only repainted area
|
||||
-- reset refresh_type
|
||||
self.refresh_type = 0
|
||||
self.refresh_type = 1
|
||||
end
|
||||
|
||||
-- wait for next event
|
||||
|
||||
2
input.c
2
input.c
@@ -58,7 +58,7 @@ static int openInputDevice(lua_State *L) {
|
||||
return luaL_error(L, "no free slot for new input device <%s>", inputdevice);
|
||||
}
|
||||
|
||||
if(!strcmp("slider",inputdevice)) {
|
||||
if(!strcmp("fake_events",inputdevice)) {
|
||||
/* special case: the power slider */
|
||||
int pipefd[2];
|
||||
int childpid;
|
||||
|
||||
Reference in New Issue
Block a user