diff --git a/blitbuffer.c b/blitbuffer.c index 106a8b286..aef8bab72 100644 --- a/blitbuffer.c +++ b/blitbuffer.c @@ -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!"); } diff --git a/einkfb.c b/einkfb.c index b7784e592..b8eeee2e9 100644 --- a/einkfb.c +++ b/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 . */ +#include #include #include #include @@ -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) { diff --git a/einkfb.h b/einkfb.h index d3c0ca933..f7d3c019f 100644 --- a/einkfb.h +++ b/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 diff --git a/frontend/ui/device.lua b/frontend/ui/device.lua index 2aacc05de..f480ac46e 100644 --- a/frontend/ui/device.lua +++ b/frontend/ui/device.lua @@ -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 diff --git a/frontend/ui/focusmanager.lua b/frontend/ui/focusmanager.lua index 335d40005..8e5394723 100644 --- a/frontend/ui/focusmanager.lua +++ b/frontend/ui/focusmanager.lua @@ -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 diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index 125344e54..3f2674d69 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -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 diff --git a/frontend/ui/menu.lua b/frontend/ui/menu.lua index 9afd5b1f8..30498b9bd 100644 --- a/frontend/ui/menu.lua +++ b/frontend/ui/menu.lua @@ -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 diff --git a/frontend/ui/screen.lua b/frontend/ui/screen.lua index dc0b1d9c6..50469e7c7 100644 --- a/frontend/ui/screen.lua +++ b/frontend/ui/screen.lua @@ -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() diff --git a/frontend/ui/ui.lua b/frontend/ui/ui.lua index 44e5732da..be876c099 100644 --- a/frontend/ui/ui.lua +++ b/frontend/ui/ui.lua @@ -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 diff --git a/input.c b/input.c index 6dce14f50..86e53ca3f 100644 --- a/input.c +++ b/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;