[Panel-devel] dataengines and timing revisited
Aaron J. Seigo
aseigo at kde.org
Thu Aug 30 04:40:58 CEST 2007
hi =)
a few weeks ago Michael Olbrich posted a patch to allow applets (or whatever)
to determine when they should be notified of an update. there were a few
things neither of us was really happy about the patch, but it was a good run
at it.
today i sat down and drew some pictures and wrote some words using ink on
paper. totally old school. made me remember (a) why we have computers (my
hand writing is horrid) and (b) what computers still suck at (sketching
notes[1]).
here's what i came up powered by the old school love of pen 'n paper:
we can divide the problem into three parts:
Engine updating (U) its data
U(1) it knows when to update its data, don't try and tell it otherwise
U(2) engine updates on demand and should avoid updating otherwise
Engine data collection (C) methods
C(1) synchronous
C(2) asynchronous
Applet access (A) to data
A(1) wants data whenever it arrives/changes (rely on the engine)
A(2) wants data updated periodically (every N ms kick the engine)
and all combinations of U, C and A are valid. meh. this is why i hadn't yet
either simply whipped up a modification of Michael's patch or something new
off the cuff and committed it already =)
this can pretty easily lead to insanities where expensive updates are done
multiple times in a row or a request is triggered by an applet's update
frequency but the data won't arrive until some unknown time in the future.
so i'm proposing the following API in DataEngine:
public:
setMinimumUpdateFrequency(int) and int minimumUpdateFrequency() const
sets the minimumt time in ms between updates.
< 0 == never update on demand; just let the engine handle it
0 == update immediately on (every) demand
>0 == the number of ms that must pass before updates
i'm still not sure on the default. maybe 500ms?
an rss feed engine may want to have it at 60000 or even higher
a cpu temp engine might want it to 0ms or perhaps 20ms
a hotplug engine probably wants it at -1
protected:
setUpdateFrequency(int) and int updateFrequency() const
provides a built in timer for the engine (using timerEvent()) and cooperates
with minUpdateFrequency(), so if an applet kicks an update for a source this
won't cause a second update to that source
virtual bool updateSource(const QString& source)
called when a source should be updated.
the default implementation is {return true; }
false is returned when an update is started but async, meaning that emitting
the proxy QObject's updated signal should occur later in time with the next
Applet::updated() signal when setData() is called; this implies keeping a
list of objects needing to emit around. it also implies that updates only
happen when the data arrives; if there are assumptions otherwise in applets,
they are broken imho.
timerEvent()
goes through each source and calls updateSource; time out is updateFrequency
goes through each source, checks the update freq and if they need it,
pumps the engine fo an update of the data.
this may cause the Applet::updated() signal to be emitted.
connectSource and connectAllsources now take an optional update frequency,
much as in Michael's patch
the code then works something like this:
connectSource will connect the applet to the DataContainer's updated() signal
if the updateFrequency < 1. otherwise we round updateFrequency to a sane
number and create a QObject that stands in and emits the signal every
qMin(updateFrequency, minimumUpdateFrequency()). much as in Michael's patch,
these objects will be shared between objects with the same requested
frequency period. there won't be a manager for them, however; that will all
go into DataContainer itself at this point, i think. if this becomes a
generally useful pattern, we can abstract it out into its own class.
care needs to be taken to ensure that:
- the DataContainer::updated() signal is emitted when data changes; this
keeps DataContainer generally useful and obvious in use for the simple case
- DataContainers are auto-removed appropriately
- async updates are indeed propogated properly
when a update request gets fired from a DataContainer, the engine will decide
whether or not to update based on the last updated time. this implies adding
a timestamp to each DataContainer. this should hopefully prevent a lot of
expensive re-updating.
this is obviously more complicated than what is there right now but i think it
is a bit more straight forward than Michael's original patch, introduces
fewer classes and doesn't introduce regressions in behaviour AFAICS. if there
are no objections to this approach, i will be finishing this up and
committing it tomorrow.
remaining caveats: the clock has an interesting problem where it really wants
to pin the ticks to clock ticks, especially for the minutes-only ... i have
yet to figure out how to arrange that. without it, it is possible for the
ticks to drift dramatically so that the time is up 59s out. maybe it's just
me, but that would suck =) if someone provides a clock that just shows the
hour, that could be even worse. then again, perhaps the clock, as a special
case, just continues to manage its own update ticks.
other cool things that could be added: sharing ticks between engines. feels
like a premature optimization at this point, though it might be nice for
power consumption ... in any case, we'll see.
[1] it occurs to me that a -really- good note sketcher + inexpensive pen
device would be a terrific app. i've seem some note takers and they all suck.
[2] nearest 50ms? that gives up to 20 updates a second. should be enough?
--
Aaron J. Seigo
humru othro a kohnu se
GPG Fingerprint: 8B8B 2209 0C6F 7C47 B1EA EE75 D6B7 2EB1 A7F1 DB43
KDE core developer sponsored by Trolltech
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://mail.kde.org/pipermail/panel-devel/attachments/20070829/aff7427e/attachment-0001.pgp
More information about the Panel-devel
mailing list