[core] Widget creation/update overhaul
Until now, widgets were re-created during each iteration. For multiple, reasons, using static widget objects is much easier, so instead of creating new widgets continuously, modules now create the widgets during instantiation and get the list of widgets passed as parameter whenever an update occurs. During the update, they can still manipulate the widget list by removing and adding elements as needed. Advantages: * Less memory fragmentation (fewer (de)allocations) * Easier event management (widgets now have static IDs) * Easier module code (widget contents can simply be the result of a callback) see #23
This commit is contained in:
parent
60ae92c8e3
commit
f645203579
9 changed files with 65 additions and 17 deletions
|
@ -12,8 +12,14 @@ class Module(object):
|
||||||
(e.g. CPU utilization, disk usage, etc.) derive from
|
(e.g. CPU utilization, disk usage, etc.) derive from
|
||||||
this base class.
|
this base class.
|
||||||
"""
|
"""
|
||||||
def __init__(self, engine):
|
def __init__(self, engine, widgets):
|
||||||
pass
|
self._widgets = []
|
||||||
|
if widgets:
|
||||||
|
self._widgets = widgets if isinstance(widgets, list) else [widgets]
|
||||||
|
|
||||||
|
def widgets(self):
|
||||||
|
"""Return the widgets to draw for this module"""
|
||||||
|
return self._widgets
|
||||||
|
|
||||||
class Engine(object):
|
class Engine(object):
|
||||||
"""Engine for driving the application
|
"""Engine for driving the application
|
||||||
|
@ -53,11 +59,9 @@ class Engine(object):
|
||||||
"""Start the event loop"""
|
"""Start the event loop"""
|
||||||
self._output.start()
|
self._output.start()
|
||||||
while self.running():
|
while self.running():
|
||||||
widgets = []
|
|
||||||
for module in self._modules:
|
for module in self._modules:
|
||||||
module_widgets = module.widgets()
|
module.update(module.widgets())
|
||||||
widgets += module_widgets if isinstance(module_widgets, list) else [module_widgets]
|
self._output.draw(widgets=module.widgets(), engine=self)
|
||||||
self._output.draw(widgets=widgets, engine=self)
|
|
||||||
self._output.flush()
|
self._output.flush()
|
||||||
if self.running():
|
if self.running():
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
|
@ -7,12 +7,15 @@ import bumblebee.engine
|
||||||
|
|
||||||
class Module(bumblebee.engine.Module):
|
class Module(bumblebee.engine.Module):
|
||||||
def __init__(self, engine):
|
def __init__(self, engine):
|
||||||
super(Module, self).__init__(engine)
|
super(Module, self).__init__(engine,
|
||||||
|
bumblebee.output.Widget(full_text=self.utilization)
|
||||||
|
)
|
||||||
self._utilization = psutil.cpu_percent(percpu=False)
|
self._utilization = psutil.cpu_percent(percpu=False)
|
||||||
|
|
||||||
def widgets(self):
|
def utilization(self):
|
||||||
self._utilization = psutil.cpu_percent(percpu=False)
|
return "{:05.02f}%".format(self._utilization)
|
||||||
|
|
||||||
return bumblebee.output.Widget(full_text="{:05.02f}%".format(self._utilization))
|
def update(self, widgets):
|
||||||
|
self._utilization = psutil.cpu_percent(percpu=False)
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -6,9 +6,11 @@ import bumblebee.engine
|
||||||
|
|
||||||
class Module(bumblebee.engine.Module):
|
class Module(bumblebee.engine.Module):
|
||||||
def __init__(self, engine):
|
def __init__(self, engine):
|
||||||
super(Module, self).__init__(engine)
|
super(Module, self).__init__(engine,
|
||||||
|
bumblebee.output.Widget(full_text="test")
|
||||||
|
)
|
||||||
|
|
||||||
def widgets(self):
|
def update(self, widgets):
|
||||||
return bumblebee.output.Widget(full_text="test")
|
pass
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -12,7 +12,10 @@ class Widget(object):
|
||||||
|
|
||||||
def full_text(self):
|
def full_text(self):
|
||||||
"""Retrieve the full text to display in the widget"""
|
"""Retrieve the full text to display in the widget"""
|
||||||
return self._full_text
|
if callable(self._full_text):
|
||||||
|
return self._full_text()
|
||||||
|
else:
|
||||||
|
return self._full_text
|
||||||
|
|
||||||
class I3BarOutput(object):
|
class I3BarOutput(object):
|
||||||
"""Manage output according to the i3bar protocol"""
|
"""Manage output according to the i3bar protocol"""
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Theme support"""
|
"""Theme support"""
|
||||||
|
|
||||||
class Theme(object):
|
class Theme(object):
|
||||||
|
"""Represents a collection of icons and colors"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
find . -name "*.py"|xargs pylint --disable=R0903,R0201
|
find . -name "*.py"|xargs pylint --disable=R0903,R0201,C0330
|
||||||
|
|
|
@ -10,7 +10,14 @@ class TestCPUModule(unittest.TestCase):
|
||||||
self.module = Module(None)
|
self.module = Module(None)
|
||||||
|
|
||||||
def test_widgets(self):
|
def test_widgets(self):
|
||||||
widget = self.module.widgets()
|
widgets = self.module.widgets()
|
||||||
assertWidgetAttributes(self, widget)
|
for widget in widgets:
|
||||||
|
assertWidgetAttributes(self, widget)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
widgets = self.module.widgets()
|
||||||
|
self.module.update(widgets)
|
||||||
|
self.test_widgets()
|
||||||
|
self.assertEquals(widgets, self.module.widgets())
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
||||||
|
|
25
tests/test_module.py
Normal file
25
tests/test_module.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# pylint: disable=C0103,C0111,W0703
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from bumblebee.engine import Module
|
||||||
|
from tests.util import MockWidget
|
||||||
|
|
||||||
|
class TestModule(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.widget = MockWidget("foo")
|
||||||
|
self.moduleWithoutWidgets = Module(engine=None, widgets=None)
|
||||||
|
self.moduleWithOneWidget = Module(engine=None, widgets=self.widget)
|
||||||
|
self.moduleWithMultipleWidgets = Module(engine=None,
|
||||||
|
widgets=[self.widget, self.widget, self.widget]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_empty_widgets(self):
|
||||||
|
self.assertEquals(self.moduleWithoutWidgets.widgets(), [])
|
||||||
|
|
||||||
|
def test_single_widget(self):
|
||||||
|
self.assertEquals(self.moduleWithOneWidget.widgets(), [self.widget])
|
||||||
|
|
||||||
|
def test_multiple_widgets(self):
|
||||||
|
for widget in self.moduleWithMultipleWidgets.widgets():
|
||||||
|
self.assertEquals(widget, self.widget)
|
|
@ -23,6 +23,9 @@ class MockWidget(object):
|
||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
self._text = text
|
self._text = text
|
||||||
|
|
||||||
|
def update(self, widgets):
|
||||||
|
pass
|
||||||
|
|
||||||
def full_text(self):
|
def full_text(self):
|
||||||
return self._text
|
return self._text
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue