Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  interface_window_handler.cpp   Sprache: C

 

/*****************************************************************************
 * Copyright (C) 2020 VideoLAN and AUTHORS
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "interface_window_handler.hpp"
#include "mainctx.hpp"
#include "compositor.hpp"
#include <player/player_controller.hpp>
#include <playlist/playlist_controller.hpp>
#include "util/keyhelper.hpp"
#include "dialogs/systray/systray.hpp"
#include "widgets/native/qvlcframe.hpp"
#include "dialogs/dialogs/dialogmodel.hpp"
#include <QScreen>
#include <QQmlProperty>
#include <cmath>

namespace
{

void setWindowState(QWindow *window, Qt::WindowState state)
{
    // make sure to preserve original state, Qt saves this info
    // in underlying platform window but we need this in top level
    // so that our window handling code works.
    // see issue #28071
    const auto original = window->windowStates();
    window->setWindowStates(original | state);
}

}

const Qt::Key InterfaceWindowHandler::kc[10] =
{
        Qt::Key_Up, Qt::Key_Up,
        Qt::Key_Down, Qt::Key_Down,
        Qt::Key_Left, Qt::Key_Right, Qt::Key_Left, Qt::Key_Right,
        Qt::Key_B, Qt::Key_A
};

InterfaceWindowHandler::InterfaceWindowHandler(qt_intf_t *_p_intf, MainCtx* mainCtx, QWindow* window, QObject *parent)
    : QObject(parent)
    , p_intf(_p_intf)
    , m_window(window)
    , m_mainCtx(mainCtx)
{
    assert(m_window);
    assert(m_mainCtx);

    if (m_mainCtx->useClientSideDecoration())
        m_window->setFlag(Qt::FramelessWindowHint);

    /* */
    m_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );

    m_window->setIcon( QApplication::windowIcon() );
    m_window->setOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );

    QVLCTools::restoreWindowPosition( getSettings(), m_window, QSize(600, 420) );

    // this needs to be called asynchronously
    // otherwise QQuickWidget won't initialize properly
    QMetaObject::invokeMethod(this, [this]()
    {
        WindowStateHolder::holdOnTop( m_window,  WindowStateHolder::INTERFACE, m_mainCtx->isInterfaceAlwaysOnTop() );
        WindowStateHolder::holdFullscreen( m_window,  WindowStateHolder::INTERFACE, m_window->visibility() == QWindow::FullScreen );

        if (m_mainCtx->isHideAfterCreation())
            m_window->hide();
    }, Qt::QueuedConnection);

    m_window->setTitle("");

    if( var_InheritBool( p_intf, "qt-name-in-title" ) )
    {
        connect( THEMIM, &PlayerController::nameChanged, m_window, &QWindow::setTitle );
    }

    connect( m_window, &QWindow::screenChanged, m_mainCtx, &MainCtx::updateIntfScaleFactor );

    const auto updateMinimumSize = [this]()
    {
        if (m_mainCtx->isMinimalView())
        {
            m_window->setMinimumSize({128, 16});
            return;
        }

        int margin = m_mainCtx->windowExtendedMargin() * 2;
        int width = 320 + margin;
        int height = 360 + margin;

        double intfScaleFactor = m_mainCtx->getIntfScaleFactor();
        int scaledWidth = std::ceil( intfScaleFactor * width );
        int scaledHeight = std::ceil( intfScaleFactor * height );

        m_window->setMinimumSize( QSize(scaledWidth, scaledHeight) );
    };
    connect( m_mainCtx, &MainCtx::intfScaleFactorChanged, this, updateMinimumSize );
    connect( m_mainCtx, &MainCtx::windowExtendedMarginChanged, this, updateMinimumSize );
    connect( m_mainCtx, &MainCtx::mainInterfaceModesChanged, this, updateMinimumSize );
    m_mainCtx->updateIntfScaleFactor();
    updateMinimumSize();

    m_mainCtx->onWindowVisibilityChanged(m_window->visibility());
    connect( m_window, &QWindow::visibilityChanged,
             m_mainCtx, &MainCtx::onWindowVisibilityChanged);

    connect( m_mainCtx, &MainCtx::askBoss,
             this, &InterfaceWindowHandler::setBoss, Qt::QueuedConnection  );
    connect( m_mainCtx, &MainCtx::askRaise,
             this, &InterfaceWindowHandler::setRaise, Qt::QueuedConnection  );

    connect( m_mainCtx, &MainCtx::interfaceAlwaysOnTopChanged,
             this, &InterfaceWindowHandler::setInterfaceAlwaysOnTop);

    connect( m_mainCtx, &MainCtx::setInterfaceFullScreen,
             this, &InterfaceWindowHandler::setInterfaceFullScreen);

    connect( m_mainCtx, &MainCtx::toggleWindowVisibility,
             this, &InterfaceWindowHandler::toggleWindowVisibility);

    connect( m_mainCtx, &MainCtx::setInterfaceVisibible,
             this, &InterfaceWindowHandler::setInterfaceVisible);

    connect(this, &InterfaceWindowHandler::incrementIntfUserScaleFactor,
            m_mainCtx, &MainCtx::incrementIntfUserScaleFactor);

    connect( m_mainCtx, &MainCtx::useClientSideDecorationChanged,
             this, &InterfaceWindowHandler::updateCSDWindowSettings );

    connect(m_mainCtx, &MainCtx::requestInterfaceMaximized,
            this, &InterfaceWindowHandler::setInterfaceMaximized);

    connect(m_mainCtx, &MainCtx::requestInterfaceNormal,
            this, &InterfaceWindowHandler::setInterfaceNormal);

    connect(m_mainCtx, &MainCtx::requestInterfaceMinimized,
            this, &InterfaceWindowHandler::setInterfaceMinimized);

    connect(this, &InterfaceWindowHandler::kc_pressed,
            m_mainCtx, &MainCtx::kc_pressed);

    const auto dem = DialogErrorModel::getInstance<false>(); // expected to be already created
    assert(dem);
    connect(dem, &DialogErrorModel::rowsInserted, this, [w = QPointer(m_window)]() {
        if (Q_LIKELY(w))
            w->alert(0);
    });

    connect(
        &m_wheelAccumulator, &WheelToVLCConverter::wheelUpDown,
        this, [this] (int steps, Qt::KeyboardModifiers modifiers) {
            if (modifiers != Qt::ControlModifier)
                return;
            emit incrementIntfUserScaleFactor(steps > 0);
    });

    m_window->installEventFilter(this);
}

