From: Felix Domke Date: Sun, 23 Jan 2005 23:14:14 +0000 (+0000) Subject: - allow close of dialog X-Git-Tag: 2.6.0~5943 X-Git-Url: https://git.cweiske.de/enigma2.git/commitdiff_plain/4c9d04cb33fb06dfa075b431e36e7ea938a5f963?hp=9202d4248dd7df2f6e5eb53b4154c8297ec9b1d1 - allow close of dialog - some eWidget fixes - background for eWidgetDesktop - introduce "session" object --- diff --git a/components.py b/components.py index 8ae48068..4c26c0a0 100644 --- a/components.py +++ b/components.py @@ -1,5 +1,6 @@ from enigma import * import time +import sys # some helper classes first: class HTMLComponent: @@ -20,12 +21,72 @@ class HTMLSkin: return res class GUISkin: - data = { } + def __init__(self): + self.data = { } + def createGUIScreen(self, parent): for (name, val) in self.items(): self.data[name] = { } val.GUIcreate(self.data[name], parent, None) + + def deleteGUIScreen(self): + for (name, val) in self.items(): + w = self.data[name]["instance"] + val.GUIdelete(self.data[name]) + del self.data[name] + + # note: you'll probably run into this assert. if this happens, don't panic! + # yes, it's evil. I told you that programming in python is just fun, and + # suddently, you have to care about things you don't even know. + # + # but calm down, the solution is easy, at least on paper: + # + # Each Component, which is a GUIComponent, owns references to each + # instantiated eWidget (namely in screen.data[name]["instance"], in case + # you care.) + # on deleteGUIscreen, all eWidget *must* (!) be deleted (otherwise, + # well, problems appear. I don't want to go into details too much, + # but this would be a memory leak anyway.) + # The assert beyond checks for that. It asserts that the corresponding + # eWidget is about to be removed (i.e., that the refcount becomes 0 after + # running deleteGUIscreen). + # (You might wonder why the refcount is checked for 2 and not for 1 or 0 - + # one reference is still hold by the local variable 'w', another one is + # hold be the function argument to sys.getrefcount itself. So only if it's + # 2 at this point, the object will be destroyed after leaving deleteGUIscreen.) + # + # Now, how to fix this problem? You're holding a reference somewhere. (References + # can only be hold from Python, as eWidget itself isn't related to the c++ + # way of having refcounted objects. So it must be in python.) + # + # It could be possible that you're calling deleteGUIscreen trough a call of + # a PSignal. For example, you could try to call session.close() in response + # to a Button::click. This will fail. (It wouldn't work anyway, as you would + # remove a dialog while running it. It never worked - enigma1 just set a + # per-mainloop variable on eWidget::close() to leave the exec()...) + # That's why Session supports delayed closes. Just call Session.close() and + # it will work. + # + # Another reason is that you just stored the data["instance"] somewhere. or + # added it into a notifier list and didn't removed it. + # + # If you can't help yourself, just ask me. I'll be glad to help you out. + # Sorry for not keeping this code foolproof. I really wanted to archive + # that, but here I failed miserably. All I could do was to add this assert. + assert sys.getrefcount(w) == 2, "too many refs hold to " + str(w) + + def close(self): + self.deleteGUIScreen() + del self.data + +# note: components can be used in multiple screens, so we have kind of +# two contexts: first the per-component one (self), then the per-screen (i.e.: +# per eWidget one), called "priv". In "priv", for example, the instance +# of the eWidget is stored. + +# GUI components have a "notifier list" of associated eWidgets to one component +# (as said - one component instance can be used at multiple screens) class GUIComponent: """ GUI component """ @@ -38,6 +99,16 @@ class GUIComponent: self.notifier.append(i) if self.notifierAdded: self.notifierAdded(i) + + # GUIdelete must delete *all* references to the current component! + def GUIdelete(self, priv): + g = priv["instance"] + self.notifier.remove(g) + self.GUIdeleteInstance(g) + del priv["instance"] + + def GUIdeleteInstance(self, priv): + pass class VariableText: """VariableText can be used for components which have a variable text, based on any widget with setText call""" @@ -107,19 +178,11 @@ class Button(HTMLComponent, GUIComponent, VariableText): self.setText(text) self.onClick = [ ] - def clicked(self): + def push(self): for x in self.onClick: x() return 0 - - def GUIcreate(self, priv, parent, skindata): - GUIComponent.GUIcreate(self, priv,parent, skindata) - priv["instance"].selected.get().append(self.clicked) - def click(self): - for x in self.onClick: - x() - # html: def produceHTML(self): return "\n" @@ -127,8 +190,11 @@ class Button(HTMLComponent, GUIComponent, VariableText): # GUI: def GUIcreateInstance(self, priv, parent, skindata): g = eButton(parent) -# g.clicked = [ self.click ] + g.selected.get().append(self.push) return g + + def GUIdeleteInstance(self, g): + g.selected.get().remove(self.push) class Header(HTMLComponent, GUIComponent, VariableText): @@ -155,4 +221,3 @@ class VolumeBar(HTMLComponent, GUIComponent, VariableValue): g = eSlider(parent) g.setRange(0, 100) return g - diff --git a/lib/Makefile.am b/lib/Makefile.am index f33133b8..a09b9bc1 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1 +1 @@ -SUBDIRS = base dvb dvb_si gdi network service driver nav content gui python +SUBDIRS = base dvb dvb_si gdi network service driver nav gui python diff --git a/lib/gui/ewidget.cpp b/lib/gui/ewidget.cpp index 3ebac357..7f089361 100644 --- a/lib/gui/ewidget.cpp +++ b/lib/gui/ewidget.cpp @@ -10,7 +10,7 @@ eWidget::eWidget(eWidget *parent): m_parent(parent ? parent->child() : 0) if (m_parent) m_vis = wVisShow; - + if (m_parent) { m_parent->m_childs.push_back(this); @@ -109,7 +109,17 @@ void eWidget::show() void eWidget::hide() { + /* TODO: when hiding an upper level widget, widgets get hidden but keep the */ + /* wVisShow flag (because when the widget is shown again, the widgets must */ + /* become visible again. */ + if (!(m_vis & wVisShow)) + return; m_vis &= ~wVisShow; + + /* this is a workaround to the above problem. when we are in the delete phase, + don't hide childs. */ + if (!(m_parent || m_desktop)) + return; /* TODO: optimize here to only recalc what's required. possibly merge with show. */ eWidget *root = this; @@ -137,9 +147,13 @@ void eWidget::destruct() eWidget::~eWidget() { + hide(); + if (m_parent) m_parent->m_childs.remove(this); + m_parent = 0; + /* destroy all childs */ ePtrList::iterator i(m_childs.begin()); while (i != m_childs.end()) diff --git a/lib/gui/ewidgetdesktop.cpp b/lib/gui/ewidgetdesktop.cpp index bb6c7c39..1b5cf9b2 100644 --- a/lib/gui/ewidgetdesktop.cpp +++ b/lib/gui/ewidgetdesktop.cpp @@ -42,11 +42,10 @@ void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visib void eWidgetDesktop::recalcClipRegions() { - gRegion screen = gRegion(eRect(ePoint(0, 0), m_screen_size)); + m_background_region = gRegion(eRect(ePoint(0, 0), m_screen_size)); for (ePtrList::iterator i(m_root.begin()); i != m_root.end(); ++i) - calcWidgetClipRegion(*i, screen); -// dumpRegion(screen); + calcWidgetClipRegion(*i, m_background_region); } void eWidgetDesktop::invalidate(const gRegion ®ion) @@ -56,12 +55,33 @@ void eWidgetDesktop::invalidate(const gRegion ®ion) m_dirty_region |= region; } +void eWidgetDesktop::setBackgroundColor(gColor col) +{ + m_background_color = col; + + /* if there's something visible from the background, redraw it with the new color. */ + if (m_dc && m_background_region.valid() && !m_background_region.empty()) + { + /* todo: split out "setBackgroundColor / clear"... maybe? */ + gPainter painter(m_dc); + painter.resetClip(m_background_region); + painter.setBackgroundColor(m_background_color); + painter.clear(); + } +} + void eWidgetDesktop::paint() { gPainter painter(m_dc); /* walk all root windows. */ for (ePtrList::iterator i(m_root.begin()); i != m_root.end(); ++i) i->doPaint(painter, m_dirty_region); + m_dirty_region &= m_background_region; + + painter.resetClip(m_dirty_region); + painter.setBackgroundColor(m_background_color); + painter.clear(); + m_dirty_region = gRegion(); } diff --git a/lib/gui/ewidgetdesktop.h b/lib/gui/ewidgetdesktop.h index 1354a86b..f76baf60 100644 --- a/lib/gui/ewidgetdesktop.h +++ b/lib/gui/ewidgetdesktop.h @@ -13,7 +13,9 @@ class eWidgetDesktop: public Object public: // weil debug eSize m_screen_size; gRegion m_dirty_region; + gRegion m_background_region; ePtr m_dc; + gColor m_background_color; public: eWidgetDesktop(eSize screen); ~eWidgetDesktop(); @@ -25,6 +27,8 @@ public: void paint(); void setDC(gDC *dc); + void setBackgroundColor(gColor col); + void setRedrawTask(eMainloop &ml); private: ePtrList m_root; diff --git a/main/Makefile.am b/main/Makefile.am index 46ce98b1..e0e7e79b 100644 --- a/main/Makefile.am +++ b/main/Makefile.am @@ -9,7 +9,6 @@ enigma2_SOURCES = \ enigma2_LDADD_WHOLE = \ $(top_builddir)/lib/base/libenigma_base.a \ - $(top_builddir)/lib/content/libenigma_content.a \ $(top_builddir)/lib/driver/libenigma_driver.a \ $(top_builddir)/lib/dvb/libenigma_dvb.a \ $(top_builddir)/lib/dvb_si/libenigma_dvb_si.a \ diff --git a/main/enigma.cpp b/main/enigma.cpp index faff4d89..92982e5b 100644 --- a/main/enigma.cpp +++ b/main/enigma.cpp @@ -105,6 +105,7 @@ int main(int argc, char **argv) eWidgetDesktop dsk(eSize(720, 576)); wdsk = &dsk; + dsk.setBackgroundColor(gColor(0)); dsk.setDC(my_dc); #endif diff --git a/mytest.py b/mytest.py index 0cbeac02..54f0f862 100644 --- a/mytest.py +++ b/mytest.py @@ -29,7 +29,6 @@ screens["global"](components) # test our screens components["$001"] = screens["testDialog"]() -components["$002"] = screens["clockDisplay"](components["clock"]) print "*** classes:" dump(screens) @@ -55,24 +54,65 @@ class GUIOutputDevice(OutputDevice): def create(self, comp): comp.createGUIScreen(self.parent) -def runScreenTest(): - desktop = getDesktop() - - wnd = eWindow(desktop) - mainwnd = wnd - wnd.setTitle("Screen from python!") - wnd.move(ePoint(300, 100)) - wnd.resize(eSize(300, 300)) +class Session: + def __init__(self): + self.desktop = None + self.delayTimer = eTimer() + self.delayTimer.timeout.get().append(self.processDelay) + + def processDelay(self): + components[self.screenname].close() + if self.currentWindow != None: + self.currentWindow.hide() + + del components[self.screenname] + del self.currentWindow + + + def open(self, screenname, screen): + components[screenname] = screen + self.screenname = screenname + screen.session = self + + if self.desktop != None: + self.currentWindow = wnd = eWindow(self.desktop) + wnd.setTitle("Screen from python!") + wnd.move(ePoint(300, 100)) + wnd.resize(eSize(300, 300)) + + gui = GUIOutputDevice() + gui.parent = wnd + gui.create(components["$002"]) + + applyGUIskin(components["$002"], None, "clockDialog") + + wnd.show() + else: + self.currentWindow = None + + def close(self): + self.delayTimer.start(0, 1) - gui = GUIOutputDevice() - gui.parent = wnd - gui.create(components["$002"]) +def runScreenTest(): + session = Session() + session.desktop = getDesktop() + +# components["$002"] = screens["clockDisplay"](components["clock"]) - applyGUIskin(components["$002"], None, "clockDialog") + session.open("$002", screens["clockDisplay"](components["clock"])) - wnd.show() -# components["$002"].data["okbutton"]["instance"].push() + def blub(): +# x = components["$002"] + components["$002"].data["okbutton"]["instance"].push() +# dump(components) +# print "session, close screen " + str(sys.getrefcount(x)) +# session.close() + + tmr = eTimer() + tmr.timeout.get().append(blub) + tmr.start(4000, 1) + runMainloop() return 0 diff --git a/screens.py b/screens.py index 7287898d..b68f669e 100644 --- a/screens.py +++ b/screens.py @@ -1,4 +1,5 @@ from components import * +import sys # some screens def doGlobal(screen): @@ -7,6 +8,9 @@ def doGlobal(screen): class Screen(dict, HTMLSkin, GUISkin): """ bla """ + def close(self): + GUISkin.close(self) + # a test dialog class testDialog(Screen): def testDialogClick(self): @@ -24,9 +28,11 @@ class testDialog(Screen): class clockDisplay(Screen): def okbutton(self): print "clockDisplay close" + + self.session.close() def __init__(self, clock): - HTMLSkin.__init__(self, ("title", "theClock", "okbutton")) + GUISkin.__init__(self) self["theClock"] = clock b = Button("bye") b.onClick = [ self.okbutton ]