[vlc-commits] [Git][videolan/vlc][master] 8 commits: qt: add extended frame capability to compositor
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Sat Jul 22 11:03:16 UTC 2023
Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits:
fbcb6c31 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qt: add extended frame capability to compositor
this allows to define a non-client area to draw things like window shadows when
using CSD
- - - - -
0451411b by Pierre Lamot at 2023-07-22T10:48:01+00:00
qt: set extended frame when available on X11
- - - - -
72e63e36 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qt: account for extended frame in minimal window size
- - - - -
c861c002 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qml: move g_mainInterface a an inner item in the window
no functional change, this is preliminary work for the following patch
- - - - -
11258b08 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qml: draw CSD window shadow, when extended frames is supported
- - - - -
747116e3 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qml: avoid popup overlay background to bleed into the extended area
Overlay.overlay is a root node, it isn't aware of our extended area
- - - - -
db1a1e67 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qml: specify the target explicitly in CSDMouseStealer
don't rely on global id
- - - - -
e3dea257 by Pierre Lamot at 2023-07-22T10:48:01+00:00
qml: allow CSDMouseStealer areas to be placed outside the target item
- - - - -
13 changed files:
- modules/gui/qt/dialogs/dialogs/qml/ModalDialog.qml
- modules/gui/qt/maininterface/compositor.cpp
- modules/gui/qt/maininterface/compositor.hpp
- modules/gui/qt/maininterface/compositor_x11.cpp
- modules/gui/qt/maininterface/compositor_x11_renderwindow.cpp
- modules/gui/qt/maininterface/compositor_x11_renderwindow.hpp
- modules/gui/qt/maininterface/compositor_x11_utils.cpp
- modules/gui/qt/maininterface/compositor_x11_utils.hpp
- modules/gui/qt/maininterface/interface_window_handler.cpp
- modules/gui/qt/maininterface/mainctx.cpp
- modules/gui/qt/maininterface/mainctx.hpp
- modules/gui/qt/maininterface/qml/MainInterface.qml
- modules/gui/qt/widgets/qml/CSDMouseStealer.qml
Changes:
=====================================
modules/gui/qt/dialogs/dialogs/qml/ModalDialog.qml
=====================================
@@ -50,13 +50,21 @@ Dialog {
colorSet: ColorContext.Window
}
- Overlay.modal: GaussianBlur {
- source: ShaderEffectSource {
- sourceItem: control.rootWindow
- live: true
+ Overlay.modal: Item {
+ GaussianBlur {
+ anchors.fill: parent
+ anchors.topMargin: MainCtx.windowExtendedMargin
+ anchors.leftMargin: MainCtx.windowExtendedMargin
+ anchors.rightMargin: MainCtx.windowExtendedMargin
+ anchors.bottomMargin: MainCtx.windowExtendedMargin
+
+ source: ShaderEffectSource {
+ sourceItem: control.rootWindow
+ live: true
+ }
+ radius: 12
+ samples: 16
}
- radius: 12
- samples: 16
}
background: Rectangle {
=====================================
modules/gui/qt/maininterface/compositor.cpp
=====================================
@@ -260,6 +260,7 @@ bool CompositorVideo::commonGUICreateImpl(QWindow* window, QWidget* rootWidget,
m_interfaceWindowHandler = std::make_unique<InterfaceWindowHandler>(m_intf, m_mainCtx, window, rootWidget);
#endif
m_mainCtx->setHasAcrylicSurface(flags & CompositorVideo::HAS_ACRYLIC);
+ m_mainCtx->setWindowSuportExtendedFrame(flags & CompositorVideo::HAS_EXTENDED_FRAME);
#ifdef _WIN32
m_taskbarWidget = std::make_unique<WinTaskbarWidget>(m_intf, window);
=====================================
modules/gui/qt/maininterface/compositor.hpp
=====================================
@@ -92,7 +92,8 @@ public:
enum Flag : unsigned
{
CAN_SHOW_PIP = 1,
- HAS_ACRYLIC = 2
+ HAS_ACRYLIC = 2,
+ HAS_EXTENDED_FRAME = 4,
};
Q_DECLARE_FLAGS(Flags, Flag)
=====================================
modules/gui/qt/maininterface/compositor_x11.cpp
=====================================
@@ -194,6 +194,8 @@ bool CompositorX11::makeMainInterface(MainCtx* mainCtx)
CompositorVideo::Flags flags = CompositorVideo::CAN_SHOW_PIP;
if (m_renderWindow->hasAcrylic())
flags |= CompositorVideo::HAS_ACRYLIC;
+ if (m_renderWindow->supportExtendedFrame())
+ flags |= CompositorVideo::HAS_EXTENDED_FRAME;
commonGUICreate(m_renderWindow.get(), nullptr, m_qmlView.get(), flags);
m_renderWindow->setInterfaceWindow(m_qmlView.get());
=====================================
modules/gui/qt/maininterface/compositor_x11_renderwindow.cpp
=====================================
@@ -37,9 +37,11 @@
#include <vlc_cxx_helpers.hpp>
#include "qt.hpp"
+#include "mainctx.hpp"
//blur behind for KDE
#define _KDE_NET_WM_BLUR_BEHIND_REGION_NAME "_KDE_NET_WM_BLUR_BEHIND_REGION"
+#define _GTK_FRAME_EXTENTS "_GTK_FRAME_EXTENTS"
using namespace vlc;
@@ -74,7 +76,7 @@ void RenderTask::render(unsigned int requestId)
xcb_flush(m_conn);
xcb_render_picture_t drawingarea = getBackTexture();
- if (m_hasAcrylic)
+ if (m_hasAcrylic || m_hasExtendedFrame)
{
//clear screen
xcb_render_color_t clear = { 0x0000, 0x0000, 0x0000, 0x0000 };
@@ -180,6 +182,12 @@ void RenderTask::onAcrylicChanged(bool enabled)
m_hasAcrylic = enabled;
}
+void RenderTask::onExtendedFrameChanged(bool enabled)
+{
+ m_hasExtendedFrame = enabled;
+}
+
+
xcb_render_picture_t RenderTask::getBackTexture()
{
if (m_drawingarea && !m_resizeRequested)
@@ -352,6 +360,14 @@ bool CompositorX11RenderWindow::init()
}
xcb_connection_t* qtConn = QX11Info::connection();
+ xcb_window_t rootWindow = QX11Info::appRootWindow();
+ int appScreen = QX11Info::appScreen();
+
+ //if we don't have compositor, transparency effects won't work.
+ //Note that composite extention may be available and functionnal without a compositor,
+ //so having video compositing doesn't imply that window transparency is available
+ if (!wmScreenHasCompositor(qtConn, appScreen))
+ return true;
//check if KDE "acrylic" effect is available
xcb_atom_t blurBehindAtom = getInternAtom(qtConn, _KDE_NET_WM_BLUR_BEHIND_REGION_NAME);
@@ -362,6 +378,15 @@ bool CompositorX11RenderWindow::init()
blurBehindAtom, XCB_ATOM_CARDINAL, 32, 1, &val);
m_hasAcrylic = true;
}
+
+ //_GTK_FRAME_EXTENTS should be available at least on Gnome/KDE/FXCE/Enlightement
+ xcb_atom_t gtkExtendFrame = getInternAtom(qtConn, _GTK_FRAME_EXTENTS);
+ if (gtkExtendFrame != XCB_ATOM_NONE && wmNetSupport(qtConn, rootWindow, gtkExtendFrame))
+ {
+ m_supportExtendedFrame = true;
+ connect(m_intf->p_mi, &MainCtx::windowExtendedMarginChanged,
+ this, &CompositorX11RenderWindow::onWindowExtendedMarginChanged);
+ }
return true;
}
@@ -385,12 +410,13 @@ bool CompositorX11RenderWindow::startRendering()
connect(this, &CompositorX11RenderWindow::videoPositionChanged, m_renderTask, &RenderTask::onVideoPositionChanged);
connect(this, &CompositorX11RenderWindow::registerVideoWindow, m_renderTask, &RenderTask::onRegisterVideoWindow);
connect(this, &CompositorX11RenderWindow::videoSurfaceChanged, m_renderTask, &RenderTask::onVideoSurfaceChanged, Qt::BlockingQueuedConnection);
-
+ connect(this, &CompositorX11RenderWindow::hasExtendedFrameChanged, m_renderTask, &RenderTask::onExtendedFrameChanged, Qt::BlockingQueuedConnection);
//pass initial values
m_renderTask->onInterfaceSurfaceChanged(m_interfaceClient.get());
m_renderTask->onVideoSurfaceChanged(m_videoClient.get());
m_renderTask->onWindowSizeChanged(size() * devicePixelRatio());
m_renderTask->onAcrylicChanged(m_hasAcrylic);
+ m_renderTask->onExtendedFrameChanged(m_hasExtendedFrame);
//use the same thread as the rendering thread, neither tasks are blocking.
m_damageObserver->moveToThread(m_renderThread);
@@ -525,5 +551,26 @@ void CompositorX11RenderWindow::setInterfaceWindow(CompositorX11UISurface* windo
xcb_flush(QX11Info::connection());
m_interfaceClient = std::make_unique<CompositorX11RenderClient>(m_intf, m_conn, window);
m_interfaceWindow = window;
+}
+
+void CompositorX11RenderWindow::setHasExtendedFrame(bool hasExtendedFrame)
+{
+ if (hasExtendedFrame == m_hasExtendedFrame)
+ return;
+ m_hasExtendedFrame = hasExtendedFrame;
+ emit hasExtendedFrameChanged(m_hasExtendedFrame);
}
+
+void CompositorX11RenderWindow::onWindowExtendedMarginChanged(unsigned margin)
+{
+ xcb_atom_t gtkExtendFrame = getInternAtom(m_conn, _GTK_FRAME_EXTENTS);
+
+ margin *= m_intf->p_mi->intfMainWindow()->devicePixelRatio();
+
+ uint32_t val[4] = {margin, margin, margin, margin};
+ xcb_change_property(m_conn, XCB_PROP_MODE_REPLACE, m_wid,
+ gtkExtendFrame, XCB_ATOM_CARDINAL, 32, 4, &val);
+ setHasExtendedFrame(margin != 0);
+}
+
=====================================
modules/gui/qt/maininterface/compositor_x11_renderwindow.hpp
=====================================
@@ -83,6 +83,7 @@ public slots:
void onVisibilityChanged(bool visible);
void onAcrylicChanged(bool enabled);
+ void onExtendedFrameChanged(bool enabled);
signals:
void requestRefreshInternal(unsigned int requestId, QPrivateSignal priv);
@@ -109,6 +110,7 @@ private:
CompositorX11RenderClient* m_interfaceClient = nullptr;
bool m_hasAcrylic = false;
+ bool m_hasExtendedFrame = false;
bool m_visible = true;
};
@@ -163,6 +165,7 @@ public:
void setVideoSize(const QSize& size);
inline bool hasAcrylic() const { return m_hasAcrylic; }
+ inline bool supportExtendedFrame() const { return m_supportExtendedFrame; }
void setVideoWindow(QWindow* window);
void setInterfaceWindow(CompositorX11UISurface* window);
@@ -179,6 +182,7 @@ signals:
void videoSurfaceChanged(CompositorX11RenderClient*);
void visiblityChanged(bool visible);
void registerVideoWindow(unsigned int xid);
+ bool hasExtendedFrameChanged(bool hasExtendedFrame);
protected:
//override from QWindow
@@ -189,7 +193,8 @@ protected:
private:
void resetClientPixmaps();
-
+ void onWindowExtendedMarginChanged(unsigned margin);
+ void setHasExtendedFrame(bool hasExtendedFrame);
qt_intf_t* m_intf = nullptr;
xcb_connection_t* m_conn = nullptr;
@@ -202,6 +207,10 @@ private:
xcb_window_t m_wid = 0;
bool m_hasAcrylic = false;
+ //does the compositor support extended frames
+ bool m_supportExtendedFrame = false;
+ //is extended frame enabled
+ bool m_hasExtendedFrame = false;
QWindow* m_videoWindow = nullptr;
std::unique_ptr<CompositorX11RenderClient> m_videoClient;
=====================================
modules/gui/qt/maininterface/compositor_x11_utils.cpp
=====================================
@@ -130,4 +130,88 @@ void setTransparentForMouseEvent(xcb_connection_t* conn, xcb_window_t window)
xcb_xfixes_destroy_region(conn, region);
}
+//see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45894597940912
+bool wmScreenHasCompositor(xcb_connection_t* conn, int screen)
+{
+ QByteArray propName("_NET_WM_CM_S");
+ propName += QByteArray::number(screen);
+
+ xcb_atom_t atom = getInternAtom(conn, propName.constData());
+ if (atom == 0)
+ return false;
+
+ xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(conn, atom);
+ auto reply = wrap_cptr(xcb_get_selection_owner_reply(conn, cookie, nullptr));
+ if (!reply)
+ return false;
+
+ return reply->owner != 0;
+}
+
+//see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45894598144416
+static std::vector<xcb_atom_t> getNetSupportedList(xcb_connection_t* conn, xcb_window_t rootWindow)
+{
+ std::vector<xcb_atom_t> netSupportedList;
+
+ xcb_atom_t netSupportedAtom = getInternAtom(conn, "_NET_SUPPORTED");
+ if (netSupportedAtom == 0)
+ return netSupportedList;
+
+ int offset = 0;
+ int remaining = 0;
+ do {
+ xcb_get_property_cookie_t cookie = xcb_get_property(conn,
+ false, rootWindow, netSupportedAtom, XCB_ATOM_ATOM, offset, 1024);
+ auto reply = wrap_cptr(xcb_get_property_reply(conn, cookie, NULL));
+ if (!reply)
+ break;
+ if (reply->type == XCB_ATOM_ATOM && reply->format == 32)
+ {
+ int length = xcb_get_property_value_length(reply.get())/sizeof(xcb_atom_t);
+ xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply.get());
+
+ //&atoms[length] -> pointer past the last item
+ std::copy(&atoms[0], &atoms[length], std::back_inserter(netSupportedList));
+ remaining = reply->bytes_after;
+ offset += length;
+ }
+ } while (remaining > 0);
+
+ return netSupportedList;
+}
+
+static xcb_window_t getWindowProperty(xcb_connection_t* conn, xcb_window_t window, xcb_atom_t atom)
+{
+ xcb_get_property_cookie_t cookie = xcb_get_property(conn,
+ false, window, atom, 0, 0, 4096);
+ auto reply = wrap_cptr(xcb_get_property_reply(conn, cookie, NULL));
+ if (!reply)
+ return 0;
+
+ return ((xcb_window_t *)xcb_get_property_value(reply.get()))[0];
+}
+
+//see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45894598113264
+static bool supportWMCheck(xcb_connection_t* conn, xcb_window_t rootWindow)
+{
+ xcb_atom_t atom = getInternAtom(conn, "_NET_SUPPORTING_WM_CHECK");
+ xcb_window_t wmWindow = getWindowProperty(conn, rootWindow, atom);
+ if (wmWindow == 0)
+ return false;
+
+ xcb_window_t wmWindowProp = getWindowProperty(conn, wmWindow, atom);
+ return (wmWindow == wmWindowProp);
+}
+
+bool wmNetSupport(xcb_connection_t* conn, xcb_window_t rootWindow, xcb_atom_t atom)
+{
+ if (!supportWMCheck(conn, rootWindow))
+ return false;
+
+ std::vector<xcb_atom_t> netSupported = getNetSupportedList(conn, rootWindow);
+
+ auto it = std::find(netSupported.cbegin(), netSupported.cend(), atom);
+ return it != netSupported.cend();
+}
+
}
=====================================
modules/gui/qt/maininterface/compositor_x11_utils.hpp
=====================================
@@ -110,6 +110,11 @@ bool findVisualFormat(xcb_connection_t* conn, xcb_visualid_t visual, xcb_render_
xcb_atom_t getInternAtom(xcb_connection_t* conn, const char* atomName);
void setTransparentForMouseEvent(xcb_connection_t* conn, xcb_window_t window);
+
+bool wmScreenHasCompositor(xcb_connection_t* conn, int screen);
+
+bool wmNetSupport(xcb_connection_t* conn, xcb_window_t rootWindow, xcb_atom_t atom);
+
}
=====================================
modules/gui/qt/maininterface/interface_window_handler.cpp
=====================================
@@ -66,8 +66,9 @@ InterfaceWindowHandler::InterfaceWindowHandler(qt_intf_t *_p_intf, MainCtx* main
const auto updateMinimumSize = [this]()
{
- int width = 320;
- int height = 300;
+ int margin = m_mainCtx->windowExtendedMargin() * 2;
+ int width = 320 + margin;
+ int height = 300 + margin;
double intfScaleFactor = m_mainCtx->getIntfScaleFactor();
int scaledWidth = std::ceil( intfScaleFactor * width );
@@ -76,6 +77,7 @@ InterfaceWindowHandler::InterfaceWindowHandler(qt_intf_t *_p_intf, MainCtx* main
m_window->setMinimumSize( QSize(scaledWidth, scaledHeight) );
};
connect( m_mainCtx, &MainCtx::intfScaleFactorChanged, this, updateMinimumSize );
+ connect( m_mainCtx, &MainCtx::windowExtendedMarginChanged, this, updateMinimumSize );
m_mainCtx->updateIntfScaleFactor();
m_mainCtx->onWindowVisibilityChanged(m_window->visibility());
=====================================
modules/gui/qt/maininterface/mainctx.cpp
=====================================
@@ -271,6 +271,20 @@ void MainCtx::setUseGlobalShortcuts( bool useShortcuts )
emit useGlobalShortcutsChanged(m_useGlobalShortcuts);
}
+void MainCtx::setWindowSuportExtendedFrame(bool support) {
+ if (m_windowSuportExtendedFrame == support)
+ return;
+ m_windowSuportExtendedFrame = support;
+ emit windowSuportExtendedFrameChanged();
+}
+
+void MainCtx::setWindowExtendedMargin(unsigned int margin) {
+ if (margin == m_windowExtendedMargin)
+ return;
+ m_windowExtendedMargin = margin;
+ emit windowExtendedMarginChanged(margin);
+}
+
/*****************************
* Main UI handling *
*****************************/
=====================================
modules/gui/qt/maininterface/mainctx.hpp
=====================================
@@ -187,6 +187,9 @@ class MainCtx : public QObject
// NOTE: This is useful when we want to prioritize player hotkeys over QML keyboard navigation.
Q_PROPERTY(bool preferHotkeys READ preferHotkeys WRITE setPreferHotkeys NOTIFY preferHotkeysChanged FINAL)
+ Q_PROPERTY(bool windowSuportExtendedFrame READ windowSuportExtendedFrame NOTIFY windowSuportExtendedFrameChanged)
+ Q_PROPERTY(unsigned windowExtendedMargin READ windowExtendedMargin WRITE setWindowExtendedMargin NOTIFY windowExtendedMarginChanged)
+
public:
/* tors */
MainCtx(qt_intf_t *);
@@ -267,6 +270,11 @@ public:
inline float safeArea() const { return m_safeArea; }
+ inline bool windowSuportExtendedFrame() const { return m_windowSuportExtendedFrame; }
+ inline unsigned windowExtendedMargin() const { return m_windowExtendedMargin; }
+ void setWindowSuportExtendedFrame(bool support);
+ void setWindowExtendedMargin(unsigned margin);
+
bool hasEmbededVideo() const;
VideoSurfaceProvider* getVideoSurfaceProvider() const;
void setVideoSurfaceProvider(VideoSurfaceProvider* videoSurfaceProvider);
@@ -381,6 +389,9 @@ protected:
float m_safeArea = 0.0;
+ bool m_windowSuportExtendedFrame = false;
+ unsigned m_windowExtendedMargin = 0;
+
std::unique_ptr<CSDButtonModel> m_csdButtonModel;
public slots:
@@ -477,6 +488,9 @@ signals:
void safeAreaChanged();
+ void windowSuportExtendedFrameChanged();
+ void windowExtendedMarginChanged(unsigned margin);
+
private:
void loadPrefs(bool callSignals);
void loadFromSettingsImpl(bool callSignals);
=====================================
modules/gui/qt/maininterface/qml/MainInterface.qml
=====================================
@@ -20,236 +20,293 @@ import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
+import QtGraphicalEffects 1.12
import org.videolan.vlc 0.1
import org.videolan.compat 0.1
import "qrc:///widgets/" as Widgets
import "qrc:///style/"
-
import "qrc:///playlist/" as PL
Item {
- id: g_mainInterface
property bool _interfaceReady: false
property bool _playlistReady: false
+ property bool _extendedFrameVisible: MainCtx.windowSuportExtendedFrame
+ && MainCtx.clientSideDecoration
+ && (MainCtx.intfMainWindow.visibility === Window.Windowed)
- BindingCompat {
- target: VLCStyle
- property: "appWidth"
- value: g_mainInterface.width
- }
-
- BindingCompat {
- target: VLCStyle
- property: "appHeight"
- value: g_mainInterface.height
- }
-
- Window.onWindowChanged: {
- if (Window.window && !Qt.colorEqual(Window.window.color, "transparent")) {
- Window.window.color = Qt.binding(function() { return theme.bg.primary })
- }
- }
-
- ColorContext {
- id: theme
- palette: VLCStyle.palette
- colorSet: ColorContext.View
- }
-
- Widgets.ToolTipExt {
- id: attachedToolTip
+ readonly property var _pageModel: [
+ { name: "mc", url: "qrc:///main/MainDisplay.qml" },
+ { name: "player", url:"qrc:///player/Player.qml" },
+ ]
- parent: null
- z: 99
- colorContext.palette: parent && parent.colorContext ? parent.colorContext.palette
- : VLCStyle.palette
+ function setInitialView() {
+ //set the initial view
+ const loadPlayer = !MainPlaylistController.empty;
- Component.onCompleted: {
- MainCtx.setAttachedToolTip(this)
- }
- }
+ if (MainCtx.mediaLibraryAvailable)
+ History.push(["mc", "video"],
+ Qt.OtherFocusReason, loadPlayer ? History.Stay : History.Go)
+ else
+ History.push(["mc", "home"],
+ Qt.OtherFocusReason, loadPlayer ? History.Stay : History.Go)
- Loader {
- id: playlistWindowLoader
- asynchronous: true
- active: !MainCtx.playlistDocked && MainCtx.playlistVisible
- source: "qrc:///playlist/PlaylistDetachedWindow.qml"
- }
- Connections {
- target: playlistWindowLoader.item
- onClosing: MainCtx.playlistVisible = false
+ if (loadPlayer)
+ History.push(["player"])
}
- Connections {
- target: MainPlaylistController
-
- onPlaylistInitialized: {
- g_mainInterface._playlistReady = true
- if (g_mainInterface._interfaceReady)
- setInitialView()
- }
+ function _pushHome() {
+ if (MainCtx.mediaLibraryAvailable)
+ History.push(["mc", "video"])
+ else
+ History.push(["mc", "home"])
}
- readonly property var pageModel: [
- { name: "mc", url: "qrc:///main/MainDisplay.qml" },
- { name: "player", url:"qrc:///player/Player.qml" },
- ]
-
function loadCurrentHistoryView() {
const current = History.current
if ( !current || !current.name || !current.properties ) {
console.warn("unable to load requested view, undefined")
return
}
- stackView.loadView(g_mainInterface.pageModel, current.name, current.properties)
+ stackView.loadView(_pageModel, current.name, current.properties)
MainCtx.mediaLibraryVisible = (current.name !== "player")
}
- Connections {
- target: History
- onCurrentChanged: loadCurrentHistoryView()
- }
-
- Connections {
- target: MainCtx
+ Item {
+ id: g_mainInterface
- onMediaLibraryVisibleChanged: {
- if (MainCtx.mediaLibraryVisible) {
- // NOTE: Useful when we started the application on the 'player' view.
- if (History.previousEmpty) {
- if (MainCtx.hasEmbededVideo && MainCtx.canShowVideoPIP === false)
- MainPlaylistController.stop()
+ anchors.fill: parent
+ anchors.topMargin: MainCtx.windowExtendedMargin
+ anchors.leftMargin: MainCtx.windowExtendedMargin
+ anchors.rightMargin: MainCtx.windowExtendedMargin
+ anchors.bottomMargin: MainCtx.windowExtendedMargin
+
+ BindingCompat {
+ target: VLCStyle
+ property: "appWidth"
+ value: g_mainInterface.width
+ }
- _pushHome()
+ BindingCompat {
+ target: VLCStyle
+ property: "appHeight"
+ value: g_mainInterface.height
+ }
- return
- }
+ BindingCompat {
+ target: MainCtx
+ property: "windowExtendedMargin"
+ value: _extendedFrameVisible ? VLCStyle.dp(20, VLCStyle.scale) : 0
+ }
- if (History.current.name !== "player")
- return
+ Window.onWindowChanged: {
+ if (Window.window && !Qt.colorEqual(Window.window.color, "transparent")) {
+ Window.window.color = Qt.binding(function() { return theme.bg.primary })
+ }
+ }
- if (MainCtx.hasEmbededVideo && MainCtx.canShowVideoPIP === false)
- MainPlaylistController.stop()
+ ColorContext {
+ id: theme
+ palette: VLCStyle.palette
+ colorSet: ColorContext.View
+ }
- History.previous()
- } else {
- if (History.current.name === "player")
- return
+ Widgets.ToolTipExt {
+ id: attachedToolTip
- stackView.currentItem._inhibitMiniPlayer = true
+ parent: null
+ z: 99
+ colorContext.palette: parent && parent.colorContext ? parent.colorContext.palette
+ : VLCStyle.palette
- History.push(["player"])
+ Component.onCompleted: {
+ MainCtx.setAttachedToolTip(this)
}
}
- }
- function setInitialView() {
- //set the initial view
- const loadPlayer = !MainPlaylistController.empty;
+ Loader {
+ id: playlistWindowLoader
+ asynchronous: true
+ active: !MainCtx.playlistDocked && MainCtx.playlistVisible
+ source: "qrc:///playlist/PlaylistDetachedWindow.qml"
+ }
+ Connections {
+ target: playlistWindowLoader.item
+ onClosing: MainCtx.playlistVisible = false
+ }
- if (MainCtx.mediaLibraryAvailable)
- History.push(["mc", "video"],
- Qt.OtherFocusReason, loadPlayer ? History.Stay : History.Go)
- else
- History.push(["mc", "home"],
- Qt.OtherFocusReason, loadPlayer ? History.Stay : History.Go)
+ Connections {
+ target: MainPlaylistController
- if (loadPlayer)
- History.push(["player"])
- }
+ onPlaylistInitialized: {
+ _playlistReady = true
+ if (_interfaceReady)
+ setInitialView()
+ }
+ }
- function _pushHome() {
- if (MainCtx.mediaLibraryAvailable)
- History.push(["mc", "video"])
- else
- History.push(["mc", "home"])
- }
+ Connections {
+ target: History
+ onCurrentChanged: loadCurrentHistoryView()
+ }
- Component.onCompleted: {
- g_mainInterface._interfaceReady = true;
- if (g_mainInterface._playlistReady)
- setInitialView()
- }
+ Connections {
+ target: MainCtx
+ onMediaLibraryVisibleChanged: {
+ if (MainCtx.mediaLibraryVisible) {
+ // NOTE: Useful when we started the application on the 'player' view.
+ if (History.previousEmpty) {
+ if (MainCtx.hasEmbededVideo && MainCtx.canShowVideoPIP === false)
+ MainPlaylistController.stop()
- DropArea {
- anchors.fill: parent
- onDropped: {
- let urls = []
- if (drop.hasUrls) {
+ _pushHome()
- for (let i = 0; i < drop.urls.length; i++)
- urls.push(drop.urls[i])
+ return
+ }
- } else if (drop.hasText) {
- /* Browsers give content as text if you dnd the addressbar,
- so check if mimedata has valid url in text and use it
- if we didn't get any normal Urls()*/
+ if (History.current.name !== "player")
+ return
- urls.push(drop.text)
- }
+ if (MainCtx.hasEmbededVideo && MainCtx.canShowVideoPIP === false)
+ MainPlaylistController.stop()
- if (urls.length > 0) {
- /* D&D of a subtitles file, add it on the fly */
- if (Player.isPlaying && urls.length == 1) {
- if (Player.associateSubtitleFile(urls[0])) {
- drop.accept()
+ History.previous()
+ } else {
+ if (History.current.name === "player")
return
- }
- }
- MainPlaylistController.append(urls, true)
- drop.accept()
+ stackView.currentItem._inhibitMiniPlayer = true
+
+ History.push(["player"])
+ }
}
}
- Widgets.StackViewExt {
- id: stackView
+ Component.onCompleted: {
+ _interfaceReady = true;
+ if (_playlistReady)
+ setInitialView()
+ }
+
+
+ DropArea {
anchors.fill: parent
- focus: true
-
- Connections {
- target: Player
- onPlayingStateChanged: {
- if (Player.playingState === Player.PLAYING_STATE_STOPPED
- && History.current.name === "player") {
- if (History.previousEmpty)
- _pushHome()
- else
- History.previous()
+ onDropped: {
+ let urls = []
+ if (drop.hasUrls) {
+
+ for (let i = 0; i < drop.urls.length; i++)
+ urls.push(drop.urls[i])
+
+ } else if (drop.hasText) {
+ /* Browsers give content as text if you dnd the addressbar,
+ so check if mimedata has valid url in text and use it
+ if we didn't get any normal Urls()*/
+
+ urls.push(drop.text)
+ }
+
+ if (urls.length > 0) {
+ /* D&D of a subtitles file, add it on the fly */
+ if (Player.isPlaying && urls.length == 1) {
+ if (Player.associateSubtitleFile(urls[0])) {
+ drop.accept()
+ return
+ }
+ }
+
+ MainPlaylistController.append(urls, true)
+ drop.accept()
+ }
+ }
+
+ Widgets.StackViewExt {
+ id: stackView
+ anchors.fill: parent
+ focus: true
+ clip: _extendedFrameVisible
+
+ Connections {
+ target: Player
+ onPlayingStateChanged: {
+ if (Player.playingState === Player.PLAYING_STATE_STOPPED
+ && History.current.name === "player") {
+ if (History.previousEmpty)
+ _pushHome()
+ else
+ History.previous()
+ }
}
}
}
}
- }
- Loader {
- asynchronous: true
- source: "qrc:///menus/GlobalShortcuts.qml"
- }
+ Loader {
+ asynchronous: true
+ source: "qrc:///menus/GlobalShortcuts.qml"
+ }
- MouseArea {
- /// handles mouse navigation buttons
- anchors.fill: parent
- acceptedButtons: Qt.BackButton
- cursorShape: undefined
- onClicked: History.previous()
- }
+ MouseArea {
+ /// handles mouse navigation buttons
+ anchors.fill: parent
+ acceptedButtons: Qt.BackButton
+ cursorShape: undefined
+ onClicked: History.previous()
+ }
- Loader {
- active: {
- const windowVisibility = MainCtx.intfMainWindow.visibility
- return MainCtx.clientSideDecoration
- && (windowVisibility !== Window.Maximized)
- && (windowVisibility !== Window.FullScreen)
+ Loader {
+ active: {
+ const windowVisibility = MainCtx.intfMainWindow.visibility
+ return MainCtx.clientSideDecoration
+ && (windowVisibility !== Window.Maximized)
+ && (windowVisibility !== Window.FullScreen)
- }
+ }
- source: "qrc:///widgets/CSDMouseStealer.qml"
+ source: "qrc:///widgets/CSDMouseStealer.qml"
+
+ onLoaded: {
+ item.target = g_mainInterface
+ item.anchorInside = Qt.binding(() => !_extendedFrameVisible)
+ }
+ }
}
+ //draw the window drop shadow ourselve when the windowing system doesn't
+ //provide them but support extended frame
+ RectangularGlow {
+ id: effect
+ z: -1
+ visible: _extendedFrameVisible
+ anchors.fill: g_mainInterface
+ spread: 0.0
+ color: "black"
+ opacity: 0.5
+ cornerRadius: glowRadius
+ states: [
+ State {
+ when: MainCtx.intfMainWindow.active
+ PropertyChanges {
+ target: effect
+ glowRadius: MainCtx.windowExtendedMargin * 0.7
+ }
+ },
+ State {
+ when: !MainCtx.intfMainWindow.active
+ PropertyChanges {
+ target: effect
+ glowRadius: MainCtx.windowExtendedMargin * 0.5
+ }
+ }
+ ]
+ Behavior on glowRadius {
+ NumberAnimation {
+ duration: VLCStyle.duration_veryShort
+ }
+ }
+ }
}
=====================================
modules/gui/qt/widgets/qml/CSDMouseStealer.qml
=====================================
@@ -25,80 +25,165 @@ Item {
id: root
property int csdSize: MainCtx.csdBorderSize
+ /* required */ property Item target: null
+ property bool anchorInside: true
//private
- readonly property int _edgeVtHeight: g_mainInterface.height - root.csdSize * 2
- readonly property int _edgeHzWidth: g_mainInterface.width - root.csdSize * 2
+ readonly property int _targetHeight: target ? target.height : 0
+ readonly property int _targetWidth: target ? target.width : 0
+
+ readonly property int _edgeVtHeight: target ? (target.height - root.csdSize * 2) : 0
+ readonly property int _edgeHzWidth: target ? (target.width - root.csdSize * 2) : 0
+
+ //areas placed inside the target
+ readonly property var _innerModel: [
+ //Edges
+ {
+ edge: Qt.TopEdge,
+ x: root.csdSize,
+ y: 0,
+ width: root._edgeHzWidth,
+ height: root.csdSize,
+ cursor: Qt.SizeVerCursor,
+ },
+ {
+ edge: Qt.LeftEdge,
+ x: 0,
+ y: root.csdSize,
+ width: root.csdSize,
+ height: root._edgeVtHeight,
+ cursor: Qt.SizeHorCursor,
+ },
+ {
+ edge: Qt.RightEdge,
+ x: _targetWidth - root.csdSize,
+ y: root.csdSize,
+ width: root.csdSize,
+ height: root._edgeVtHeight,
+ cursor: Qt.SizeHorCursor,
+ },
+ {
+ edge: Qt.BottomEdge,
+ x: root.csdSize,
+ y: _targetHeight - root.csdSize,
+ width: root._edgeHzWidth,
+ height: root.csdSize,
+ cursor: Qt.SizeVerCursor,
+ },
+ //Corners
+ {
+ edge: Qt.TopEdge | Qt.LeftEdge,
+ x: 0,
+ y: 0,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeFDiagCursor,
+ },
+ {
+ edge: Qt.BottomEdge | Qt.LeftEdge,
+ x: 0,
+ y: _targetHeight - root.csdSize,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeBDiagCursor,
+ },
+ {
+ edge: Qt.TopEdge | Qt.RightEdge,
+ x: _targetWidth - root.csdSize,
+ y: 0,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeBDiagCursor,
+ },
+ {
+ edge: Qt.BottomEdge | Qt.RightEdge,
+ x: _targetWidth - root.csdSize,
+ y: _targetHeight - root.csdSize,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeFDiagCursor,
+ },
+ ]
+
+ //areas placed ouside the target
+ readonly property var _outterModel: [
+ //Edges
+ {
+ edge: Qt.TopEdge,
+ x: 0,
+ y: -root.csdSize,
+ width: _targetWidth,
+ height: root.csdSize,
+ cursor: Qt.SizeVerCursor,
+ },
+ {
+ edge: Qt.LeftEdge,
+ x: -root.csdSize,
+ y: 0,
+ width: root.csdSize,
+ height: _targetHeight,
+ cursor: Qt.SizeHorCursor,
+ },
+ {
+ edge: Qt.RightEdge,
+ x: _targetWidth,
+ y: 0,
+ width: root.csdSize,
+ height: _targetHeight,
+ cursor: Qt.SizeHorCursor,
+ },
+ {
+ edge: Qt.BottomEdge,
+ x: 0,
+ y: _targetHeight,
+ width: _targetWidth,
+ height: root.csdSize,
+ cursor: Qt.SizeVerCursor,
+ },
+ //Corners
+ {
+ edge: Qt.TopEdge | Qt.LeftEdge,
+ x: -root.csdSize,
+ y: -root.csdSize,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeFDiagCursor,
+ },
+ {
+ edge: Qt.BottomEdge | Qt.LeftEdge,
+ x: -root.csdSize,
+ y: _targetHeight,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeBDiagCursor,
+ },
+ {
+ edge: Qt.TopEdge | Qt.RightEdge,
+ x: _targetWidth,
+ y: -root.csdSize,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeBDiagCursor,
+ },
+ {
+ edge: Qt.BottomEdge | Qt.RightEdge,
+ x: _targetWidth,
+ y: _targetHeight,
+ width: root.csdSize,
+ height: root.csdSize,
+ cursor: Qt.SizeFDiagCursor,
+ },
+ ]
Repeater {
- model: [
- //Edges
- {
- edge: Qt.TopEdge,
- x: root.csdSize,
- y: 0,
- width: root._edgeHzWidth,
- height: root.csdSize,
- cursor: Qt.SizeVerCursor,
- },
- {
- edge: Qt.LeftEdge,
- x: 0,
- y: root.csdSize,
- width: root.csdSize,
- height: root._edgeVtHeight,
- cursor: Qt.SizeHorCursor,
- },
- {
- edge: Qt.RightEdge,
- x: g_mainInterface.width - root.csdSize,
- y: root.csdSize,
- width: root.csdSize,
- height: root._edgeVtHeight,
- cursor: Qt.SizeHorCursor,
- },
- {
- edge: Qt.BottomEdge,
- x: root.csdSize,
- y: g_mainInterface.height - root.csdSize,
- width: root._edgeHzWidth,
- height: root.csdSize,
- cursor: Qt.SizeVerCursor,
- },
- //Corners
- {
- edge: Qt.TopEdge | Qt.LeftEdge,
- x: 0,
- y: 0,
- width: root.csdSize,
- height: root.csdSize,
- cursor: Qt.SizeFDiagCursor,
- },
- {
- edge: Qt.BottomEdge | Qt.LeftEdge,
- x: 0,
- y: g_mainInterface.height - root.csdSize,
- width: root.csdSize,
- height: root.csdSize,
- cursor: Qt.SizeBDiagCursor,
- },
- {
- edge: Qt.TopEdge | Qt.RightEdge,
- x: g_mainInterface.width - root.csdSize,
- y: 0,
- width: root.csdSize,
- height: root.csdSize,
- cursor: Qt.SizeBDiagCursor,
- },
- {
- edge: Qt.BottomEdge | Qt.RightEdge,
- x: g_mainInterface.width - root.csdSize,
- y: g_mainInterface.height - root.csdSize,
- width: root.csdSize,
- height: root.csdSize,
- cursor: Qt.SizeFDiagCursor,
- },
- ]
+ model: {
+ if (!target)
+ return 0
+ else if (anchorInside)
+ return _innerModel
+ else
+ return _outterModel
+ }
delegate: MouseArea {
x: modelData.x
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/8c569859a0b36b438bd4979c3f96e91bed55a88b...e3dea2575851338e8df78d1886d450f1a698e378
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/8c569859a0b36b438bd4979c3f96e91bed55a88b...e3dea2575851338e8df78d1886d450f1a698e378
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list