InterfaceWindowHandler::~InterfaceWindowHandler()
{
    m_window->removeEventFilter(this);
    /* Save this size */
    QVLCTools::saveWindowPosition(getSettings(), m_window);
    assert(qApp);
    if (!qApp->property("isDying").toBool())
    {
        // If application is dying, we don't need to adjust the state
        WindowStateHolder::holdOnTop( m_window,  WindowStateHolder::INTERFACE, false );
        WindowStateHolder::holdFullscreen( m_window,  WindowStateHolder::INTERFACE, false );
    }
}

void InterfaceWindowHandler::updateCSDWindowSettings()
{
    m_window->setFlag(Qt::FramelessWindowHint, m_mainCtx->useClientSideDecoration());
}

bool InterfaceWindowHandler::eventFilter(QObject*, QEvent* event)
{
    switch ( event->type() )
    {
    case QEvent::WindowStateChange:
    {
        QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
        Qt::WindowStates newState = m_window->windowStates();
        Qt::WindowStates oldState = windowStateChangeEvent->oldState();

        /* b_maximizedView stores if the window was maximized before entering fullscreen.
         * It is set when entering maximized mode, unset when leaving it to normal mode.
         * Upon leaving full screen, if b_maximizedView is set,
         * the window should be maximized again. */

        if( newState & Qt::WindowMaximized &&
            !( oldState & Qt::WindowMaximized ) )
            m_maximizedView = true;

        if( !( newState & Qt::WindowMaximized ) &&
            oldState & Qt::WindowMaximized ) //FIXME && !b_videoFullScreen )
            m_maximizedView = false;

        if( !( newState & Qt::WindowFullScreen ) &&
            oldState & Qt::WindowFullScreen &&
            m_maximizedView )
        {
            setInterfaceMaximized();
            return false;
        }

        if( newState & Qt::WindowMinimized )
        {

            m_hasPausedWhenMinimized = false;

            if( THEMIM->getPlayingState() == PlayerController::PLAYING_STATE_PLAYING &&
                THEMIM->hasVideoOutput() && !THEMIM->hasAudioVisualization() &&
                m_pauseOnMinimize )
            {
                m_hasPausedWhenMinimized = true;
                THEMPL->pause();
            }
        }
        else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
        {
            if( m_hasPausedWhenMinimized )
            {
                THEMPL->play();
            }
        }
        break;
    }
    case QEvent::KeyPress:
    {
        QKeyEvent * keyEvent = static_cast<QKeyEvent *> (event);

        /* easter eggs sequence handling */
        if ( keyEvent->key() == kc[ i_kc_offset ] )
            i_kc_offset++;
        else
            i_kc_offset = 0;

        if ( i_kc_offset == ARRAY_SIZE( kc ) )
        {
            i_kc_offset = 0;
            emit kc_pressed();
        }

        if (applyKeyEvent(keyEvent) == false)
            return false;

        m_mainCtx->sendHotkey(static_cast<Qt::Key> (keyEvent->key()), keyEvent->modifiers());

        return true;
    }
    case QEvent::KeyRelease:
    {
        return applyKeyEvent(static_cast<QKeyEvent *> (event));
    }
    case QEvent::Wheel:
    {
        QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
        if (wheelEvent->modifiers() == Qt::ControlModifier)
        {
            m_wheelAccumulator.wheelEvent(wheelEvent);
            wheelEvent->accept();
            return true;
        }
        break;
    }
    case QEvent::Close:
    {
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
        // Before Qt 6.9.0, `QWindow`'s `wl_surface` gets deleted when `QWindow::hide()` is called.
        static bool platformIsWayland = []() {
            assert(qGuiApp);
            return qGuiApp->platformName().startsWith(QLatin1String("wayland"));
        }();

        if (!platformIsWayland)
            setInterfaceHiden();
#else
        setInterfaceHiden();
#endif

        if (var_InheritBool(p_intf, "qt-close-to-system-tray"))
        {
            if (const QSystemTrayIcon* const sysTrayIcon = m_mainCtx->getSysTray())
            {
                if (sysTrayIcon->isSystemTrayAvailable() && sysTrayIcon->isVisible())
                {
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
                    if (platformIsWayland)
                        setInterfaceHiden();
#endif
                    event->ignore();
                    return true;
                }
            }
        }

        m_mainCtx->onWindowClose(m_window);
        event->ignore();
        return true;
    }
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
    case QEvent::DevicePixelRatioChange:
    {
        m_mainCtx->intfDevicePixelRatioChanged();
    }
#endif

    default:
        break;
    }

    return false;
}

void InterfaceWindowHandler::onVideoEmbedChanged(bool embed)
{
    if (embed)
    {
        m_interfaceGeometry = m_window->geometry();
    }
    else if (!m_interfaceGeometry.isNull())
    {
        m_window->setGeometry(m_interfaceGeometry);
        m_interfaceGeometry = QRect();
    }
}


void InterfaceWindowHandler::toggleWindowVisibility(bool _requestActivate)
{
    switch ( m_window->visibility() )
    {
    case QWindow::Hidden:
        /* If hidden, show it */
        setInterfaceShown();
        if (_requestActivate)
            requestActivate();
        break;
    case QWindow::Minimized:
        setInterfaceNormal();
        if (_requestActivate)
            requestActivate();
        break;
    default:
        setInterfaceHiden();
        break;
    }
}


void InterfaceWindowHandler::setInterfaceVisible(bool visible, bool _requestActivate)
{
    if (visible)
    {
        switch ( m_window->visibility() )
        {
        case QWindow::Hidden:
            setInterfaceShown();
            if (_requestActivate)
                requestActivate();
            break;
        case QWindow::Minimized:
            setInterfaceNormal();
            if (_requestActivate)
                requestActivate();
            break;
        default:
            break;
        }
    }
    else
    {
        setInterfaceHiden();
    }
}


