Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (8)
Showing
with 575 additions and 246 deletions
......@@ -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 {
......
......@@ -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);
......
......@@ -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)
......
......@@ -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());
......
......@@ -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);
}
......@@ -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;
......
......@@ -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();
}
}
......@@ -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);
}
......
......@@ -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());
......
......@@ -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 *
*****************************/
......
......@@ -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);
......
......@@ -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
}
}
}
}
......@@ -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
......