Merge pull request #1168 from hwhw/master

Fix double-check of task list
pull/1171/head
Huang Xin 10 years ago
commit 2dbda247a2

@ -69,6 +69,7 @@ local UIManager = {
_running = true, _running = true,
_window_stack = {}, _window_stack = {},
_execution_stack = {}, _execution_stack = {},
_execution_stack_dirty = false,
_dirty = {}, _dirty = {},
_zeromqs = {}, _zeromqs = {},
} }
@ -232,6 +233,7 @@ end
-- schedule an execution task -- schedule an execution task
function UIManager:schedule(time, action) function UIManager:schedule(time, action)
table.insert(self._execution_stack, { time = time, action = action }) table.insert(self._execution_stack, { time = time, action = action })
self._execution_stack_dirty = true
end end
-- schedule task in a certain amount of seconds (fractions allowed) from now -- schedule task in a certain amount of seconds (fractions allowed) from now
@ -370,131 +372,139 @@ function UIManager:checkTasks()
end end
end end
until all_tasks_checked until all_tasks_checked
return wait_until self._execution_stack_dirty = false
return wait_until, now
end end
-- this is the main loop of the UI controller -- repaint dirty widgets
-- it is intended to manage input events and delegate function UIManager:repaint()
-- them to dialogs local dirty = false
function UIManager:run() local request_full_refresh = false
self._running = true local force_full_refresh = false
while self._running do local force_partial_refresh = false
local now = { util.gettime() } local force_fast_refresh = false
local wait_until = self:checkTasks() for _, widget in ipairs(self._window_stack) do
-- paint if repaint_all is request
--DEBUG("---------------------------------------------------") -- paint also if current widget or any widget underneath is dirty
--DEBUG("exec stack", self._execution_stack) if self.repaint_all or dirty or self._dirty[widget.widget] then
--DEBUG("window stack", self._window_stack) widget.widget:paintTo(Screen.bb, widget.x, widget.y)
--DEBUG("dirty stack", self._dirty)
--DEBUG("---------------------------------------------------")
-- stop when we have no window to show
if #self._window_stack == 0 then
DEBUG("no dialog left to show")
self:quit()
return nil
end
-- repaint dirty widgets if self._dirty[widget.widget] == "auto" then
local dirty = false request_full_refresh = true
local request_full_refresh = false
local force_full_refresh = false
local force_partial_refresh = false
local force_fast_refresh = false
for _, widget in ipairs(self._window_stack) do
-- paint if repaint_all is request
-- paint also if current widget or any widget underneath is dirty
if self.repaint_all or dirty or self._dirty[widget.widget] then
widget.widget:paintTo(Screen.bb, widget.x, widget.y)
if self._dirty[widget.widget] == "auto" then
request_full_refresh = true
end
if self._dirty[widget.widget] == "full" then
force_full_refresh = true
end
if self._dirty[widget.widget] == "partial" then
force_partial_refresh = true
end
if self._dirty[widget.widget] == "fast" then
force_fast_refresh = true
end
-- and remove from list after painting
self._dirty[widget.widget] = nil
-- trigger repaint
dirty = true
end end
end if self._dirty[widget.widget] == "full" then
force_full_refresh = true
if self.full_refresh then end
if self._dirty[widget.widget] == "partial" then
force_partial_refresh = true
end
if self._dirty[widget.widget] == "fast" then
force_fast_refresh = true
end
-- and remove from list after painting
self._dirty[widget.widget] = nil
-- trigger repaint
dirty = true dirty = true
force_full_refresh = true
end end
end
if self.partial_refresh then if self.full_refresh then
dirty = true dirty = true
force_partial_refresh = true force_full_refresh = true
end end
self.repaint_all = false if self.partial_refresh then
self.full_refresh = false dirty = true
self.partial_refresh = false force_partial_refresh = true
end
local refresh_type = self.default_refresh_type
local waveform_mode = self.default_waveform_mode self.repaint_all = false
local wait_for_marker = self.wait_for_every_marker self.full_refresh = false
if dirty then self.partial_refresh = false
if force_partial_refresh or force_fast_refresh then
refresh_type = UPDATE_MODE_PARTIAL local refresh_type = self.default_refresh_type
elseif force_full_refresh or self.refresh_count == self.FULL_REFRESH_COUNT - 1 then local waveform_mode = self.default_waveform_mode
refresh_type = UPDATE_MODE_FULL local wait_for_marker = self.wait_for_every_marker
end if dirty then
-- Handle the waveform mode selection... if force_partial_refresh or force_fast_refresh then
if refresh_type == UPDATE_MODE_FULL then refresh_type = UPDATE_MODE_PARTIAL
waveform_mode = self.full_refresh_waveform_mode elseif force_full_refresh or self.refresh_count == self.FULL_REFRESH_COUNT - 1 then
else refresh_type = UPDATE_MODE_FULL
waveform_mode = self.partial_refresh_waveform_mode end
end -- Handle the waveform mode selection...
if force_fast_refresh then if refresh_type == UPDATE_MODE_FULL then
waveform_mode = self.fast_waveform_mode waveform_mode = self.full_refresh_waveform_mode
-- FIXME: Should we also avoid doing an MXCFB_WAIT_FOR_UPDATE_SUBMISSION for this update? else
--wait_for_marker = false waveform_mode = self.partial_refresh_waveform_mode
end end
-- If the device is REAGL-aware, we're specifically asking for a REAGL update, and we're doing a PARTIAL *reader* refresh, apply some trickery to match the stock reader's behavior if force_fast_refresh then
-- (On most device, REAGL updates are always FULL, but there's no black flash. On devices where this isn't the case [H2O], we're letting the driver do the job by using AUTO). waveform_mode = self.fast_waveform_mode
if not force_partial_refresh and not force_fast_refresh and refresh_type == UPDATE_MODE_PARTIAL and (waveform_mode == WAVEFORM_MODE_REAGL or waveform_mode == NTX_WFM_MODE_GLD16) then -- FIXME: Should we also avoid doing an MXCFB_WAIT_FOR_UPDATE_SUBMISSION for this update?
refresh_type = UPDATE_MODE_FULL --wait_for_marker = false
end end
-- On the other hand, if we asked for a PARTIAL *UI* refresh, fall back to the default waveform mode, which is tailored per-device to hopefully be more appropriate in this instance than the one we use in the reader. -- If the device is REAGL-aware, we're specifically asking for a REAGL update, and we're doing a PARTIAL *reader* refresh, apply some trickery to match the stock reader's behavior
if force_partial_refresh then -- (On most device, REAGL updates are always FULL, but there's no black flash. On devices where this isn't the case [H2O], we're letting the driver do the job by using AUTO).
-- NOTE: Using default_waveform_mode might seem counter-intuitive when we have partial_refresh_waveform_mode, but partial_refresh_waveform_mode is mostly there as a means to flag REAGL-aware devices ;). if not force_partial_refresh and not force_fast_refresh and refresh_type == UPDATE_MODE_PARTIAL and (waveform_mode == WAVEFORM_MODE_REAGL or waveform_mode == NTX_WFM_MODE_GLD16) then
-- Here, we're actually interested in handling PARTIAL, regional (be it properly flagged or not) updates, and not the PARTIAL updates from the reader that actually refresh the whole screen (i.e., those between black flashes). refresh_type = UPDATE_MODE_FULL
waveform_mode = self.default_waveform_mode end
end -- On the other hand, if we asked for a PARTIAL *UI* refresh, fall back to the default waveform mode, which is tailored per-device to hopefully be more appropriate in this instance than the one we use in the reader.
if self.update_regions_func then if force_partial_refresh then
local update_regions = self.update_regions_func() -- NOTE: Using default_waveform_mode might seem counter-intuitive when we have partial_refresh_waveform_mode, but partial_refresh_waveform_mode is mostly there as a means to flag REAGL-aware devices ;).
for _, update_region in ipairs(update_regions) do -- Here, we're actually interested in handling PARTIAL, regional (be it properly flagged or not) updates, and not the PARTIAL updates from the reader that actually refresh the whole screen (i.e., those between black flashes).
-- in some rare cases update region has 1 pixel offset waveform_mode = self.default_waveform_mode
Screen:refresh(refresh_type, waveform_mode, wait_for_marker, end
update_region.x-1, update_region.y-1, if self.update_regions_func then
update_region.w+2, update_region.h+2) local update_regions = self.update_regions_func()
end for _, update_region in ipairs(update_regions) do
else -- in some rare cases update region has 1 pixel offset
Screen:refresh(refresh_type, waveform_mode, wait_for_marker) Screen:refresh(refresh_type, waveform_mode, wait_for_marker,
end update_region.x-1, update_region.y-1,
-- REAGL refreshes are always FULL (but without a black flash), but we want to keep our black flash timeout working, so don't reset the counter on FULL REAGL refreshes... update_region.w+2, update_region.h+2)
if refresh_type == UPDATE_MODE_FULL and waveform_mode ~= WAVEFORM_MODE_REAGL and waveform_mode ~= NTX_WFM_MODE_GLD16 then
self.refresh_count = 0
elseif not force_partial_refresh and not force_full_refresh then
self.refresh_count = (self.refresh_count + 1)%self.FULL_REFRESH_COUNT
end end
self.update_regions_func = nil else
Screen:refresh(refresh_type, waveform_mode, wait_for_marker)
end end
-- REAGL refreshes are always FULL (but without a black flash), but we want to keep our black flash timeout working, so don't reset the counter on FULL REAGL refreshes...
if refresh_type == UPDATE_MODE_FULL and waveform_mode ~= WAVEFORM_MODE_REAGL and waveform_mode ~= NTX_WFM_MODE_GLD16 then
self.refresh_count = 0
elseif not force_partial_refresh and not force_full_refresh then
self.refresh_count = (self.refresh_count + 1)%self.FULL_REFRESH_COUNT
end
self.update_regions_func = nil
end
end
-- this is the main loop of the UI controller
-- it is intended to manage input events and delegate
-- them to dialogs
function UIManager:run()
self._running = true
while self._running do
local wait_until, now
-- run this in a loop, so that paints can trigger events
-- that will be honored when calculating the time to wait
-- for input events:
repeat
wait_until, now = self:checkTasks()
--DEBUG("---------------------------------------------------")
--DEBUG("exec stack", self._execution_stack)
--DEBUG("window stack", self._window_stack)
--DEBUG("dirty stack", self._dirty)
--DEBUG("---------------------------------------------------")
-- stop when we have no window to show
if #self._window_stack == 0 then
DEBUG("no dialog left to show")
self:quit()
return nil
end
self:checkTasks() self:repaint()
until not self._execution_stack_dirty
-- wait for next event -- wait for next event
-- note that we will skip that if in the meantime we have tasks that are ready to run -- note that we will skip that if we have tasks that are ready to run
local input_event = nil local input_event = nil
if not wait_until then if not wait_until then
if #self._zeromqs > 0 then if #self._zeromqs > 0 then
@ -507,7 +517,7 @@ function UIManager:run()
end end
end end
else else
-- no pending task, wait endlessly -- no pending task, wait without timeout
input_event = Input:waitEvent() input_event = Input:waitEvent()
end end
elseif wait_until[1] > now[1] elseif wait_until[1] > now[1]

Loading…
Cancel
Save