void InterfaceWindowHandler::setFullScreen( bool fs )
{
    WindowStateHolder::holdFullscreen(m_window, WindowStateHolder::INTERFACE, fs);
}

void InterfaceWindowHandler::setInterfaceFullScreen( bool fs )
{
    setFullScreen(fs);
    emit interfaceFullScreenChanged( fs );
}

void InterfaceWindowHandler::setRaise()
{
    assert(m_window);

    switch ( m_window->visibility() )
    {
    case QWindow::Hidden:
        /* If hidden, show it */
        setInterfaceShown();
        break;
    case QWindow::Minimized:
        setInterfaceNormal();
        break;
    default:
        break;
    }

    requestActivate();
    m_window->raise();
}

void InterfaceWindowHandler::setBoss()
{
    THEMPL->pause();
    if( m_mainCtx->getSysTray() )
    {
        setInterfaceHiden();
    }
    else
    {
        setInterfaceMinimized();
    }
}

void InterfaceWindowHandler::setInterfaceHiden()
{
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
    // `CompositorWayland` depends on the promise that the window resources are not deleted.
    // Window's `wl_surface` gets deleted when the window gets hidden before Qt 6.9.0. So,
    // here we should inhibit hiding the window. Note that intercepting `QEvent::hide` does
    // not make it possible to inhibit hiding the window.
    assert(p_intf);
    assert(p_intf->p_compositor);
    static bool inhibitHide = [intf = p_intf]() {
        assert(qGuiApp);
        // type() == WaylandCompositor is not used because any video embedding methodology may
        // depend on window resources:
        const bool ret = qGuiApp->platformName().startsWith(QLatin1String("wayland")) &&
                         (intf->p_compositor && (intf->p_compositor->type() != vlc::Compositor::DummyCompositor));
        if (ret)
            msg_Warn(intf, "In this configuration, the interface window can not get hidden.");
        return ret;
    }();

    if (inhibitHide)
    {
        // Instead of doing nothing, minimize the window:
        setInterfaceMinimized();
        return;
    }
#endif

    m_window->hide();
}

void InterfaceWindowHandler::setInterfaceShown()
{
    m_window->setVisible(true);
}

void InterfaceWindowHandler::setInterfaceMinimized()
{
    setWindowState(m_window, Qt::WindowMinimized);
}

void InterfaceWindowHandler::setInterfaceMaximized()
{
    setWindowState(m_window, Qt::WindowMaximized);
}

void InterfaceWindowHandler::setInterfaceNormal()
{
    m_window->showNormal();
}


void InterfaceWindowHandler::requestActivate()
{
    m_window->requestActivate();
}

void InterfaceWindowHandler::setInterfaceAlwaysOnTop( bool on_top )
{
    WindowStateHolder::holdOnTop(m_window, WindowStateHolder::INTERFACE, on_top);
}

// Functions private

bool InterfaceWindowHandler::applyKeyEvent(QKeyEvent * event) const
{
    int key = event->key();

    // NOTE: We have to make sure tab and backtab are never used as hotkeys. When browsing the
    //       MediaLibrary, we let the view handle the navigation keys.
    if (key == Qt::Key_Tab || key == Qt::Key_Backtab || m_mainCtx->preferHotkeys() == false)
    {
        return false;
    }

    QQuickItem * item = p_intf->p_compositor->activeFocusItem();

    // NOTE: When the item has visual focus we let it handle the key. When the item does not
    //       inherit from QQuickControl we have to declare the 'visualFocus' property ourselves.
    if (item)
    {

        QVariant visualFocus = QQmlProperty::read(item, "visualFocus", qmlContext(item));
        if (visualFocus.isValid())
        {
            if (visualFocus.toBool())
                return false;
        }
        //while being QuickControls TextField and TextArea don't provide visualFocus property
        //here we check their (non control) parent class, this should cover all text input widgets
        else if (item->inherits("QQuickTextInput") || item->inherits("QQuickTextEdit"))
        {
            QVariant activeFocus = QQmlProperty::read(item, "activeFocus", qmlContext(item));
            if (activeFocus.isValid())
            {
                if (activeFocus.toBool())
                    return false;
            }
        }
    }

    event->accept();

    return true;
}

Messung
CHZG
841009091

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=417989