diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index f618adae2..a070a5be4 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -596,11 +596,11 @@ bool Application::isActiveForTrayMenu() const { } bool Application::hideMediaView() { - if (_mediaView && !_mediaView->isHidden()) { - _mediaView->hide(); - if (const auto window = activeWindow()) { - window->reActivate(); - } + if (_mediaView + && _mediaView->isFullScreen() + && !_mediaView->isMinimized() + && !_mediaView->isHidden()) { + _mediaView->close(); return true; } return false; @@ -1489,7 +1489,10 @@ void Application::windowActivated(not_null window) { nowSession->updates().updateOnline(); } } - if (_mediaView && !_mediaView->isHidden()) { + if (_mediaView + && !_mediaView->isHidden() + && !_mediaView->isMinimized() + && _mediaView->isFullScreen()) { _mediaView->activate(); } } diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index bc8f8beb2..80a7e8502 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -240,7 +240,6 @@ mediaviewTextTop: 24px; mediaviewIconOpacity: 0.45; mediaviewIconOverOpacity: 1.; -mediaviewControlMargin: 0px; mediaviewControlSize: 90px; mediaviewIconSize: size(60px, 56px); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 84d1d2a57..51e70ec0c 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -18,11 +18,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/mime_type.h" #include "core/ui_integration.h" #include "core/crash_reports.h" +#include "core/sandbox.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/buttons.h" #include "ui/image/image.h" #include "ui/text/text_utilities.h" #include "ui/platform/ui_platform_utility.h" +#include "ui/platform/ui_platform_window_title.h" #include "ui/toast/toast.h" #include "ui/toasts/common_toasts.h" #include "ui/text/format_values.h" @@ -31,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/ui_utility.h" #include "ui/cached_round_corners.h" #include "ui/gl/gl_surface.h" +#include "ui/gl/gl_window.h" #include "ui/boxes/confirm_box.h" #include "info/info_memento.h" #include "info/info_controller.h" @@ -84,6 +87,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_media_view.h" #include "styles/style_chat.h" #include "styles/style_menu_icons.h" +#include "styles/style_window.h" // windowDefaultWidth / windowDefaultHeight +#include "styles/style_calls.h" #ifdef Q_OS_MAC #include "platform/mac/touchbar/mac_touchbar_media_view.h" @@ -293,18 +298,27 @@ OverlayWidget::PipWrap::PipWrap( } OverlayWidget::OverlayWidget() -: _surface(Ui::GL::CreateSurface( - [=](Ui::GL::Capabilities capabilities) { - return chooseRenderer(capabilities); - })) +: _supportWindowMode(!Platform::IsMac()) +, _wrap(std::make_unique()) +, _window(_wrap->window()) +#ifndef Q_OS_MAC +, _controls(Ui::Platform::SetupSeparateTitleControls( + _window.get(), + st::callTitle, + [=](bool maximized) { toggleFullScreen(maximized); })) +#endif +, _body(_wrap->widget()) +, _surface( + Ui::GL::CreateSurface(_body, chooseRenderer(_wrap->backend()))) , _widget(_surface->rpWidget()) -, _docDownload(_widget, tr::lng_media_download(tr::now), st::mediaviewFileLink) -, _docSaveAs(_widget, tr::lng_mediaview_save_as(tr::now), st::mediaviewFileLink) -, _docCancel(_widget, tr::lng_cancel(tr::now), st::mediaviewFileLink) +, _fullscreen(true || !_supportWindowMode) +, _docDownload(_body, tr::lng_media_download(tr::now), st::mediaviewFileLink) +, _docSaveAs(_body, tr::lng_mediaview_save_as(tr::now), st::mediaviewFileLink) +, _docCancel(_body, tr::lng_cancel(tr::now), st::mediaviewFileLink) , _radial([=](crl::time now) { return radialAnimationCallback(now); }) , _lastAction(-st::mediaviewDeltaFromLastAction, -st::mediaviewDeltaFromLastAction) , _stateAnimation([=](crl::time now) { return stateAnimationCallback(now); }) -, _dropdown(_widget, st::mediaviewDropdownMenu) { +, _dropdown(_body, st::mediaviewDropdownMenu) { CrashReports::SetAnnotation("OpenGL Renderer", "[not-initialized]"); Lang::Updated( @@ -316,8 +330,6 @@ OverlayWidget::OverlayWidget() ? Core::App().settings().videoVolume() : Core::Settings::kDefaultVolume; - _widget->setWindowTitle(u"Media viewer"_q); - const auto text = tr::lng_mediaview_saved_to( tr::now, lt_downloads, @@ -339,23 +351,7 @@ OverlayWidget::OverlayWidget() QImage::Format_ARGB32_Premultiplied); _docRectImage.setDevicePixelRatio(cIntRetinaFactor()); - _surface->shownValue( - ) | rpl::start_with_next([=](bool shown) { - toggleApplicationEventFilter(shown); - if (shown) { - const auto geometry = _widget->geometry(); - const auto screenList = QGuiApplication::screens(); - DEBUG_LOG(("Viewer Pos: Shown, geometry: %1, %2, %3, %4, screen number: %5") - .arg(geometry.x()) - .arg(geometry.y()) - .arg(geometry.width()) - .arg(geometry.height()) - .arg(screenList.indexOf(_widget->screen()))); - moveToScreen(); - } else { - clearAfterHide(); - } - }, lifetime()); + setupWindow(); const auto mousePosition = [](not_null e) { return static_cast(e.get())->pos(); @@ -363,7 +359,7 @@ OverlayWidget::OverlayWidget() const auto mouseButton = [](not_null e) { return static_cast(e.get())->button(); }; - base::install_event_filter(_widget, [=](not_null e) { + base::install_event_filter(_window, [=](not_null e) { const auto type = e->type(); if (type == QEvent::Move) { const auto position = static_cast(e.get())->pos(); @@ -371,20 +367,40 @@ OverlayWidget::OverlayWidget() .arg(position.x()) .arg(position.y())); moveToScreen(true); - } else if (type == QEvent::Resize) { + } else if (type == QEvent::Close + && !Core::Sandbox::Instance().isSavingSession() + && !Core::Quitting()) { + close(); + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }); + base::install_event_filter(_body, [=](not_null e) { + const auto type = e->type(); + if (type == QEvent::Resize) { const auto size = static_cast(e.get())->size(); DEBUG_LOG(("Viewer Pos: Resized to %1, %2") .arg(size.width()) .arg(size.height())); + _widget->setGeometry({ QPoint(), size }); updateControlsGeometry(); + } else if (type == QEvent::KeyPress) { + handleKeyPress(static_cast(e.get())); + } + return base::EventFilterResult::Continue; + }); + base::install_event_filter(_widget, [=](not_null e) { + const auto type = e->type(); + if (type == QEvent::Leave) { + if (_over != OverNone) { + updateOverState(OverNone); + } } else if (type == QEvent::MouseButtonPress) { handleMousePress(mousePosition(e), mouseButton(e)); } else if (type == QEvent::MouseButtonRelease) { handleMouseRelease(mousePosition(e), mouseButton(e)); } else if (type == QEvent::MouseMove) { handleMouseMove(mousePosition(e)); - } else if (type == QEvent::KeyPress) { - handleKeyPress(static_cast(e.get())); } else if (type == QEvent::ContextMenu) { const auto event = static_cast(e.get()); const auto mouse = (event->reason() == QContextMenuEvent::Mouse); @@ -413,22 +429,18 @@ OverlayWidget::OverlayWidget() return base::EventFilterResult::Continue; }); - if constexpr (Platform::IsWindows()) { - _widget->setWindowFlags(Qt::FramelessWindowHint); - } else if constexpr (Platform::IsMac()) { + _window->setTitle(u"Media viewer"_q); + _window->setTitleStyle(st::callTitle); + + if constexpr (Platform::IsMac()) { // Without Qt::Tool starting with Qt 5.15.1 this widget // when being opened from a fullscreen main window was // opening not as overlay over the main window, but as // a separate fullscreen window with a separate space. - _widget->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); + _window->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); } - _widget->setAttribute(Qt::WA_NoSystemBackground, true); - _widget->setAttribute(Qt::WA_TranslucentBackground, true); _widget->setMouseTracking(true); - hide(); - _widget->createWinId(); - QObject::connect( window(), &QWindow::screenChanged, @@ -439,7 +451,7 @@ OverlayWidget::OverlayWidget() #ifdef Q_OS_MAC TouchBar::SetupMediaViewTouchBar( - _widget->winId(), + _window->winId(), static_cast(this), _touchbarTrackState.events(), _touchbarDisplay.events(), @@ -472,6 +484,77 @@ OverlayWidget::OverlayWidget() _dropdown->setHiddenCallback([this] { dropdownHidden(); }); _dropdownShowTimer.setCallback([=] { showDropdown(); }); + + orderWidgets(); +} + +void OverlayWidget::orderWidgets() { +#ifndef Q_OS_MAC + _controls->wrap.raise(); +#endif // !Q_OS_MAC +} + +void OverlayWidget::setupWindow() { + _window->setBodyTitleArea([=](QPoint widgetPoint) { + using Flag = Ui::WindowTitleHitTestFlag; + if (!_windowed || !_widget->rect().contains(widgetPoint)) { + return Flag::None | Flag(0); + } +#ifndef Q_OS_MAC + if (_controls->controls.geometry().contains(widgetPoint)) { + return Flag::None | Flag(0); + } +#endif // !Q_OS_MAC + const auto inControls = (_over != OverNone) && (_over != OverVideo); + if (inControls) { + return Flag::None | Flag(0); + } + return Flag::Move | Flag(0); + }); + + if (_supportWindowMode) { + const auto callback = [=](Qt::WindowState state) { + if (state == Qt::WindowMinimized) { + return; + } else if (state == Qt::WindowFullScreen) { + _fullscreen = true; + _windowed = false; + } else if (state == Qt::WindowMaximized) { + _fullscreen = _windowed = false; + } else { + _fullscreen = false; + _windowed = true; + } + }; + QObject::connect( + _window->windowHandle(), + &QWindow::windowStateChanged, + callback); + } + + _window->setAttribute(Qt::WA_NoSystemBackground, true); + _window->setAttribute(Qt::WA_TranslucentBackground, true); + + _window->setMinimumSize( + { st::windowDefaultWidth, st::windowDefaultHeight }); + + _window->shownValue( + ) | rpl::start_with_next([=](bool shown) { + toggleApplicationEventFilter(shown); + if (!shown) { + clearAfterHide(); + } else { + const auto geometry = _window->geometry(); + const auto screenList = QGuiApplication::screens(); + DEBUG_LOG(("Viewer Pos: Shown, geometry: %1, %2, %3, %4, screen number: %5") + .arg(geometry.x()) + .arg(geometry.y()) + .arg(geometry.width()) + .arg(geometry.height()) + .arg(screenList.indexOf(_window->screen()))); + moveToScreen(); + } + }, lifetime()); } void OverlayWidget::refreshLang() { @@ -479,6 +562,9 @@ void OverlayWidget::refreshLang() { } void OverlayWidget::moveToScreen(bool inMove) { + if (!_fullscreen) { + return; + } const auto widgetScreen = [&](auto &&widget) -> QScreen* { if (!widget) { return nullptr; @@ -495,7 +581,7 @@ void OverlayWidget::moveToScreen(bool inMove) { ? Core::App().activeWindow()->widget().get() : nullptr; const auto activeWindowScreen = widgetScreen(applicationWindow); - const auto myScreen = widgetScreen(_widget); + const auto myScreen = widgetScreen(_window); if (activeWindowScreen && myScreen != activeWindowScreen) { const auto screenList = QGuiApplication::screens(); DEBUG_LOG(("Viewer Pos: Currently on screen %1, moving to screen %2") @@ -503,16 +589,16 @@ void OverlayWidget::moveToScreen(bool inMove) { .arg(screenList.indexOf(activeWindowScreen))); window()->setScreen(activeWindowScreen); DEBUG_LOG(("Viewer Pos: New actual screen: %1") - .arg(screenList.indexOf(_widget->screen()))); + .arg(screenList.indexOf(_window->screen()))); } updateGeometry(inMove); } void OverlayWidget::updateGeometry(bool inMove) { - if (Platform::IsWayland()) { + if (Platform::IsWayland() || Platform::IsWindows() || !_fullscreen) { return; } - const auto available = _widget->screen()->geometry(); + const auto available = _window->screen()->geometry(); const auto openglWidget = _opengl ? static_cast(_widget.get()) : nullptr; @@ -526,11 +612,11 @@ void OverlayWidget::updateGeometry(bool inMove) { const auto mask = useSizeHack ? QRegion(QRect(QPoint(), available.size())) : QRegion(); - if (inMove && use.contains(_widget->geometry())) { + if (inMove && use.contains(_window->geometry())) { return; } - if ((_widget->geometry() == use) - && (!possibleSizeHack || _widget->mask() == mask)) { + if ((_window->geometry() == use) + && (!possibleSizeHack || _window->mask() == mask)) { return; } DEBUG_LOG(("Viewer Pos: Setting %1, %2, %3, %4") @@ -538,19 +624,21 @@ void OverlayWidget::updateGeometry(bool inMove) { .arg(use.y()) .arg(use.width()) .arg(use.height())); - _widget->setGeometry(use); + _window->setGeometry(use); if (possibleSizeHack) { - _widget->setMask(mask); + _window->setMask(mask); } } void OverlayWidget::updateControlsGeometry() { - auto navSkip = 2 * st::mediaviewControlMargin + st::mediaviewControlSize; - _closeNav = QRect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, st::mediaviewControlMargin, st::mediaviewControlSize, st::mediaviewControlSize); + const auto navSkip = _supportWindowMode + ? st::mediaviewHeaderTop + : st::mediaviewControlSize; + _closeNav = QRect(width() - st::mediaviewControlSize, 0, st::mediaviewControlSize, st::mediaviewControlSize); _closeNavIcon = style::centerrect(_closeNav, st::mediaviewClose); - _leftNav = QRect(st::mediaviewControlMargin, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); + _leftNav = QRect(0, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); _leftNavIcon = style::centerrect(_leftNav, st::mediaviewLeft); - _rightNav = QRect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); + _rightNav = QRect(width() - st::mediaviewControlSize, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); _rightNavIcon = style::centerrect(_rightNav, st::mediaviewRight); _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); @@ -1502,7 +1590,21 @@ void OverlayWidget::showSaveMsgFile() { } void OverlayWidget::close() { - Core::App().hideMediaView(); + if (isHidden()) { + return; + } + hide(); + if (const auto window = Core::App().activeWindow()) { + window->reActivate(); + } +} + +void OverlayWidget::toggleFullScreen(bool fullscreen) { + if (fullscreen) { + _window->showFullScreen(); + } else { + _window->showNormal(); + } } void OverlayWidget::activateControls() { @@ -1573,7 +1675,7 @@ void OverlayWidget::handleScreenChanged(QScreen *screen) { void OverlayWidget::subscribeToScreenGeometry() { _screenGeometryLifetime.destroy(); - const auto screen = _widget->screen(); + const auto screen = _window->screen(); if (!screen) { return; } @@ -1595,13 +1697,13 @@ void OverlayWidget::toMessage() { } void OverlayWidget::notifyFileDialogShown(bool shown) { - if (shown && isHidden()) { + if (!_fullscreen || (shown && isHidden())) { return; } if (shown) { - Ui::Platform::BringToBack(_widget); + Ui::Platform::BringToBack(_window); } else { - Ui::Platform::ShowOverAll(_widget); + Ui::Platform::ShowOverAll(_window); } } @@ -1673,7 +1775,7 @@ void OverlayWidget::saveAs() { const auto photo = _photo; auto filter = u"Video Files (*.mp4);;"_q + FileDialog::AllFilesFilter(); FileDialog::GetWritePath( - _widget.get(), + _window.get(), tr::lng_save_video(tr::now), filter, filedialogDefaultName( @@ -1682,7 +1784,7 @@ void OverlayWidget::saveAs() { QString(), false, _photo->date), - crl::guard(_widget, [=](const QString &result) { + crl::guard(_window, [=](const QString &result) { QFile f(result); if (!result.isEmpty() && _photo == photo @@ -1704,7 +1806,7 @@ void OverlayWidget::saveAs() { const auto filter = u"JPEG Image (*.jpg);;"_q + FileDialog::AllFilesFilter(); FileDialog::GetWritePath( - _widget.get(), + _window.get(), tr::lng_save_photo(tr::now), filter, filedialogDefaultName( @@ -1713,7 +1815,7 @@ void OverlayWidget::saveAs() { QString(), false, _photo->date), - crl::guard(_widget, [=](const QString &result) { + crl::guard(_window, [=](const QString &result) { if (!result.isEmpty() && _photo == photo) { media->saveToFile(result); } @@ -1851,7 +1953,9 @@ void OverlayWidget::showInFolder() { auto filepath = _document->filepath(true); if (!filepath.isEmpty()) { File::ShowInFolder(filepath); - close(); + if (!_windowed) { + close(); + } } } @@ -1867,7 +1971,9 @@ void OverlayWidget::forwardMedia() { ? _message->fullId() : FullMsgId(); if (id) { - close(); + if (!_windowed) { + close(); + } Window::ShowForwardMessagesBox(active.front(), { 1, id }); } } @@ -1921,7 +2027,9 @@ void OverlayWidget::showMediaOverview() { } update(); if (const auto overviewType = computeOverviewType()) { - close(); + if (!_windowed) { + close(); + } if (SharedMediaOverviewType(*overviewType)) { if (const auto window = findWindow()) { const auto topic = _topicRootId @@ -1983,7 +2091,9 @@ void OverlayWidget::showAttachedStickers() { } else { return; } - close(); + if (!_windowed) { + close(); + } } auto OverlayWidget::sharedMediaType() const @@ -2425,7 +2535,7 @@ void OverlayWidget::clearControlsState() { } not_null OverlayWidget::window() const { - return _widget->windowHandle(); + return _window->windowHandle(); } int OverlayWidget::width() const { @@ -2445,7 +2555,15 @@ void OverlayWidget::update(const QRegion ®ion) { } bool OverlayWidget::isHidden() const { - return _widget->isHidden(); + return _window->isHidden(); +} + +bool OverlayWidget::isMinimized() const { + return _window->windowHandle()->windowState() == Qt::WindowMinimized; +} + +bool OverlayWidget::isFullScreen() const { + return _fullscreen; } not_null OverlayWidget::widget() const { @@ -2455,7 +2573,7 @@ not_null OverlayWidget::widget() const { void OverlayWidget::hide() { clearBeforeHide(); applyHideWindowWorkaround(); - _widget->hide(); + _window->hide(); } void OverlayWidget::setCursor(style::cursor cursor) { @@ -2467,9 +2585,9 @@ void OverlayWidget::setFocus() { } void OverlayWidget::activate() { - _widget->raise(); - _widget->activateWindow(); - QApplication::setActiveWindow(_widget); + _window->raise(); + _window->activateWindow(); + QApplication::setActiveWindow(_window); setFocus(); } @@ -2524,7 +2642,7 @@ void OverlayWidget::show(OpenRequest request) { } } if (const auto controller = request.controller()) { - _window = base::make_weak(&controller->window()); + _openedFrom = base::make_weak(&controller->window()); } } @@ -2758,17 +2876,32 @@ void OverlayWidget::displayFinished() { //OverlayParent::setVisibleHook(true); //OverlayParent::setVisibleHook(false); //setAttribute(Qt::WA_DontShowOnScreen, false); - Ui::Platform::UpdateOverlayed(_widget); - if constexpr (!Platform::IsMac()) { - _widget->showFullScreen(); - } else { - _widget->show(); - } - Ui::Platform::ShowOverAll(_widget); + //Ui::Platform::UpdateOverlayed(_window); + showAndActivate(); + } else if (isMinimized()) { + showAndActivate(); + } else { activate(); } } +void OverlayWidget::showAndActivate() { + _body->show(); + if constexpr (Platform::IsMac()) { + _window->show(); + } else if (_windowed) { + _window->showNormal(); + } else if (_fullscreen) { + _window->showFullScreen(); + } else { + _window->showMaximized(); + } + if (_fullscreen) { + Ui::Platform::ShowOverAll(_window); + } + activate(); +} + bool OverlayWidget::canInitStreaming() const { return (_document && _documentMedia->canBePlayed(_message)) || (_photo && _photo->videoCanBePlayed()); @@ -2920,14 +3053,14 @@ bool OverlayWidget::createStreamingObjects() { _streamed = std::make_unique( _document, fileOrigin(), - _widget, + _body, static_cast(this), [=] { waitingAnimationCallback(); }); } else { _streamed = std::make_unique( _photo, fileOrigin(), - _widget, + _body, static_cast(this), [=] { waitingAnimationCallback(); }); } @@ -3091,7 +3224,7 @@ void OverlayWidget::initThemePreview() { _themePreview = std::move(result); if (_themePreview) { _themeApply.create( - _widget, + _body, tr::lng_theme_preview_apply(), st::themePreviewApplyButton); _themeApply->show(); @@ -3107,14 +3240,14 @@ void OverlayWidget::initThemePreview() { } }); _themeCancel.create( - _widget, + _body, tr::lng_cancel(), st::themePreviewCancelButton); _themeCancel->show(); _themeCancel->setClickedCallback([this] { close(); }); if (const auto slug = _themeCloudData.slug; !slug.isEmpty()) { _themeShare.create( - _widget, + _body, tr::lng_theme_share(), st::themePreviewCancelButton); _themeShare->show(); @@ -3122,7 +3255,7 @@ void OverlayWidget::initThemePreview() { QGuiApplication::clipboard()->setText( session->createInternalLinkFull("addtheme/" + slug)); Ui::Toast::Show( - _widget, + _body, tr::lng_background_link_copied(tr::now)); }); } else { @@ -3367,7 +3500,7 @@ void OverlayWidget::switchToPip() { }; _showAsPip = true; _pip = std::make_unique( - _widget, + _window, document, _streamed->instance.shared(), closeAndContinue, @@ -3508,21 +3641,14 @@ void OverlayWidget::validatePhotoCurrentImage() { } Ui::GL::ChosenRenderer OverlayWidget::chooseRenderer( - Ui::GL::Capabilities capabilities) { - const auto use = Platform::IsMac() - ? true - : capabilities.transparency; - LOG(("OpenGL: %1 (OverlayWidget)").arg(Logs::b(use))); - if (use) { - _opengl = true; - return { - .renderer = std::make_unique(this), - .backend = Ui::GL::Backend::OpenGL, - }; - } + Ui::GL::Backend backend) { + _opengl = (backend == Ui::GL::Backend::OpenGL); return { - .renderer = std::make_unique(this), - .backend = Ui::GL::Backend::Raster, + .renderer = (_opengl + ? std::unique_ptr( + std::make_unique(this)) + : std::make_unique(this)), + .backend = backend, }; } @@ -3838,7 +3964,7 @@ void OverlayWidget::paintControls( st::mediaviewRight }, { OverClose, - true, + !_supportWindowMode, _closeNav, _closeNavIcon, st::mediaviewClose }, @@ -4243,7 +4369,7 @@ void OverlayWidget::setSession(not_null session) { clearSession(); _session = session; - _widget->setWindowIcon(Window::CreateIcon(session)); + _window->setWindowIcon(Window::CreateIcon(session)); session->downloaderTaskFinished( ) | rpl::start_with_next([=] { @@ -4545,7 +4671,7 @@ void OverlayWidget::updateOver(QPoint pos) { updateOverState(OverIcon); } else if (_moreNav.contains(pos)) { updateOverState(OverMore); - } else if (_closeNav.contains(pos)) { + } else if (!_supportWindowMode && _closeNav.contains(pos)) { updateOverState(OverClose); } else if (documentContentShown() && finalContentRect().contains(pos)) { if ((_document->isVideoFile() || _document->isVideoMessage()) && _streamed) { @@ -4585,9 +4711,12 @@ void OverlayWidget::handleMouseRelease( if (_over == OverName && _down == OverName) { if (_from) { - close(); + if (!_windowed) { + close(); + } if (const auto window = findWindow(true)) { window->showPeerInfo(_from); + window->window().activate(); } } } else if (_over == OverDate && _down == OverDate) { @@ -4618,8 +4747,9 @@ void OverlayWidget::handleMouseRelease( } _dragging = 0; setCursor(style::cur_default); - } else if ((position - _lastAction).manhattanLength() - >= st::mediaviewDeltaFromLastAction) { + } else if (!_windowed + && (position - _lastAction).manhattanLength() + >= st::mediaviewDeltaFromLastAction) { if (_themePreviewShown) { if (!_themePreviewRect.contains(position)) { close(); @@ -4644,7 +4774,7 @@ bool OverlayWidget::handleContextMenu(std::optional position) { return false; } _menu = base::make_unique_q( - _widget, + _window, st::mediaviewPopupMenu); fillContextMenuActions([&]( const QString &text, @@ -4671,8 +4801,8 @@ bool OverlayWidget::handleTouchEvent(not_null e) { return false; } else if (e->type() == QEvent::TouchBegin && !e->touchPoints().isEmpty() - && _widget->childAt( - _widget->mapFromGlobal( + && _body->childAt( + _body->mapFromGlobal( e->touchPoints().cbegin()->screenPos().toPoint()))) { return false; } @@ -4774,9 +4904,9 @@ bool OverlayWidget::filterApplicationEvent( || type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease) { if (object->isWidgetType() - && _widget->isAncestorOf(static_cast(object.get()))) { + && static_cast(object.get())->window() == _window) { const auto mouseEvent = static_cast(e.get()); - const auto mousePosition = _widget->mapFromGlobal( + const auto mousePosition = _body->mapFromGlobal( mouseEvent->globalPos()); const auto delta = (mousePosition - _lastMouseMovePos); auto activate = delta.manhattanLength() @@ -4803,10 +4933,10 @@ void OverlayWidget::applyHideWindowWorkaround() { // QOpenGLWidget can't properly destroy a child widget if it is hidden // exactly after that, the child is cached in the backing store. // So on next paint we force full backing store repaint. - if (_opengl && !isHidden() && !_hideWorkaround) { - _hideWorkaround = std::make_unique(_widget); + if (!isHidden() && !_hideWorkaround) { + _hideWorkaround = std::make_unique(_window); const auto raw = _hideWorkaround.get(); - raw->setGeometry(_widget->rect()); + raw->setGeometry(_window->rect()); raw->show(); raw->paintRequest( ) | rpl::start_with_next([=] { @@ -4821,7 +4951,7 @@ void OverlayWidget::applyHideWindowWorkaround() { raw->update(); if (Platform::IsWindows()) { - Ui::Platform::UpdateOverlayed(_widget); + Ui::Platform::UpdateOverlayed(_window); } } } @@ -4831,7 +4961,7 @@ Window::SessionController *OverlayWidget::findWindow(bool switchTo) const { return nullptr; } - const auto window = _window.get(); + const auto window = _openedFrom.get(); if (window) { if (const auto controller = window->sessionController()) { if (&controller->session() == _session) { @@ -4882,14 +5012,10 @@ void OverlayWidget::clearBeforeHide() { } _controlsHideTimer.cancel(); _controlsState = ControlsShown; - _controlsOpacity = anim::value(1, 1); + _controlsOpacity = anim::value(1); _groupThumbs = nullptr; _groupThumbsRect = QRect(); - for (const auto child : _widget->children()) { - if (child->isWidgetType() && _hideWorkaround.get() != child) { - static_cast(child)->hide(); - } - } + _body->hide(); } void OverlayWidget::clearAfterHide() { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 5df8b584c..5fc68be69 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -31,12 +31,19 @@ namespace Ui { class PopupMenu; class LinkButton; class RoundButton; -namespace GL { -struct ChosenRenderer; -struct Capabilities; -} // namespace GL +class RpWindow; } // namespace Ui +namespace Ui::GL { +class Window; +struct ChosenRenderer; +enum class Backend; +} // namespace Ui::GL + +namespace Ui::Platform { +struct SeparateTitleControls; +} // namespace Ui::Platform + namespace Window { namespace Theme { struct Preview; @@ -74,6 +81,8 @@ public: }; [[nodiscard]] bool isHidden() const; + [[nodiscard]] bool isMinimized() const; + [[nodiscard]] bool isFullScreen() const; [[nodiscard]] not_null widget() const; void hide(); void setCursor(style::cursor cursor); @@ -93,6 +102,7 @@ public: void activateControls(); void close(); + void toggleFullScreen(bool fullscreen); void notifyFileDialogShown(bool shown); @@ -161,9 +171,12 @@ private: void update(const QRegion ®ion); [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( - Ui::GL::Capabilities capabilities); + Ui::GL::Backend backend); void paint(not_null renderer); + void setupWindow(); + void orderWidgets(); + void showAndActivate(); void handleMousePress(QPoint position, Qt::MouseButton button); void handleMouseRelease(QPoint position, Qt::MouseButton button); void handleMouseMove(QPoint position); @@ -438,11 +451,20 @@ private: Window::SessionController *findWindow(bool switchTo = true) const; + const bool _supportWindowMode = false; bool _opengl = false; + const std::unique_ptr _wrap; + const not_null _window; +#ifndef Q_OS_MAC + const std::unique_ptr _controls; +#endif + const not_null _body; const std::unique_ptr _surface; const not_null _widget; + bool _fullscreen = true; + bool _windowed = false; - base::weak_ptr _window; + base::weak_ptr _openedFrom; Main::Session *_session = nullptr; rpl::lifetime _sessionLifetime; PhotoData *_photo = nullptr; @@ -562,7 +584,7 @@ private: ControlsState _controlsState = ControlsShown; crl::time _controlsAnimStarted = 0; base::Timer _controlsHideTimer; - anim::value _controlsOpacity; + anim::value _controlsOpacity = { 1. }; bool _mousePressed = false; base::unique_qptr _menu;