diff --git a/configure.ac b/configure.ac index 2209e4c431..4845dc13e9 100644 --- a/configure.ac +++ b/configure.ac @@ -230,21 +230,19 @@ AS_IF([test "$BOXTYPE" == "vuzero"],[AC_DEFINE(HWVUZERO, 1,[vuzero])]) AS_IF([test "$BOXTYPE" == "vuzero4k"],[AC_DEFINE(HWVUZERO4K, 1,[vuzero4k])]) dnl Software HDR detection (HEVC bitstream parser + TS recorder tap). -dnl Enabled for VU+ 4K boxes and GigaBlue Quad 4K Pro, which have capable +dnl Enabled for VU+ 4K boxes and GigaBlue 4K boxes, which have capable dnl enough SoCs and GStreamer stacks to support the detection pipeline. -if test "$BOXTYPE" == "vuduo4k" -o "$BOXTYPE" == "vuduo4kse" \ - -o "$BOXTYPE" == "vuduo4klite" -o "$BOXTYPE" == "vusolo4k" \ - -o "$BOXTYPE" == "vuultimo4k" -o "$BOXTYPE" == "vuuno4k" \ - -o "$BOXTYPE" == "vuuno4kse" -o "$BOXTYPE" == "vuzero4k" \ - -o "$BOXTYPE" == "gb7252"; then +dnl Not enabled for vuduo4klite, vuultimo4k and gbquad4kpro. +has_sw_hdr_detection=no +if test "$MACHINEBUILD" != "gbquad4kpro" -a "$MACHINEBUILD" != "vuduo4klite" -a "$MACHINEBUILD" != "vuultimo4k" \ + -a \( "$BOXTYPE" == "vuduo4k" -o "$BOXTYPE" == "vuduo4kse" \ + -o "$BOXTYPE" == "vusolo4k" -o "$BOXTYPE" == "vuuno4k" \ + -o "$BOXTYPE" == "vuuno4kse" -o "$BOXTYPE" == "vuzero4k" \ + -o "$BOXTYPE" == "gb7252" \); then + has_sw_hdr_detection=yes AC_DEFINE(HAS_SOFTWARE_HDR_DETECTION, 1, [Enable software HDR detection via HEVC bitstream parsing]) fi -AM_CONDITIONAL(HAS_SOFTWARE_HDR_DETECTION, \ - test "$BOXTYPE" == "vuduo4k" -o "$BOXTYPE" == "vuduo4kse" \ - -o "$BOXTYPE" == "vuduo4klite" -o "$BOXTYPE" == "vusolo4k" \ - -o "$BOXTYPE" == "vuultimo4k" -o "$BOXTYPE" == "vuuno4k" \ - -o "$BOXTYPE" == "vuuno4kse" -o "$BOXTYPE" == "vuzero4k" \ - -o "$BOXTYPE" == "gb7252") +AM_CONDITIONAL(HAS_SOFTWARE_HDR_DETECTION, test "x$has_sw_hdr_detection" = "xyes") AC_ARG_WITH(accelerationthreshold, AS_HELP_STRING([--with-accelerationthreshold=n], [use acceleration threshold of n bytes]), diff --git a/lib/gui/estack.cpp b/lib/gui/estack.cpp index 306592c676..039ff13c11 100644 --- a/lib/gui/estack.cpp +++ b/lib/gui/estack.cpp @@ -2,6 +2,28 @@ eStack::eStack(eWidget* parent, LayoutDirection dir) : eWidget(parent), m_direction(dir) { m_spacing = 0; + setTransparent(1); +} + +eStack::~eStack() { + /* children must not call back into a destroyed stack */ + for (auto child : m_stackchilds) + child->setStack(nullptr); +} + +void eStack::setSpacing(int spacing) { + m_spacing = spacing; + recalcLayout(); +} + +void eStack::show() { + eWidget::show(); + recalcLayout(); +} + +void eStack::forgetStackChild(eWidget* child) { + if (auto it = std::ranges::find(m_stackchilds, child); it != m_stackchilds.end()) + m_stackchilds.erase(it); } void eStack::setLayoutDirection(LayoutDirection dir) { @@ -38,7 +60,10 @@ int eStack::event(int event, void* data, void* data2) { if (event == evtPaint) return 0; - return eWidget::event(event, data, data2); + int ret = eWidget::event(event, data, data2); + if (event == evtChangedSize) + recalcLayout(); + return ret; } void eStack::recalcLayout() { @@ -47,6 +72,8 @@ void eStack::recalcLayout() { if (stack_w < 0 || stack_h < 0) return; + if (!isVisible()) + return; int x = 0, y = 0; int xr = stack_w; @@ -78,8 +105,8 @@ void eStack::recalcLayout() { lcount++; } else if (child->align() & eStackAlignRight) { cx = xr - cw; - xr -= cx; - if (lcount > 0) { + xr -= cw; + if (rcount > 0) { cx -= m_spacing; xr -= m_spacing; } @@ -91,7 +118,7 @@ void eStack::recalcLayout() { } else { if (child->align() & eStackAlignTop) { cy = y; - y += cy; + y += ch; if (tcount > 0) { y += m_spacing; cy += m_spacing; @@ -99,7 +126,7 @@ void eStack::recalcLayout() { tcount++; } else if (child->align() & eStackAlignBottom) { cy = yb - ch; - yb -= cy; + yb -= ch; if (bcount > 0) { cy -= m_spacing; yb -= m_spacing; diff --git a/lib/gui/estack.h b/lib/gui/estack.h index 2bf2053e21..787cf7c1e3 100644 --- a/lib/gui/estack.h +++ b/lib/gui/estack.h @@ -1,5 +1,5 @@ -#ifndef __lib_gui_epanel_h -#define __lib_gui_epanel_h +#ifndef __lib_gui_estack_h +#define __lib_gui_estack_h #include #include @@ -14,6 +14,7 @@ class eStack : public eWidget { }; eStack(eWidget* parent = nullptr, LayoutDirection dir = Vertical); + ~eStack(); void setLayoutDirection(LayoutDirection dir); LayoutDirection layoutDirection() const { return m_direction; } @@ -22,12 +23,15 @@ class eStack : public eWidget { void removeChild(eWidget* child); int getSpacing() const { return m_spacing; } - void setSpacing(int spacing) { m_spacing = spacing; } + void setSpacing(int spacing); + + void show() override; protected: int event(int event, void* data = 0, void* data2 = 0) override; void recalcLayout(); void invalidateChilds() override; + void forgetStackChild(eWidget* child) override; private: LayoutDirection m_direction; diff --git a/lib/gui/ewidget.cpp b/lib/gui/ewidget.cpp index ac802d58a8..8396887139 100644 --- a/lib/gui/ewidget.cpp +++ b/lib/gui/ewidget.cpp @@ -310,6 +310,11 @@ void eWidget::mayKillFocus() eWidget::~eWidget() { + if (m_stack) + { + m_stack->forgetStackChild(this); + m_stack = nullptr; + } hide(); if (m_parent) m_parent->m_childs.remove(this); diff --git a/lib/gui/ewidget.h b/lib/gui/ewidget.h index 4e8d4be1de..78dbc4cec7 100644 --- a/lib/gui/ewidget.h +++ b/lib/gui/ewidget.h @@ -35,7 +35,7 @@ class eWidget eWidget *getParent() { return m_parent; } - void show(); + virtual void show(); void hide(); void raise(); @@ -162,6 +162,7 @@ class eWidget bool m_alphaBlend = false; uint8_t m_align = eStackAlignNone; virtual void invalidateChilds() {} // This will be overwritten in subclass + virtual void forgetStackChild(eWidget*) {} // This will be overwritten in subclass public: diff --git a/lib/gui/ewindow.h b/lib/gui/ewindow.h index a76202758a..eca8d7b4d9 100644 --- a/lib/gui/ewindow.h +++ b/lib/gui/ewindow.h @@ -15,7 +15,7 @@ class eWindow: public eWidget void setTitle(const std::string &string); std::string getTitle() const; eWidget *child() { return m_child; } - void show(); + void show() override; void hide(); enum { diff --git a/lib/python/Components/AVSwitch.py b/lib/python/Components/AVSwitch.py index a5d9198825..03b80cee14 100644 --- a/lib/python/Components/AVSwitch.py +++ b/lib/python/Components/AVSwitch.py @@ -3,7 +3,7 @@ from enigma import eAVSwitch, eDVBVolumecontrol, getDesktop from Components.config import ConfigEnableDisable, ConfigNothing, ConfigSelection, ConfigSelectionNumber, ConfigSlider, ConfigSubDict, ConfigSubsection, ConfigYesNo, NoSave, config -from Components.SystemInfo import SystemInfo +from Components.SystemInfo import BOXTYPE, SystemInfo from Tools.CList import CList from Tools.Directories import fileCheck, fileReadLine, fileWriteLine, isPluginInstalled @@ -509,18 +509,18 @@ def setHDMIColorimetry(configElement): if SystemInfo["havehdmicolordepth"]: def setHdmiColordepth(configElement): - open(SystemInfo["havehdmicolordepth"], "w").write("12bit" if SystemInfo["needsVideoJudderDriverFix"] else configElement.value) + open(SystemInfo["havehdmicolordepth"], "w").write(configElement.value) choices = [("auto", _("Auto")), ("8bit", _("8bit")), ("10bit", _("10bit")), ("12bit", _("12bit"))] default = "auto" - if SystemInfo["needsVideoJudderDriverFix"]: - choices = [("10bit", "10bit"), ("12bit", "12bit")] - default = "12bit" - elif SystemInfo["havehdmicolordepthchoices"] and SystemInfo["CanProc"]: + if SystemInfo["havehdmicolordepthchoices"] and SystemInfo["CanProc"]: f = "/proc/stb/video/hdmi_colordepth_choices" (choices, default) = readChoices(f, choices, default) + if BOXTYPE in ("gbquad4kpro", "vuduo4klite"): + choices = [choice for choice in choices if choice[0] not in ("auto", "8bit")] + default = "10bit" config.av.hdmicolordepth = ConfigSelection(choices=choices, default=default) config.av.hdmicolordepth.addNotifier(setHdmiColordepth) else: @@ -916,27 +916,3 @@ def stopHotplug(): def InitiVideomodeHotplug(**kwargs): startHotplug() - - -iVideoJudderDriverFixTask = None - - -class VideoJudderDriverFixTask: - def __init__(self): - self.onClose = [] - from enigma import iPlayableService - from Components.ServiceEventTracker import ServiceEventTracker - self.inited = False - self.__event_tracker = ServiceEventTracker(screen=self, eventmap={iPlayableService.evVideoFramerateChanged: self.__evVideoFramerateChanged}) - - def __evVideoFramerateChanged(self): - if not self.inited: - with open("/proc/stb/video/hdmi_colordepth", "w") as fd: - fd.write("10bit") - self.inited = True - - -def startVideoJudderDriverFixTask(): - global iVideoJudderDriverFixTask - if SystemInfo["needsVideoJudderDriverFix"]: - iVideoJudderDriverFixTask = VideoJudderDriverFixTask() diff --git a/lib/python/Components/SystemInfo.py b/lib/python/Components/SystemInfo.py index b28999f3ca..4c86ef3f4f 100644 --- a/lib/python/Components/SystemInfo.py +++ b/lib/python/Components/SystemInfo.py @@ -302,7 +302,6 @@ def hasInitCam(): SystemInfo["hasScart"] = SystemInfo["scart"] SystemInfo["hasScartYUV"] = SystemInfo["scartyuv"] SystemInfo["hasYUV"] = SystemInfo["yuv"] -SystemInfo["needsVideoJudderDriverFix"] = BOXTYPE in ("gbquad4kpro", "vuduo4klite") SystemInfo["scalerSharpnessWorkaround"] = BOXTYPE in ("gbquad", "gbquadplus") SystemInfo["dmVideoRates"] = MODEL in ("dm900", "dm920") diff --git a/lib/python/Screens/Screen.py b/lib/python/Screens/Screen.py index de98c277b9..5a3e66a2d6 100644 --- a/lib/python/Screens/Screen.py +++ b/lib/python/Screens/Screen.py @@ -1,6 +1,6 @@ from os.path import isfile -from enigma import eRCInput, eTimer, eWindow, getDesktop +from enigma import eRCInput, eStack, eTimer, eWindow, getDesktop from skin import GUI_SKIN_ID, DISPLAY_SKIN_ID, applyAllAttributes, menus, screens, setups # noqa: F401 from Components.config import config @@ -146,6 +146,9 @@ def show(self): for val in list(self.values()) + self.renderer: if isinstance(val, GUIComponent) or isinstance(val, Source): val.onShow() + for stack in getattr(self, "stacks", []): + if isinstance(stack.instance, eStack): + stack.instance.show() def hide(self): if not self.shown or not self.instance: @@ -157,6 +160,9 @@ def hide(self): for val in list(self.values()) + self.renderer: if isinstance(val, GUIComponent) or isinstance(val, Source): val.onHide() + for stack in getattr(self, "stacks", []): + if isinstance(stack.instance, eStack): + stack.instance.hide() def getScreenPath(self): return self.screenPath @@ -277,14 +283,16 @@ def addToStack(widget): stack = self.stacks[widget.stackIndex] stack.instance.addChild(widget.instance) - for widget in self.stacks: - widget.instance = widget.widget(parent, widget.layout) - applyAllAttributes(widget.instance, desktop, widget.skinAttributes, self.scale) - addToStack(widget) + if not updateonly: + for widget in self.stacks: + widget.instance = widget.widget(parent, widget.layout) + applyAllAttributes(widget.instance, desktop, widget.skinAttributes, self.scale) + addToStack(widget) for val in self.renderer: if isinstance(val, GUIComponent): if not updateonly: val.GUIcreate(parent) + addToStack(val) if not val.applySkin(desktop, self): print("[Screen] Warning: Skin is missing renderer '%s' in %s." % (val, str(self))) for key in self: @@ -292,6 +300,7 @@ def addToStack(widget): if isinstance(val, GUIComponent): if not updateonly: val.GUIcreate(parent) + addToStack(val) depr = val.deprecationInfo if val.applySkin(desktop, self): if depr: @@ -304,6 +313,8 @@ def addToStack(widget): w.instance = w.widget(parent) # w.instance.thisown = 0 applyAllAttributes(w.instance, desktop, w.skinAttributes, self.scale) + if not updateonly: + addToStack(w) if self.screenImage: self["Image"].setPixmap(LoadPixmap(self.screenImage)) for f in self.onLayoutFinish: diff --git a/lib/python/Screens/VideoMode.py b/lib/python/Screens/VideoMode.py index 4e95babcae..47c3eb3744 100644 --- a/lib/python/Screens/VideoMode.py +++ b/lib/python/Screens/VideoMode.py @@ -57,8 +57,7 @@ def createSetup(self): if SystemInfo["havecolorimetry"]: self.list.append(getConfigListEntry(_("HDMI Colorimetry"), config.av.hdmicolorimetry, _("Change the Colorimetry for HDR - this may cause unexpected results or black screen"))) if SystemInfo["havehdmicolordepth"]: - if not SystemInfo["needsVideoJudderDriverFix"]: - self.list.append(getConfigListEntry(_("HDMI Color Depth"), config.av.hdmicolordepth, _("Change the Colordepth for UHD - this may cause unexpected results or black screen"))) + self.list.append(getConfigListEntry(_("HDMI Color Depth"), config.av.hdmicolordepth, _("Change the Colordepth for UHD - this may cause unexpected results or black screen"))) if SystemInfo["havehdmihdrtype"]: self.list.append(getConfigListEntry(_("HDMI HDR Type"), config.av.hdmihdrtype, _("Enable or disable to force HDR Modes for UHD"))) if SystemInfo["havehdmihdrosd"]: diff --git a/lib/python/StartEnigma.py b/lib/python/StartEnigma.py index 1b17b08679..fdd711f5b6 100644 --- a/lib/python/StartEnigma.py +++ b/lib/python/StartEnigma.py @@ -355,10 +355,6 @@ def runScreenTest(): Tools.Trashcan.init(session) if not VuRecovery: CiHandler.setSession(session) - if SystemInfo["needsVideoJudderDriverFix"]: - profile("Init:Components.AVSwitch.VideoJudderDriverFixTask") - from Components.AVSwitch import startVideoJudderDriverFixTask - startVideoJudderDriverFixTask() screensToRun = [p.fnc for p in plugins.getPlugins(PluginDescriptor.WHERE_WIZARD)] profile("wizards") diff --git a/lib/python/skin.py b/lib/python/skin.py index 1d2bc4f59f..d8038b3191 100644 --- a/lib/python/skin.py +++ b/lib/python/skin.py @@ -585,6 +585,15 @@ def position(self, value): def size(self, value): self.guiObject.resize(eSize(*value) if isinstance(value, tuple) else parseSize(value, self.scaleTuple, self.guiObject, self.desktop)) + def align(self, value): + self.guiObject.setAlign(value) + + def spacing(self, value): + self.guiObject.setSpacing(int(value)) + + def stack(self, value): # This is a dummy method for the parser. + pass + def animationPaused(self, value): pass @@ -1242,6 +1251,7 @@ def __str__(self): class SkinContext: def __init__(self, parent=None, pos=None, size=None, font=None): + self.spacing = 0 if parent is not None and pos is not None: pos, size = parent.parse(pos, size, font) self.x, self.y = pos @@ -1358,7 +1368,8 @@ def parse(self, pos, size, font): self.h -= (height + self.spacing) self.y += (height + self.spacing) elif pos == "center": - pos = (left, (self.h - height) / 2) + originY = self.by - self.bh + pos = (left, originY + (self.bh - height) // 2) size = (width, height) else: size = (width, height) @@ -1406,7 +1417,8 @@ def parse(self, pos, size, font): size = (width, height) self.w -= (width + self.spacing) elif pos == "center": - pos = ((self.w - width) / 2, top) + originX = self.rx - self.rw + pos = (originX + (self.rw - width) // 2, top) size = (width, height) else: size = (width, height) @@ -1482,13 +1494,13 @@ def readSkin(screen, skin, names, desktop): screen.stacks = [] usedComponents = set() - def processNone(widget, context): + def processNone(widget, context, stack=None): pass def proccesStackAddition(widget, stack, target): if stack: target.stackIndex = stack.index - pos = widget.attrib.get("position") + pos = widget.attrib.get("position", "") align = eWidget.eStackAlignNone if stack.layout == 0: # horizontal if "left" in pos: @@ -1507,7 +1519,7 @@ def proccesStackAddition(widget, stack, target): target.skinAttributes.append(("align", align)) return target - def processWidget(widget, context): + def processWidget(widget, context, stack=None): # Okay, we either have 1:1-mapped widgets ("old style"), or 1:n-mapped # widgets (source->renderer). wname = widget.attrib.get("name") @@ -1531,6 +1543,7 @@ def processWidget(widget, context): raise SkinError("Component with name '%s' was not found in skin of screen '%s'" % (wname, name)) # assert screen[wname] is not Source collectAttributes(attributes, widget, context, skinPath, ignore=("name",)) + screen[wname] = proccesStackAddition(widget, stack, screen[wname]) elif wsource: # print("[Skin] DEBUG: Widget source='%s'." % wsource) while True: # Get corresponding source until we found a non-obsolete source. @@ -1594,6 +1607,7 @@ def processWidget(widget, context): renderer.connect(source) # Connect to source. attributes = renderer.skinAttributes = [] collectAttributes(attributes, widget, context, skinPath, ignore=("render", "source")) + renderer = proccesStackAddition(widget, stack, renderer) screen.renderer.append(renderer) elif wclass: try: @@ -1616,8 +1630,9 @@ def processWidget(widget, context): screen[wclassname].connectRelatedElement(wconnection, screen) attributes = screen[wclassname].skinAttributes = [] collectAttributes(attributes, widget, context, skinPath, ignore=("addon",)) + screen[wclassname] = proccesStackAddition(widget, stack, screen[wclassname]) - def processApplet(widget, context): + def processApplet(widget, context, stack=None): try: codeText = widget.text.strip() widgetType = widget.attrib.get("type") @@ -1631,19 +1646,25 @@ def processApplet(widget, context): else: raise SkinError("Applet type '%s' is unknown" % widgetType) - def processLabel(widget, context): + def processLabel(widget, context, stack=None): w = additionalWidget() w.widget = eLabel w.skinAttributes = [] collectAttributes(w.skinAttributes, widget, context, skinPath, ignore=("name",)) + w = proccesStackAddition(widget, stack, w) screen.additionalWidgets.append(w) + if stack: + stack.children.append(w) - def processPixmap(widget, context): + def processPixmap(widget, context, stack=None): w = additionalWidget() w.widget = ePixmap w.skinAttributes = [] collectAttributes(w.skinAttributes, widget, context, skinPath, ignore=("name",)) + w = proccesStackAddition(widget, stack, w) screen.additionalWidgets.append(w) + if stack: + stack.children.append(w) def processRectangle(widget, context, stack=None): item = additionalWidget() @@ -1655,7 +1676,7 @@ def processRectangle(widget, context, stack=None): if stack: stack.children.append(item) - def processScreen(widget, context): + def processScreen(widget, context, stack=None): for w in list(widget): conditional = w.attrib.get("conditional") if conditional and not [i for i in conditional.split(",") if i in screen]: @@ -1668,13 +1689,13 @@ def processScreen(widget, context): continue p = processors.get(w.tag, processNone) try: - p(w, context) + p(w, context, stack) except SkinError as err: print("[Skin] Error in screen '%s' widget '%s' %s!" % (name, w.tag, str(err))) import traceback traceback.print_exc() - def processPanel(widget, context): + def processPanel(widget, context, stack=None): n = widget.attrib.get("name") if n: try: