[vlc-commits] [Git][videolan/vlc][master] 5 commits: qt: introduce virtual `CompositorVideo::supportsFractionalPositioning()`

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Thu Oct 22 06:40:11 UTC 2026



Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
b3361da7 by Fatih Uzunoglu at 2026-10-22T08:28:46+02:00
qt: introduce virtual `CompositorVideo::supportsFractionalPositioning()`

Sadly Wayland does not support fractional positioning.

- - - - -
115e7fe7 by Fatih Uzunoglu at 2026-10-22T08:28:46+02:00
qt: introduce property `MainCtx::videoSurfaceCanHaveFractionalPosition`

- - - - -
4e5de81c by Fatih Uzunoglu at 2026-10-22T08:28:46+02:00
qml: introduce `Helpers::alignRound()`

This method can be used when `alignUp`
and `alignDown` are equally favored.

- - - - -
7e6c06ed by Fatih Uzunoglu at 2026-10-22T08:28:46+02:00
qml: pixel align the position in `PIPPlayer`

Currently we are already rounding the size, but
that is not really enough, we need to align the
position as well (when necessary).

Although aligning the size is enough for layered
item cases, in video surface case we also should
align the position because compositors (such as
`CompositorWayland`) does not support fractional
position. This is already a problem even if the
window scale is not fractional, because Qt Quick
supports fractional positioning and `DragHandler`
don't have such `pixelAligned` property.

Although we ideally should do the same in the
player page for the main video surface item, it
is currently not done for the sake of maintenance,
since with d212c67b it does not cause visible
glitches. Ideally we should do the same there,
though.

- - - - -
3b896736 by Fatih Uzunoglu at 2026-10-22T08:28:46+02:00
qml: introduce `pixelAlignedForDPR` property in `PIPPlayer`

The preceding patch pixel aligns the position, but it is
not enough if the window scale is fractional, since Qt
Quick item coordinates by nature don't consider the window
DPR.

- - - - -


6 changed files:

- modules/gui/qt/maininterface/compositor.hpp
- modules/gui/qt/maininterface/compositor_dcomp.hpp
- modules/gui/qt/maininterface/mainctx.cpp
- modules/gui/qt/maininterface/mainctx.hpp
- modules/gui/qt/player/qml/PIPPlayer.qml
- modules/gui/qt/util/qml/Helpers.qml


Changes:

=====================================
modules/gui/qt/maininterface/compositor.hpp
=====================================
@@ -146,6 +146,10 @@ public:
     // The following method should return true if surface updates can be threaded:
     virtual bool canDoThreadedSurfaceUpdates() const { return false; };
 
+    // The following method should return true if the fractional position is
+    // respected as is:
+    virtual bool supportsFractionalPositioning() const { return false; }
+
 protected:
     void commonSetupVoutWindow(vlc_window_t* p_wnd, VoutDestroyCb destroyCb);
     void commonWindowEnable();


=====================================
modules/gui/qt/maininterface/compositor_dcomp.hpp
=====================================
@@ -71,6 +71,9 @@ public:
 
     bool canDoThreadedSurfaceUpdates() const override { return true; };
 
+    // See `IDCompositionVisual::SetOffset{X,Y}()`:
+    bool supportsFractionalPositioning() const override { return true; }
+
 protected:
     bool canDoCombinedSurfaceUpdates() const override { return true; };
     void commitSurface() override;


=====================================
modules/gui/qt/maininterface/mainctx.cpp
=====================================
@@ -1051,6 +1051,17 @@ QWindow *MainCtx::intfMainWindow() const
         return nullptr;
 }
 
+bool MainCtx::videoSurfaceCanHaveFractionalPosition() const
+{
+    assert(p_intf->p_compositor);
+    if (p_intf->p_compositor->type() == vlc::Compositor::DummyCompositor)
+        return true; // Does not matter, there is no video embedding in this case.
+
+    // We can avoid dynamic cast here, since we early return if the type is not `CompositorVideo`:
+    const auto videoCompositor = static_cast<vlc::CompositorVideo*>(p_intf->p_compositor.get());
+    return videoCompositor->supportsFractionalPositioning();
+}
+
 QVariant MainCtx::settingValue(const QString &key, const QVariant &defaultValue) const
 {
     return settings->value(key, defaultValue);


=====================================
modules/gui/qt/maininterface/mainctx.hpp
=====================================
@@ -125,6 +125,7 @@ class MainCtx : public QObject
     Q_PROPERTY(bool hasAcrylicSurface READ hasAcrylicSurface NOTIFY hasAcrylicSurfaceChanged FINAL)
     Q_PROPERTY(bool smoothScroll READ smoothScroll NOTIFY smoothScrollChanged FINAL)
     Q_PROPERTY(QWindow* intfMainWindow READ intfMainWindow CONSTANT FINAL)
+    Q_PROPERTY(bool videoSurfaceCanHaveFractionalPosition READ videoSurfaceCanHaveFractionalPosition CONSTANT FINAL)
     Q_PROPERTY(bool useGlobalShortcuts READ getUseGlobalShortcuts WRITE setUseGlobalShortcuts NOTIFY useGlobalShortcutsChanged FINAL)
     Q_PROPERTY(int maxVolume READ maxVolume NOTIFY maxVolumeChanged FINAL)
     Q_PROPERTY(float safeArea READ safeArea NOTIFY safeAreaChanged FINAL)
@@ -388,6 +389,8 @@ public:
 
     QWindow *intfMainWindow() const;
 
+    bool videoSurfaceCanHaveFractionalPosition() const;
+
     Q_INVOKABLE QVariant settingValue(const QString &key, const QVariant &defaultValue) const;
     Q_INVOKABLE void setSettingValue(const QString &key, const QVariant &value);
 


=====================================
modules/gui/qt/player/qml/PIPPlayer.qml
=====================================
@@ -16,6 +16,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 import QtQuick
+import QtQuick.Window
 import QtQuick.Templates as T
 
 import VLC.MainInterface
@@ -27,8 +28,28 @@ import VLC.Util
 
 T.Control {
     id: root
-    width: Math.round(VLCStyle.dp(320, VLCStyle.scale))
-    height: Math.round(VLCStyle.dp(180, VLCStyle.scale))
+    width: Helpers.alignRound(320, _alignNumber)
+    height: Helpers.alignRound(180, _alignNumber)
+
+    // Default size is always aligned, this only
+    // controls position alignment. Note that
+    // setting this may make dragging less smooth,
+    // depending on how big is the denominator
+    // for the fractional DPR (the bigger, the
+    // worse). See `Helpers::denominatorForFloat()`.
+    property bool pixelAlignedForDPR: !MainCtx.videoSurfaceCanHaveFractionalPosition
+
+    transform: Translate {
+        x: (root.x !== targetX) ? (targetX - root.x) : 0.0
+        y: (root.y !== targetY) ? (targetY - root.y) : 0.0
+
+        readonly property real targetX: root.pixelAlignedForDPR ? Helpers.alignRound(root.x, root._alignNumber)
+                                                                : (MainCtx.videoSurfaceCanHaveFractionalPosition ? root.x
+                                                                                                                 : Math.round(root.x))
+        readonly property real targetY: root.pixelAlignedForDPR ? Helpers.alignRound(root.y, root._alignNumber)
+                                                                : (MainCtx.videoSurfaceCanHaveFractionalPosition ? root.y
+                                                                                                                 : Math.round(root.y))
+    }
 
     objectName: "pip window"
 
@@ -46,6 +67,17 @@ T.Control {
     Accessible.focusable: false
     Accessible.name: qsTr("video content")
 
+    property real _eDPR: MainCtx.effectiveDevicePixelRatio(Window.window) || 1.0
+    readonly property int _alignNumber: pixelAlignedForDPR ? Helpers.denominatorForFloat(_eDPR) : 1
+
+    Connections {
+        target: MainCtx
+
+        function onIntfDevicePixelRatioChanged() {
+            root._eDPR = MainCtx.effectiveDevicePixelRatio(root.Window.window) || 1.0
+        }
+    }
+
     Drag.active: dragHandler.active
 
     Drag.onActiveChanged: {


=====================================
modules/gui/qt/util/qml/Helpers.qml
=====================================
@@ -79,6 +79,10 @@ QtObject {
         return Math.floor(a / b) * b
     }
 
+    function alignRound(a : real, b : int) : int {
+        return Math.round(a / b) * b
+    }
+
     // Currently only supports .25, .5, .75
     function denominatorForFloat(number : real) : int {
         const fraction = number % 1



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c116df96ee86c58aff6da31593f1c2dc57ab3a1e...3b896736b8f01a71be901f16f47f6183fb9868d0

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c116df96ee86c58aff6da31593f1c2dc57ab3a1e...3b896736b8f01a71be901f16f47f6183fb9868d0
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help




More information about the vlc-commits mailing list