diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index ecd0852da..21eb25dc3 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -107,7 +107,7 @@ Ui::GL::ChosenRenderer Panel::Incoming::chooseRenderer( } void paintFallback( - QPainter &&p, + Painter &&p, const QRegion &clip, Ui::GL::Backend backend) override { _owner->paint( @@ -121,11 +121,15 @@ Ui::GL::ChosenRenderer Panel::Incoming::chooseRenderer( }; + const auto use = Platform::IsMac() + ? true + : Platform::IsWindows() + ? capabilities.supported + : capabilities.transparency; + LOG(("OpenGL: %1 (Incoming)").arg(Logs::b(use))); return { .renderer = std::make_unique(this), - .backend = (capabilities.supported - ? Ui::GL::Backend::OpenGL - : Ui::GL::Backend::Raster), + .backend = (use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster), }; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp b/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp index 72cec93de..6f3d1fa94 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_large_video.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_common.h" #include "calls/group/calls_group_members_row.h" #include "media/view/media_view_pip.h" +#include "base/platform/base_platform_info.h" #include "webrtc/webrtc_video_track.h" #include "ui/painter.h" #include "ui/abstract_button.h" @@ -87,10 +88,11 @@ Ui::GL::ChosenRenderer LargeVideo::chooseRenderer( } void paintFallback( - QPainter &&p, + Painter &&p, const QRegion &clip, Ui::GL::Backend backend) override { _owner->paint( + p, clip.boundingRect(), backend == Ui::GL::Backend::OpenGL); } @@ -100,11 +102,15 @@ Ui::GL::ChosenRenderer LargeVideo::chooseRenderer( }; + const auto use = Platform::IsMac() + ? true + : Platform::IsWindows() + ? capabilities.supported + : capabilities.transparency; + LOG(("OpenGL: %1 (LargeVideo)").arg(Logs::b(use))); return { .renderer = std::make_unique(this), - .backend = (capabilities.supported - ? Ui::GL::Backend::OpenGL - : Ui::GL::Backend::Raster), + .backend = (use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster), }; } @@ -292,8 +298,7 @@ void LargeVideo::updateControlsGeometry() { } } -void LargeVideo::paint(QRect clip, bool opengl) { - auto p = Painter(widget()); +void LargeVideo::paint(Painter &p, QRect clip, bool opengl) { const auto fill = [&](QRect rect) { if (rect.intersects(clip)) { p.fillRect(rect.intersected(clip), st::groupCallMembersBg); diff --git a/Telegram/SourceFiles/calls/group/calls_group_large_video.h b/Telegram/SourceFiles/calls/group/calls_group_large_video.h index 997719582..48c51d457 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_large_video.h +++ b/Telegram/SourceFiles/calls/group/calls_group_large_video.h @@ -87,7 +87,7 @@ private: rpl::producer track, rpl::producer pinned); void setupControls(rpl::producer pinned); - void paint(QRect clip, bool opengl); + void paint(Painter &p, QRect clip, bool opengl); void paintControls(Painter &p, QRect clip); void updateControlsGeometry(); void togglePinShown(bool shown); diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 6c844bfd7..e35b78cbb 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -368,8 +368,6 @@ void Application::showPhoto(not_null photo, HistoryItem *item) { Expects(_mediaView != nullptr); _mediaView->showPhoto(photo, item); - _mediaView->activateWindow(); - _mediaView->setFocus(); } void Application::showPhoto( @@ -378,8 +376,6 @@ void Application::showPhoto( Expects(_mediaView != nullptr); _mediaView->showPhoto(photo, peer); - _mediaView->activateWindow(); - _mediaView->setFocus(); } void Application::showDocument(not_null document, HistoryItem *item) { @@ -391,8 +387,6 @@ void Application::showDocument(not_null document, HistoryItem *it File::Launch(document->location(false).fname); } else { _mediaView->showDocument(document, item); - _mediaView->activateWindow(); - _mediaView->setFocus(); } } @@ -402,8 +396,6 @@ void Application::showTheme( Expects(_mediaView != nullptr); _mediaView->showTheme(document, cloud); - _mediaView->activateWindow(); - _mediaView->setFocus(); } PeerData *Application::ui_getPeerForMouseAction() { @@ -976,7 +968,7 @@ bool Application::minimizeActiveWindow() { } QWidget *Application::getFileDialogParent() { - return (_mediaView && _mediaView->isVisible()) + return (_mediaView && !_mediaView->isHidden()) ? (QWidget*)_mediaView.get() : activeWindow() ? (QWidget*)activeWindow()->widget() @@ -991,9 +983,7 @@ void Application::notifyFileDialogShown(bool shown) { void Application::checkMediaViewActivation() { if (_mediaView && !_mediaView->isHidden()) { - _mediaView->activateWindow(); - QApplication::setActiveWindow(_mediaView.get()); - _mediaView->setFocus(); + _mediaView->activate(); } } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 7062f08e0..56ee41576 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/item_text_options.h" #include "ui/ui_utility.h" #include "ui/cached_round_corners.h" +#include "ui/gl/gl_surface.h" #include "boxes/confirm_box.h" #include "media/audio/media_audio.h" #include "media/view/media_view_playback_controls.h" @@ -54,6 +55,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/openssl_help.h" #include "base/unixtime.h" #include "base/qt_signal_producer.h" +#include "base/event_filter.h" #include "main/main_account.h" #include "main/main_domain.h" // Domain::activeSessionValue. #include "main/main_session.h" @@ -199,7 +201,6 @@ void PaintImageProfile(QPainter &p, const QImage &image, QRect rect, QRect fill) } QPixmap PrepareStaticImage(QImage image) { -#if defined Q_OS_MAC && !defined OS_MAC_OLD if (image.width() > kMaxDisplayImageSize || image.height() > kMaxDisplayImageSize) { image = image.scaled( @@ -208,7 +209,6 @@ QPixmap PrepareStaticImage(QImage image) { Qt::KeepAspectRatio, Qt::SmoothTransformation); } -#endif // Q_OS_MAC && !OS_MAC_OLD return App::pixmapFromImageInPlace(std::move(image)); } @@ -249,13 +249,13 @@ struct OverlayWidget::Streamed { Streamed( not_null document, Data::FileOrigin origin, - QWidget *controlsParent, + not_null controlsParent, not_null controlsDelegate, Fn waitingCallback); Streamed( not_null photo, Data::FileOrigin origin, - QWidget *controlsParent, + not_null controlsParent, not_null controlsDelegate, Fn waitingCallback); @@ -288,7 +288,7 @@ struct OverlayWidget::PipWrap { OverlayWidget::Streamed::Streamed( not_null document, Data::FileOrigin origin, - QWidget *controlsParent, + not_null controlsParent, not_null controlsDelegate, Fn waitingCallback) : instance(document, origin, std::move(waitingCallback)) @@ -298,7 +298,7 @@ OverlayWidget::Streamed::Streamed( OverlayWidget::Streamed::Streamed( not_null photo, Data::FileOrigin origin, - QWidget *controlsParent, + not_null controlsParent, not_null controlsDelegate, Fn waitingCallback) : instance(photo, origin, std::move(waitingCallback)) @@ -323,15 +323,20 @@ OverlayWidget::PipWrap::PipWrap( } OverlayWidget::OverlayWidget() -: OverlayParent(nullptr) +: _surface(Ui::GL::CreateSurface( + nullptr, // No parent for the window in Qt parent-child sense. + [=](Ui::GL::Capabilities capabilities) { + return chooseRenderer(capabilities); + })) +, _widget(_surface->rpWidget()) , _transparentBrush(style::transparentPlaceholderBrush()) -, _docDownload(this, tr::lng_media_download(tr::now), st::mediaviewFileLink) -, _docSaveAs(this, tr::lng_mediaview_save_as(tr::now), st::mediaviewFileLink) -, _docCancel(this, tr::lng_cancel(tr::now), st::mediaviewFileLink) +, _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) , _radial([=](crl::time now) { return radialAnimationCallback(now); }) , _lastAction(-st::mediaviewDeltaFromLastAction, -st::mediaviewDeltaFromLastAction) , _stateAnimation([=](crl::time now) { return stateAnimationCallback(now); }) -, _dropdown(this, st::mediaviewDropdownMenu) { +, _dropdown(_widget, st::mediaviewDropdownMenu) { Lang::Updated( ) | rpl::start_with_next([=] { refreshLang(); @@ -341,7 +346,7 @@ OverlayWidget::OverlayWidget() ? Core::App().settings().videoVolume() : Core::Settings::kDefaultVolume; - setWindowTitle(qsl("Media viewer")); + _widget->setWindowTitle(qsl("Media viewer")); const auto text = tr::lng_mediaview_saved_to( tr::now, @@ -353,45 +358,106 @@ OverlayWidget::OverlayWidget() _saveMsgText.setMarkedText(st::mediaviewSaveMsgStyle, text, Ui::DialogTextOptions()); _saveMsg = QRect(0, 0, _saveMsgText.maxWidth() + st::mediaviewSaveMsgPadding.left() + st::mediaviewSaveMsgPadding.right(), st::mediaviewSaveMsgStyle.font->height + st::mediaviewSaveMsgPadding.top() + st::mediaviewSaveMsgPadding.bottom()); + _surface->shownValue( + ) | rpl::start_with_next([=](bool shown) { + toggleApplicationEventFilter(shown); + if (shown) { + const auto screenList = QGuiApplication::screens(); + DEBUG_LOG(("Viewer Pos: Shown, screen number: %1") + .arg(screenList.indexOf(window()->screen()))); + moveToScreen(); + } else { + clearAfterHide(); + } + }, lifetime()); + + base::install_event_filter(_widget, [=](not_null e) { + const auto type = e->type(); + if (type == QEvent::Move) { + const auto position = static_cast(e.get())->pos(); + DEBUG_LOG(("Viewer Pos: Moved to %1, %2") + .arg(position.x()) + .arg(position.y())); + } else 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())); + updateControlsGeometry(); + } else if (type == QEvent::MouseButtonPress) { + handleMousePress( + static_cast(e.get())->pos(), + static_cast(e.get())->button()); + } else if (type == QEvent::MouseButtonRelease) { + handleMouseRelease( + static_cast(e.get())->pos(), + static_cast(e.get())->button()); + } else if (type == QEvent::MouseMove) { + handleMouseMove(static_cast(e.get())->pos()); + } 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); + const auto position = mouse + ? std::make_optional(event->pos()) + : std::nullopt; + if (handleContextMenu(position)) { + return base::EventFilterResult::Cancel; + } + } else if (type == QEvent::MouseButtonDblClick) { + const auto position = static_cast(e.get())->pos(); + if (handleDoubleClick(position)) { + return base::EventFilterResult::Cancel; + } + } else if (type == QEvent::UpdateRequest) { + _wasRepainted = true; + } else if (type == QEvent::TouchBegin + || type == QEvent::TouchUpdate + || type == QEvent::TouchEnd + || type == QEvent::TouchCancel) { + if (handleTouchEvent(static_cast(e.get()))) { + return base::EventFilterResult::Cancel;; + } + } else if (type == QEvent::Wheel) { + handleWheelEvent(static_cast(e.get())); + } + return base::EventFilterResult::Continue; + }); + if (Platform::IsLinux()) { - setWindowFlags(Qt::FramelessWindowHint + _widget->setWindowFlags(Qt::FramelessWindowHint | Qt::MaximizeUsingFullscreenGeometryHint); } else if (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. - setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); + _widget->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); } else { - setWindowFlags(Qt::FramelessWindowHint); + _widget->setWindowFlags(Qt::FramelessWindowHint); } - updateGeometry(); - updateControlsGeometry(); - setAttribute(Qt::WA_NoSystemBackground, true); - setAttribute(Qt::WA_TranslucentBackground, true); - setMouseTracking(true); + _widget->setAttribute(Qt::WA_NoSystemBackground, true); + _widget->setAttribute(Qt::WA_TranslucentBackground, true); + _widget->setMouseTracking(true); hide(); - createWinId(); + _widget->createWinId(); if (Platform::IsLinux()) { - windowHandle()->setTransientParent(App::wnd()->windowHandle()); - setWindowModality(Qt::WindowModal); + window()->setTransientParent(App::wnd()->windowHandle()); + _widget->setWindowModality(Qt::WindowModal); } if (!Platform::IsMac()) { - setWindowState(Qt::WindowFullScreen); + _widget->setWindowState(Qt::WindowFullScreen); } - connect( - windowHandle(), - &QWindow::visibleChanged, - this, - [=](bool visible) { handleVisibleChanged(visible); }); - connect( - windowHandle(), + QObject::connect( + window(), &QWindow::screenChanged, - this, [=](QScreen *screen) { handleScreenChanged(screen); }); subscribeToScreenGeometry(); + updateGeometry(); + updateControlsGeometry(); #if defined Q_OS_MAC && !defined OS_OSX TouchBar::SetupMediaViewTouchBar( @@ -419,7 +485,7 @@ OverlayWidget::OverlayWidget() _saveMsgUpdater.setCallback([=] { updateImage(); }); - setAttribute(Qt::WA_AcceptTouchEvents); + _widget->setAttribute(Qt::WA_AcceptTouchEvents); _touchTimer.setCallback([=] { handleTouchTimer(); }); _controlsHideTimer.setCallback([=] { hideControls(); }); @@ -433,31 +499,29 @@ OverlayWidget::OverlayWidget() } void OverlayWidget::refreshLang() { - InvokeQueued(this, [this] { updateThemePreviewGeometry(); }); + InvokeQueued(_widget, [=] { updateThemePreviewGeometry(); }); } void OverlayWidget::moveToScreen() { - Expects(windowHandle()); - const auto widgetScreen = [&](auto &&widget) -> QScreen* { if (auto handle = widget ? widget->windowHandle() : nullptr) { return handle->screen(); } return nullptr; }; - const auto window = Core::App().activeWindow() + const auto applicationWindow = Core::App().activeWindow() ? Core::App().activeWindow()->widget().get() : nullptr; - const auto activeWindowScreen = widgetScreen(window); - const auto myScreen = widgetScreen(this); + const auto activeWindowScreen = widgetScreen(applicationWindow); + const auto myScreen = widgetScreen(_widget); if (activeWindowScreen && myScreen != activeWindowScreen) { const auto screenList = QGuiApplication::screens(); DEBUG_LOG(("Viewer Pos: Currently on screen %1, moving to screen %2") .arg(screenList.indexOf(myScreen)) .arg(screenList.indexOf(activeWindowScreen))); - windowHandle()->setScreen(activeWindowScreen); + window()->setScreen(activeWindowScreen); DEBUG_LOG(("Viewer Pos: New actual screen: %1") - .arg(screenList.indexOf(windowHandle()->screen()))); + .arg(screenList.indexOf(window()->screen()))); } updateGeometry(); } @@ -466,19 +530,17 @@ void OverlayWidget::updateGeometry() { if (Platform::IsWayland()) { return; } - const auto window = windowHandle(); - const auto screen = window && window->screen() - ? window->screen() + const auto screen = window()->screen() + ? window()->screen() : QApplication::primaryScreen(); const auto available = screen->geometry(); - const auto useSizeHack = (USE_OPENGL_OVERLAY_WIDGET - && Platform::IsWindows()); + const auto useSizeHack = _opengl && Platform::IsWindows(); const auto use = available.marginsAdded({ 0, 0, 0, 1 }); const auto mask = useSizeHack ? QRegion(QRect(QPoint(), available.size())) : QRegion(); - if ((geometry() == use) - && (!useSizeHack || (window && window->mask() == mask))) { + if ((_widget->geometry() == use) + && (!useSizeHack || window()->mask() == mask)) { return; } DEBUG_LOG(("Viewer Pos: Setting %1, %2, %3, %4") @@ -486,36 +548,19 @@ void OverlayWidget::updateGeometry() { .arg(use.y()) .arg(use.width()) .arg(use.height())); - setGeometry(use); - if (window && useSizeHack) { - window->setMask(mask); + _widget->setGeometry(use); + if (useSizeHack) { + window()->setMask(mask); } } -void OverlayWidget::moveEvent(QMoveEvent *e) { - const auto newPos = e->pos(); - DEBUG_LOG(("Viewer Pos: Moved to %1, %2") - .arg(newPos.x()) - .arg(newPos.y())); - OverlayParent::moveEvent(e); -} - -void OverlayWidget::resizeEvent(QResizeEvent *e) { - const auto newSize = e->size(); - DEBUG_LOG(("Viewer Pos: Resized to %1, %2") - .arg(newSize.width()) - .arg(newSize.height())); - updateControlsGeometry(); - OverlayParent::resizeEvent(e); -} - void OverlayWidget::updateControlsGeometry() { auto navSkip = 2 * st::mediaviewControlMargin + st::mediaviewControlSize; - _closeNav = myrtlrect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, st::mediaviewControlMargin, st::mediaviewControlSize, st::mediaviewControlSize); + _closeNav = QRect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, st::mediaviewControlMargin, st::mediaviewControlSize, st::mediaviewControlSize); _closeNavIcon = style::centerrect(_closeNav, st::mediaviewClose); - _leftNav = myrtlrect(st::mediaviewControlMargin, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); + _leftNav = QRect(st::mediaviewControlMargin, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); _leftNavIcon = style::centerrect(_leftNav, st::mediaviewLeft); - _rightNav = myrtlrect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); + _rightNav = QRect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); _rightNavIcon = style::centerrect(_rightNav, st::mediaviewRight); _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); @@ -626,7 +671,7 @@ void OverlayWidget::documentUpdated(DocumentData *doc) { updateControls(); } else if (_document->loading()) { updateDocSize(); - update(_docRect); + _widget->update(_docRect); } } else if (_streamed) { const auto ready = _documentMedia->loaded() @@ -741,7 +786,7 @@ void OverlayWidget::updateControls() { _saveVisible = contentCanBeSaved(); _rotateVisible = !_themePreviewShown; const auto navRect = [&](int i) { - return myrtlrect(width() - st::mediaviewIconSize.width() * i, + return QRect(width() - st::mediaviewIconSize.width() * i, height() - st::mediaviewIconSize.height(), st::mediaviewIconSize.width(), st::mediaviewIconSize.height()); @@ -769,17 +814,17 @@ void OverlayWidget::updateControls() { _dateText = Ui::FormatDateTime(d, cTimeFormat()); if (!_fromName.isEmpty()) { _fromNameLabel.setText(st::mediaviewTextStyle, _fromName, Ui::NameTextOptions()); - _nameNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromNameLabel.maxWidth(), width() / 3), st::mediaviewFont->height); - _dateNav = myrtlrect(st::mediaviewTextLeft + _nameNav.width() + st::mediaviewTextSkip, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); + _nameNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromNameLabel.maxWidth(), width() / 3), st::mediaviewFont->height); + _dateNav = QRect(st::mediaviewTextLeft + _nameNav.width() + st::mediaviewTextSkip, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); } else { _nameNav = QRect(); - _dateNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); + _dateNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); } updateHeader(); refreshNavVisibility(); resizeCenteredControls(); - updateOver(mapFromGlobal(QCursor::pos())); + updateOver(_widget->mapFromGlobal(QCursor::pos())); update(); } @@ -1260,6 +1305,10 @@ void OverlayWidget::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pr update(QRegion(_saveMsg) + _captionRect); } +rpl::lifetime &OverlayWidget::lifetime() { + return _surface->lifetime(); +} + void OverlayWidget::showSaveMsgFile() { File::ShowInFolder(_saveMsgFilename); } @@ -1310,7 +1359,7 @@ void OverlayWidget::hideControls(bool force) { } if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) return; - _lastMouseMovePos = mapFromGlobal(QCursor::pos()); + _lastMouseMovePos = _widget->mapFromGlobal(QCursor::pos()); _controlsState = ControlsHiding; _controlsAnimStarted = crl::now(); _controlsOpacity.start(0); @@ -1322,7 +1371,7 @@ void OverlayWidget::hideControls(bool force) { void OverlayWidget::dropdownHidden() { setFocus(); _ignoringDropdown = true; - _lastMouseMovePos = mapFromGlobal(QCursor::pos()); + _lastMouseMovePos = _widget->mapFromGlobal(QCursor::pos()); updateOver(_lastMouseMovePos); _ignoringDropdown = false; if (!_controlsHideTimer.isActive()) { @@ -1330,19 +1379,9 @@ void OverlayWidget::dropdownHidden() { } } -void OverlayWidget::handleVisibleChanged(bool visible) { - if (visible) { - const auto screenList = QGuiApplication::screens(); - DEBUG_LOG(("Viewer Pos: Shown, screen number: %1") - .arg(screenList.indexOf(windowHandle()->screen()))); - - moveToScreen(); - } -} - void OverlayWidget::handleScreenChanged(QScreen *screen) { subscribeToScreenGeometry(); - if (!isVisible()) { + if (isHidden()) { return; } @@ -1355,7 +1394,7 @@ void OverlayWidget::handleScreenChanged(QScreen *screen) { void OverlayWidget::subscribeToScreenGeometry() { _screenGeometryLifetime.destroy(); - const auto screen = windowHandle()->screen(); + const auto screen = window()->screen(); if (!screen) { return; } @@ -1382,9 +1421,9 @@ void OverlayWidget::notifyFileDialogShown(bool shown) { return; } if (shown) { - Ui::Platform::BringToBack(this); + Ui::Platform::BringToBack(_widget); } else { - Ui::Platform::ShowOverAll(this); + Ui::Platform::ShowOverAll(_widget); } } @@ -1442,9 +1481,10 @@ void OverlayWidget::saveAs() { } } else if (_photo && _photo->hasVideo()) { if (const auto bytes = _photoMedia->videoContent(); !bytes.isEmpty()) { + const auto photo = _photo; auto filter = qsl("Video Files (*.mp4);;") + FileDialog::AllFilesFilter(); FileDialog::GetWritePath( - this, + _widget.get(), tr::lng_save_video(tr::now), filter, filedialogDefaultName( @@ -1453,7 +1493,7 @@ void OverlayWidget::saveAs() { QString(), false, _photo->date), - crl::guard(this, [=, photo = _photo](const QString &result) { + crl::guard(_widget, [=](const QString &result) { QFile f(result); if (!result.isEmpty() && _photo == photo @@ -1471,9 +1511,10 @@ void OverlayWidget::saveAs() { } const auto image = _photoMedia->image(Data::PhotoSize::Large)->original(); + const auto photo = _photo; auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(); FileDialog::GetWritePath( - this, + _widget.get(), tr::lng_save_photo(tr::now), filter, filedialogDefaultName( @@ -1482,15 +1523,13 @@ void OverlayWidget::saveAs() { QString(), false, _photo->date), - crl::guard(this, [=, photo = _photo](const QString &result) { + crl::guard(_widget, [=](const QString &result) { if (!result.isEmpty() && _photo == photo) { image.save(result, "JPG"); } })); } - activateWindow(); - QApplication::setActiveWindow(this); - setFocus(); + activate(); } void OverlayWidget::handleDocumentClick() { @@ -2141,6 +2180,50 @@ void OverlayWidget::clearControlsState() { } } +not_null OverlayWidget::window() const { + return _widget->windowHandle(); +} + +int OverlayWidget::width() const { + return _widget->width(); +} + +int OverlayWidget::height() const { + return _widget->height(); +} + +void OverlayWidget::update() { + _widget->update(); +} + +void OverlayWidget::update(const QRegion ®ion) { + _widget->update(region); +} + +bool OverlayWidget::isHidden() const { + return _widget->isHidden(); +} + +void OverlayWidget::hide() { + applyHideWindowWorkaround(); + clearBeforeHide(); + _widget->hide(); +} + +void OverlayWidget::setCursor(style::cursor cursor) { + _widget->setCursor(cursor); +} + +void OverlayWidget::setFocus() { + _widget->setFocus(); +} + +void OverlayWidget::activate() { + _widget->activateWindow(); + QApplication::setActiveWindow(_widget); + setFocus(); +} + void OverlayWidget::showPhoto( not_null photo, HistoryItem *context) { @@ -2388,7 +2471,7 @@ void OverlayWidget::displayDocument( // _docSize is updated in updateControls() _docRect = QRect((width() - st::mediaviewFileSize.width()) / 2, (height() - st::mediaviewFileSize.height()) / 2, st::mediaviewFileSize.width(), st::mediaviewFileSize.height()); - _docIconRect = myrtlrect(_docRect.x() + st::mediaviewFilePadding, _docRect.y() + st::mediaviewFilePadding, st::mediaviewFileIconSize, st::mediaviewFileIconSize); + _docIconRect = QRect(_docRect.x() + st::mediaviewFilePadding, _docRect.y() + st::mediaviewFilePadding, st::mediaviewFileIconSize, st::mediaviewFileIconSize); } else if (_themePreviewShown) { updateThemePreviewGeometry(); } else if (!_staticContent.isNull()) { @@ -2443,16 +2526,14 @@ void OverlayWidget::displayFinished() { //OverlayParent::setVisibleHook(true); //OverlayParent::setVisibleHook(false); //setAttribute(Qt::WA_DontShowOnScreen, false); - Ui::Platform::UpdateOverlayed(this); + Ui::Platform::UpdateOverlayed(_widget); if (Platform::IsLinux()) { - showFullScreen(); + _widget->showFullScreen(); } else { - show(); + _widget->show(); } - Ui::Platform::ShowOverAll(this); - activateWindow(); - QApplication::setActiveWindow(this); - setFocus(); + Ui::Platform::ShowOverAll(_widget); + activate(); } } @@ -2605,14 +2686,14 @@ bool OverlayWidget::createStreamingObjects() { _streamed = std::make_unique( _document, fileOrigin(), - this, + _widget, static_cast(this), [=] { waitingAnimationCallback(); }); } else { _streamed = std::make_unique( _photo, fileOrigin(), - this, + _widget, static_cast(this), [=] { waitingAnimationCallback(); }); } @@ -2741,7 +2822,7 @@ void OverlayWidget::initThemePreview() { const auto weakSession = base::make_weak(&_document->session()); const auto path = _document->location().name(); const auto id = _themePreviewId = openssl::RandomValue(); - const auto weak = Ui::MakeWeak(this); + const auto weak = Ui::MakeWeak(_widget); crl::async([=, data = std::move(current)]() mutable { auto preview = GeneratePreview( bytes, @@ -2758,7 +2839,7 @@ void OverlayWidget::initThemePreview() { _themePreview = std::move(result); if (_themePreview) { _themeApply.create( - this, + _widget, tr::lng_theme_preview_apply(), st::themePreviewApplyButton); _themeApply->show(); @@ -2774,14 +2855,14 @@ void OverlayWidget::initThemePreview() { } }); _themeCancel.create( - this, + _widget, tr::lng_cancel(), st::themePreviewCancelButton); _themeCancel->show(); _themeCancel->setClickedCallback([this] { close(); }); if (const auto slug = _themeCloudData.slug; !slug.isEmpty()) { _themeShare.create( - this, + _widget, tr::lng_theme_share(), st::themePreviewCancelButton); _themeShare->show(); @@ -2789,7 +2870,7 @@ void OverlayWidget::initThemePreview() { QGuiApplication::clipboard()->setText( session->createInternalLinkFull("addtheme/" + slug)); Ui::Toast::Show( - this, + _widget, tr::lng_background_link_copied(tr::now)); }); } else { @@ -2991,7 +3072,7 @@ void OverlayWidget::switchToPip() { }; _showAsPip = true; _pip = std::make_unique( - this, + _widget, document, msgId, _streamed->instance.shared(), @@ -3110,24 +3191,51 @@ void OverlayWidget::validatePhotoCurrentImage() { } } -void OverlayWidget::paintEvent(QPaintEvent *e) { - const auto r = e->rect(); - const auto region = e->region(); +Ui::GL::ChosenRenderer OverlayWidget::chooseRenderer( + Ui::GL::Capabilities capabilities) { + class Renderer : public Ui::GL::Renderer { + public: + Renderer(not_null owner) : _owner(owner) { + } + + void paintFallback( + Painter &&p, + const QRegion &clip, + Ui::GL::Backend backend) override { + _owner->paint(p, clip); + } + + private: + const not_null _owner; + + }; + + const auto use = Platform::IsMac() + ? true + : capabilities.transparency; + LOG(("OpenGL: %1 (OverlayWidget)").arg(Logs::b(use))); + _opengl = use; + return { + .renderer = std::make_unique(this), + .backend = (use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster), + }; +} + +void OverlayWidget::paint(Painter &p, const QRegion &clip) { + const auto r = clip.boundingRect(); const auto contentShown = _photo || documentContentShown(); const auto opaqueContentShown = contentShown && (!_document || (!_document->isVideoMessage() && !_document->sticker())); const auto bgRegion = opaqueContentShown - ? (region - contentRect()) - : region; + ? (clip - contentRect()) + : clip; auto ms = crl::now(); - Painter p(this); - bool name = false; - p.setClipRegion(region); + p.setClipRegion(clip); // main bg const auto m = p.compositionMode(); @@ -3229,7 +3337,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { auto o = overLevel(OverLeftNav); if (o > 0) { p.setOpacity(o * co); - for (const auto &rect : region) { + for (const auto &rect : clip) { const auto fill = _leftNav.intersected(rect); if (!fill.isEmpty()) p.fillRect(fill, st::mediaviewControlBg); } @@ -3245,7 +3353,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { auto o = overLevel(OverRightNav); if (o > 0) { p.setOpacity(o * co); - for (const auto &rect : region) { + for (const auto &rect : clip) { const auto fill = _rightNav.intersected(rect); if (!fill.isEmpty()) p.fillRect(fill, st::mediaviewControlBg); } @@ -3261,7 +3369,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { auto o = overLevel(OverClose); if (o > 0) { p.setOpacity(o * co); - for (const auto &rect : region) { + for (const auto &rect : clip) { const auto fill = _closeNav.intersected(rect); if (!fill.isEmpty()) p.fillRect(fill, st::mediaviewControlBg); } @@ -3383,7 +3491,7 @@ void OverlayWidget::paintTransformedVideoFrame(Painter &p) { PainterHighQualityEnabler hq(p); const auto rotation = contentRotation(); - if (UsePainterRotation(rotation, USE_OPENGL_OVERLAY_WIDGET)) { + if (UsePainterRotation(rotation, _opengl)) { if (rotation) { p.save(); p.rotate(rotation); @@ -3413,7 +3521,7 @@ void OverlayWidget::paintTransformedStaticContent(Painter &p) { return; } const auto rotation = contentRotation(); - if (UsePainterRotation(rotation, USE_OPENGL_OVERLAY_WIDGET)) { + if (UsePainterRotation(rotation, _opengl)) { if (rotation) { p.save(); p.rotate(rotation); @@ -3526,7 +3634,7 @@ void OverlayWidget::paintThemePreview(Painter &p, QRect clip) { if (!fill.isEmpty()) { if (_themePreview) { p.drawImage( - myrtlrect(_themePreviewRect).topLeft(), + _themePreviewRect.topLeft(), _themePreview->preview); } else { p.fillRect(fill, st::themePreviewBg); @@ -3582,26 +3690,28 @@ void OverlayWidget::paintThemePreview(Painter &p, QRect clip) { } } -void OverlayWidget::keyPressEvent(QKeyEvent *e) { - const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier); +void OverlayWidget::handleKeyPress(not_null e) { + const auto key = e->key(); + const auto modifiers = e->modifiers(); + const auto ctrl = modifiers.testFlag(Qt::ControlModifier); if (_streamed) { // Ctrl + F for full screen toggle is in eventFilter(). - const auto toggleFull = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) - && (e->modifiers().testFlag(Qt::AltModifier) || ctrl); + const auto toggleFull = (modifiers.testFlag(Qt::AltModifier) || ctrl) + && (key == Qt::Key_Enter || key == Qt::Key_Return); if (toggleFull) { playbackToggleFullScreen(); return; - } else if (e->key() == Qt::Key_Space) { + } else if (key == Qt::Key_Space) { playbackPauseResume(); return; } else if (_fullScreenVideo) { - if (e->key() == Qt::Key_Escape) { + if (key == Qt::Key_Escape) { playbackToggleFullScreen(); } return; } } - if (!_menu && e->key() == Qt::Key_Escape) { + if (!_menu && key == Qt::Key_Escape) { if (_document && _document->loading() && !_streamed) { handleDocumentClick(); } else { @@ -3609,43 +3719,46 @@ void OverlayWidget::keyPressEvent(QKeyEvent *e) { } } else if (e == QKeySequence::Save || e == QKeySequence::SaveAs) { saveAs(); - } else if (e->key() == Qt::Key_Copy || (e->key() == Qt::Key_C && ctrl)) { + } else if (key == Qt::Key_Copy || (key == Qt::Key_C && ctrl)) { copyMedia(); - } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) { + } else if (key == Qt::Key_Enter + || key == Qt::Key_Return + || key == Qt::Key_Space) { if (_streamed) { playbackPauseResume(); - } else if (_document && !_document->loading() && (documentBubbleShown() || !_documentMedia->loaded())) { + } else if (_document + && !_document->loading() + && (documentBubbleShown() || !_documentMedia->loaded())) { handleDocumentClick(); } - } else if (e->key() == Qt::Key_Left) { + } else if (key == Qt::Key_Left) { if (_controlsHideTimer.isActive()) { activateControls(); } moveToNext(-1); - } else if (e->key() == Qt::Key_Right) { + } else if (key == Qt::Key_Right) { if (_controlsHideTimer.isActive()) { activateControls(); } moveToNext(1); } else if (ctrl) { - if (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == Qt::Key_Asterisk || e->key() == ']') { + if (key == Qt::Key_Plus + || key == Qt::Key_Equal + || key == Qt::Key_Asterisk + || key == ']') { zoomIn(); - } else if (e->key() == Qt::Key_Minus || e->key() == Qt::Key_Underscore) { + } else if (key == Qt::Key_Minus || key == Qt::Key_Underscore) { zoomOut(); - } else if (e->key() == Qt::Key_0) { + } else if (key == Qt::Key_0) { zoomReset(); - } else if (e->key() == Qt::Key_I) { + } else if (key == Qt::Key_I) { update(); } } } -void OverlayWidget::wheelEvent(QWheelEvent *e) { -#ifdef OS_MAC_OLD - constexpr auto step = 120; -#else // OS_MAC_OLD - constexpr auto step = static_cast(QWheelEvent::DefaultDeltasPerStep); -#endif // OS_MAC_OLD +void OverlayWidget::handleWheelEvent(not_null e) { + constexpr auto step = int(QWheelEvent::DefaultDeltasPerStep); _verticalWheelDelta += e->angleDelta().y(); while (qAbs(_verticalWheelDelta) >= step) { @@ -3653,23 +3766,15 @@ void OverlayWidget::wheelEvent(QWheelEvent *e) { _verticalWheelDelta += step; if (e->modifiers().testFlag(Qt::ControlModifier)) { zoomOut(); - } else { -#ifndef OS_MAC_OLD - if (e->source() == Qt::MouseEventNotSynthesized) { - moveToNext(1); - } -#endif // OS_MAC_OLD + } else if (e->source() == Qt::MouseEventNotSynthesized) { + moveToNext(1); } } else { _verticalWheelDelta -= step; if (e->modifiers().testFlag(Qt::ControlModifier)) { zoomIn(); - } else { -#ifndef OS_MAC_OLD - if (e->source() == Qt::MouseEventNotSynthesized) { - moveToNext(-1); - } -#endif // OS_MAC_OLD + } else if (e->source() == Qt::MouseEventNotSynthesized) { + moveToNext(-1); } } } @@ -3826,7 +3931,7 @@ void OverlayWidget::setSession(not_null session) { clearSession(); _session = session; - setWindowIcon(Window::CreateIcon(session)); + _widget->setWindowIcon(Window::CreateIcon(session)); session->downloaderTaskFinished( ) | rpl::start_with_next([=] { @@ -3925,21 +4030,23 @@ void OverlayWidget::preloadData(int delta) { _preloadDocuments = std::move(documents); } -void OverlayWidget::mousePressEvent(QMouseEvent *e) { - updateOver(e->pos()); +void OverlayWidget::handleMousePress( + QPoint position, + Qt::MouseButton button) { + updateOver(position); if (_menu || !_receiveMouse) { return; } ClickHandler::pressed(); - if (e->button() == Qt::LeftButton) { + if (button == Qt::LeftButton) { _down = OverNone; if (!ClickHandler::getPressed()) { if (_over == OverLeftNav && moveToNext(-1)) { - _lastAction = e->pos(); + _lastAction = position; } else if (_over == OverRightNav && moveToNext(1)) { - _lastAction = e->pos(); + _lastAction = position; } else if (_over == OverName || _over == OverDate || _over == OverHeader @@ -3950,31 +4057,30 @@ void OverlayWidget::mousePressEvent(QMouseEvent *e) { || _over == OverClose || _over == OverVideo) { _down = _over; - } else if (!_saveMsg.contains(e->pos()) || !_saveMsgStarted) { + } else if (!_saveMsg.contains(position) || !_saveMsgStarted) { _pressed = true; _dragging = 0; updateCursor(); - _mStart = e->pos(); + _mStart = position; _xStart = _x; _yStart = _y; } } - } else if (e->button() == Qt::MiddleButton) { + } else if (button == Qt::MiddleButton) { zoomReset(); } activateControls(); } -void OverlayWidget::mouseDoubleClickEvent(QMouseEvent *e) { - updateOver(e->pos()); +bool OverlayWidget::handleDoubleClick(QPoint position) { + updateOver(position); - if (_over == OverVideo && _streamed) { - playbackToggleFullScreen(); - playbackPauseResume(); - } else { - e->ignore(); - return OverlayParent::mouseDoubleClickEvent(e); + if (_over != OverVideo || !_streamed) { + return false; } + playbackToggleFullScreen(); + playbackPauseResume(); + return true; } void OverlayWidget::snapXY() { @@ -3990,13 +4096,17 @@ void OverlayWidget::snapXY() { if (_y > ymax) _y = ymax; } -void OverlayWidget::mouseMoveEvent(QMouseEvent *e) { - updateOver(e->pos()); - if (_lastAction.x() >= 0 && (e->pos() - _lastAction).manhattanLength() >= st::mediaviewDeltaFromLastAction) { +void OverlayWidget::handleMouseMove(QPoint position) { + updateOver(position); + if (_lastAction.x() >= 0 + && ((position - _lastAction).manhattanLength() + >= st::mediaviewDeltaFromLastAction)) { _lastAction = QPoint(-st::mediaviewDeltaFromLastAction, -st::mediaviewDeltaFromLastAction); } if (_pressed) { - if (!_dragging && (e->pos() - _mStart).manhattanLength() >= QApplication::startDragDistance()) { + if (!_dragging + && ((position - _mStart).manhattanLength() + >= QApplication::startDragDistance())) { _dragging = QRect(_x, _y, _w, _h).contains(_mStart) ? 1 : -1; if (_dragging > 0) { if (_w > width() || _h > height()) { @@ -4007,8 +4117,8 @@ void OverlayWidget::mouseMoveEvent(QMouseEvent *e) { } } if (_dragging > 0) { - _x = _xStart + (e->pos() - _mStart).x(); - _y = _yStart + (e->pos() - _mStart).y(); + _x = _xStart + (position - _mStart).x(); + _y = _yStart + (position - _mStart).y(); snapXY(); update(); } @@ -4137,8 +4247,10 @@ void OverlayWidget::updateOver(QPoint pos) { } } -void OverlayWidget::mouseReleaseEvent(QMouseEvent *e) { - updateOver(e->pos()); +void OverlayWidget::handleMouseRelease( + QPoint position, + Qt::MouseButton button) { + updateOver(position); if (const auto activated = ClickHandler::unpressed()) { if (activated->dragText() == qstr("internal:show_saved_message")) { @@ -4150,7 +4262,7 @@ void OverlayWidget::mouseReleaseEvent(QMouseEvent *e) { if (_session) { Core::App().domain().activate(&_session->account()); } - ActivateClickHandler(this, activated, e->button()); + ActivateClickHandler(_widget, activated, button); return; } @@ -4170,7 +4282,7 @@ void OverlayWidget::mouseReleaseEvent(QMouseEvent *e) { } else if (_over == OverIcon && _down == OverIcon) { handleDocumentClick(); } else if (_over == OverMore && _down == OverMore) { - InvokeQueued(this, [=] { showDropdown(); }); + InvokeQueued(_widget, [=] { showDropdown(); }); } else if (_over == OverClose && _down == OverClose) { close(); } else if (_over == OverVideo && _down == OverVideo) { @@ -4180,22 +4292,23 @@ void OverlayWidget::mouseReleaseEvent(QMouseEvent *e) { } else if (_pressed) { if (_dragging) { if (_dragging > 0) { - _x = _xStart + (e->pos() - _mStart).x(); - _y = _yStart + (e->pos() - _mStart).y(); + _x = _xStart + (position - _mStart).x(); + _y = _yStart + (position - _mStart).y(); snapXY(); update(); } _dragging = 0; setCursor(style::cur_default); - } else if ((e->pos() - _lastAction).manhattanLength() >= st::mediaviewDeltaFromLastAction) { + } else if ((position - _lastAction).manhattanLength() + >= st::mediaviewDeltaFromLastAction) { if (_themePreviewShown) { - if (!_themePreviewRect.contains(e->pos())) { + if (!_themePreviewRect.contains(position)) { close(); } } else if (!_document || documentContentShown() || !documentBubbleShown() - || !_docRect.contains(e->pos())) { + || !_docRect.contains(position)) { close(); } } @@ -4207,29 +4320,41 @@ void OverlayWidget::mouseReleaseEvent(QMouseEvent *e) { } } -void OverlayWidget::contextMenuEvent(QContextMenuEvent *e) { - if (e->reason() != QContextMenuEvent::Mouse || QRect(_x, _y, _w, _h).contains(e->pos())) { - _menu = base::make_unique_q( - this, - st::mediaviewPopupMenu); - fillContextMenuActions([&] (const QString &text, Fn handler) { - _menu->addAction(text, std::move(handler)); - }); - _menu->setDestroyedCallback(crl::guard(this, [=] { - activateControls(); - _receiveMouse = false; - InvokeQueued(this, [=] { receiveMouse(); }); - })); - _menu->popup(e->globalPos()); - e->accept(); - activateControls(); +bool OverlayWidget::handleContextMenu(std::optional position) { + if (position && !QRect(_x, _y, _w, _h).contains(*position)) { + return false; } + _menu = base::make_unique_q( + _widget, + st::mediaviewPopupMenu); + fillContextMenuActions([&] (const QString &text, Fn handler) { + _menu->addAction(text, std::move(handler)); + }); + _menu->setDestroyedCallback(crl::guard(_widget, [=] { + activateControls(); + _receiveMouse = false; + InvokeQueued(_widget, [=] { receiveMouse(); }); + })); + _menu->popup(QCursor::pos()); + activateControls(); + return true; } -void OverlayWidget::touchEvent(QTouchEvent *e) { +bool OverlayWidget::handleTouchEvent(not_null e) { + if (e->device()->type() != QTouchDevice::TouchScreen) { + return false; + } else if (e->type() == QEvent::TouchBegin + && !e->touchPoints().isEmpty() + && _widget->childAt( + _widget->mapFromGlobal( + e->touchPoints().cbegin()->screenPos().toPoint()))) { + return false; + } switch (e->type()) { case QEvent::TouchBegin: { - if (_touchPress || e->touchPoints().isEmpty()) return; + if (_touchPress || e->touchPoints().isEmpty()) { + break; + } _touchTimer.callOnce(QApplication::startDragTime()); _touchPress = true; _touchMove = _touchRightButton = false; @@ -4237,32 +4362,32 @@ void OverlayWidget::touchEvent(QTouchEvent *e) { } break; case QEvent::TouchUpdate: { - if (!_touchPress || e->touchPoints().isEmpty()) return; + if (!_touchPress || e->touchPoints().isEmpty()) { + break; + } if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { _touchMove = true; } } break; case QEvent::TouchEnd: { - if (!_touchPress) return; - auto weak = Ui::MakeWeak(this); + if (!_touchPress) { + break; + } + auto weak = Ui::MakeWeak(_widget); if (!_touchMove) { - Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); - auto mapped = mapFromGlobal(_touchStart); - - QMouseEvent pressEvent(QEvent::MouseButtonPress, mapped, mapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers()); - pressEvent.accept(); - if (weak) mousePressEvent(&pressEvent); - - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, mapped, mapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers()); - if (weak) mouseReleaseEvent(&releaseEvent); + const auto button = _touchRightButton + ? Qt::RightButton + : Qt::LeftButton; + const auto position = _widget->mapFromGlobal(_touchStart); + if (weak) handleMousePress(position, button); + if (weak) handleMouseRelease(position, button); if (weak && _touchRightButton) { - QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); - contextMenuEvent(&contextEvent); + handleContextMenu(position); } } else if (_touchMove) { - if ((!_leftNavVisible || !_leftNav.contains(mapFromGlobal(_touchStart))) && (!_rightNavVisible || !_rightNav.contains(mapFromGlobal(_touchStart)))) { + if ((!_leftNavVisible || !_leftNav.contains(_widget->mapFromGlobal(_touchStart))) && (!_rightNavVisible || !_rightNav.contains(_widget->mapFromGlobal(_touchStart)))) { QPoint d = (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart); if (d.x() * d.x() > d.y() * d.y() && (d.x() > st::mediaviewSwipeDistance || d.x() < -st::mediaviewSwipeDistance)) { moveToNext(d.x() > 0 ? -1 : 1); @@ -4280,54 +4405,56 @@ void OverlayWidget::touchEvent(QTouchEvent *e) { _touchTimer.cancel(); } break; } + return true; } -bool OverlayWidget::eventHook(QEvent *e) { - if (e->type() == QEvent::UpdateRequest) { - _wasRepainted = true; - } else if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { - QTouchEvent *ev = static_cast(e); - if (ev->device()->type() == QTouchDevice::TouchScreen) { - if (ev->type() != QEvent::TouchBegin || ev->touchPoints().isEmpty() || !childAt(mapFromGlobal(ev->touchPoints().cbegin()->screenPos().toPoint()))) { - touchEvent(ev); - return true; - } - } - } else if (e->type() == QEvent::Wheel) { - QWheelEvent *ev = static_cast(e); - if (ev->phase() == Qt::ScrollBegin) { - _accumScroll = ev->angleDelta(); - } else { - _accumScroll += ev->angleDelta(); - if (ev->phase() == Qt::ScrollEnd) { - if (ev->angleDelta().x() != 0) { - if (_accumScroll.x() * _accumScroll.x() > _accumScroll.y() * _accumScroll.y() && _accumScroll.x() != 0) { - moveToNext(_accumScroll.x() > 0 ? -1 : 1); - } - _accumScroll = QPoint(); - } - } - } +void OverlayWidget::toggleApplicationEventFilter(bool install) { + if (!install) { + _applicationEventFilter = nullptr; + return; + } else if (_applicationEventFilter) { + return; } - return OverlayParent::eventHook(e); + class Filter final : public QObject { + public: + explicit Filter(not_null owner) : _owner(owner) { + } + + private: + bool eventFilter(QObject *obj, QEvent *e) override { + return obj && e && _owner->filterApplicationEvent(obj, e); + } + + const not_null _owner; + + }; + + _applicationEventFilter = std::make_unique(this); + qApp->installEventFilter(_applicationEventFilter.get()); } -bool OverlayWidget::eventFilter(QObject *obj, QEvent *e) { - auto type = e->type(); +bool OverlayWidget::filterApplicationEvent( + not_null object, + not_null e) { + const auto type = e->type(); if (type == QEvent::ShortcutOverride) { - const auto keyEvent = static_cast(e); + const auto keyEvent = static_cast(e.get()); const auto ctrl = keyEvent->modifiers().testFlag(Qt::ControlModifier); if (keyEvent->key() == Qt::Key_F && ctrl && _streamed) { playbackToggleFullScreen(); } return true; - } - if ((type == QEvent::MouseMove || type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease) && obj->isWidgetType()) { - if (isAncestorOf(static_cast(obj))) { - const auto mouseEvent = static_cast(e); - const auto mousePosition = mapFromGlobal(mouseEvent->globalPos()); + } else if (type == QEvent::MouseMove + || type == QEvent::MouseButtonPress + || type == QEvent::MouseButtonRelease) { + if (object->isWidgetType() + && _widget->isAncestorOf(static_cast(object.get()))) { + const auto mouseEvent = static_cast(e.get()); + const auto mousePosition = _widget->mapFromGlobal( + mouseEvent->globalPos()); const auto delta = (mousePosition - _lastMouseMovePos); - auto activate = delta.manhattanLength() >= st::mediaviewDeltaFromLastAction; + auto activate = delta.manhattanLength() + >= st::mediaviewDeltaFromLastAction; if (activate) { _lastMouseMovePos = mousePosition; } @@ -4343,7 +4470,7 @@ bool OverlayWidget::eventFilter(QObject *obj, QEvent *e) { } } } - return OverlayParent::eventFilter(obj, e); + return false; } void OverlayWidget::applyHideWindowWorkaround() { @@ -4401,20 +4528,6 @@ void OverlayWidget::clearAfterHide() { _themeShare.destroyDelayed(); } -void OverlayWidget::setVisibleHook(bool visible) { - if (!visible) { - applyHideWindowWorkaround(); - clearBeforeHide(); - } - OverlayParent::setVisibleHook(visible); - if (visible) { - QCoreApplication::instance()->installEventFilter(this); - } else { - QCoreApplication::instance()->removeEventFilter(this); - clearAfterHide(); - } -} - void OverlayWidget::receiveMouse() { _receiveMouse = true; } @@ -4512,7 +4625,7 @@ void OverlayWidget::updateHeader() { hwidth = width() / 3; _headerText = st::mediaviewThickFont->elided(_headerText, hwidth, Qt::ElideMiddle); } - _headerNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewHeaderTop, hwidth, st::mediaviewThickFont->height); + _headerNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewHeaderTop, hwidth, st::mediaviewThickFont->height); } float64 OverlayWidget::overLevel(OverState control) const { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 1484aff1b..39136c879 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -27,6 +27,10 @@ namespace Ui { class PopupMenu; class LinkButton; class RoundButton; +namespace GL { +struct ChosenRenderer; +struct Capabilities; +} // namespace GL } // namespace Ui namespace Window { @@ -52,25 +56,8 @@ namespace View { class GroupThumbs; class Pip; -#if 1 -#define USE_OPENGL_OVERLAY_WIDGET 1 -#else // Q_OS_MAC && !OS_MAC_OLD -#define USE_OPENGL_OVERLAY_WIDGET 0 -#endif // Q_OS_MAC && !OS_MAC_OLD - -struct OverlayParentTraits : Ui::RpWidgetDefaultTraits { - static constexpr bool kSetZeroGeometry = false; -}; - -#if USE_OPENGL_OVERLAY_WIDGET -using OverlayParent = Ui::RpWidgetBase; -#else // USE_OPENGL_OVERLAY_WIDGET -using OverlayParent = Ui::RpWidgetBase; -#endif // USE_OPENGL_OVERLAY_WIDGET - class OverlayWidget final - : public OverlayParent - , public ClickHandlerHost + : public ClickHandlerHost , private PlaybackControls::Delegate { public: OverlayWidget(); @@ -82,6 +69,12 @@ public: None, }; + [[nodiscard]] bool isHidden() const; + void hide(); + void setCursor(style::cursor cursor); + void setFocus(); + void activate(); + void showPhoto(not_null photo, HistoryItem *context); void showPhoto(not_null photo, not_null context); void showDocument( @@ -91,12 +84,14 @@ public: not_null document, const Data::CloudTheme &cloud); - void leaveToChildEvent(QEvent *e, QWidget *child) override { // e -- from enterEvent() of child TWidget - updateOverState(OverNone); - } - void enterFromChildEvent(QEvent *e, QWidget *child) override { // e -- from leaveEvent() of child TWidget - updateOver(mapFromGlobal(QCursor::pos())); - } + //void leaveToChildEvent(QEvent *e, QWidget *child) override { + // // e -- from enterEvent() of child TWidget + // updateOverState(OverNone); + //} + //void enterFromChildEvent(QEvent *e, QWidget *child) override { + // // e -- from leaveEvent() of child TWidget + // updateOver(mapFromGlobal(QCursor::pos())); + //} void activateControls(); void close(); @@ -111,6 +106,8 @@ public: void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; + rpl::lifetime &lifetime(); + private: struct Streamed; struct PipWrap; @@ -142,24 +139,29 @@ private: SaveAs, }; - void paintEvent(QPaintEvent *e) override; - void moveEvent(QMoveEvent *e) override; - void resizeEvent(QResizeEvent *e) override; + [[nodiscard]] not_null window() const; + [[nodiscard]] int width() const; + [[nodiscard]] int height() const; + void update(); + void update(const QRegion ®ion); - void keyPressEvent(QKeyEvent *e) override; - void wheelEvent(QWheelEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseDoubleClickEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void contextMenuEvent(QContextMenuEvent *e) override; - void touchEvent(QTouchEvent *e); + [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( + Ui::GL::Capabilities capabilities); + void paint(Painter &p, const QRegion &clip); - bool eventHook(QEvent *e) override; - bool eventFilter(QObject *obj, QEvent *e) override; - - void setVisibleHook(bool visible) override; + void handleMousePress(QPoint position, Qt::MouseButton button); + void handleMouseRelease(QPoint position, Qt::MouseButton button); + void handleMouseMove(QPoint position); + bool handleContextMenu(std::optional position); + bool handleDoubleClick(QPoint position); + bool handleTouchEvent(not_null e); + void handleWheelEvent(not_null e); + void handleKeyPress(not_null e); + void toggleApplicationEventFilter(bool install); + bool filterApplicationEvent( + not_null object, + not_null e); void setSession(not_null session); void playbackControlsPlay() override; @@ -214,7 +216,6 @@ private: bool moveToNext(int delta); void preloadData(int delta); - void handleVisibleChanged(bool visible); void handleScreenChanged(QScreen *screen); bool contentCanBeSaved() const; @@ -379,6 +380,9 @@ private: void applyHideWindowWorkaround(); + bool _opengl = false; + const std::unique_ptr _surface; + const not_null _widget; QBrush _transparentBrush; Main::Session *_session = nullptr; @@ -435,7 +439,9 @@ private: int32 _dragging = 0; QPixmap _staticContent; bool _blurred = true; + rpl::lifetime _screenGeometryLifetime; + std::unique_ptr _applicationEventFilter; std::unique_ptr _streamed; std::unique_ptr _pip; @@ -509,7 +515,6 @@ private: bool _touchRightButton = false; base::Timer _touchTimer; QPoint _touchStart; - QPoint _accumScroll; QString _saveMsgFilename; crl::time _saveMsgStarted = 0; diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index fad7276cb..fad2347f8 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -391,7 +391,7 @@ Ui::GL::ChosenRenderer PipPanel::chooseRenderer( } void paintFallback( - QPainter &&p, + Painter &&p, const QRegion &clip, Ui::GL::Backend backend) override { _owner->paint( @@ -405,11 +405,13 @@ Ui::GL::ChosenRenderer PipPanel::chooseRenderer( }; + const auto use = Platform::IsMac() + ? true + : capabilities.transparency; + LOG(("OpenGL: %1 (PipPanel)").arg(Logs::b(use))); return { .renderer = std::make_unique(this), - .backend = (capabilities.supported - ? Ui::GL::Backend::OpenGL - : Ui::GL::Backend::Raster), + .backend = (use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster), }; } diff --git a/Telegram/SourceFiles/media/view/media_view_pip.h b/Telegram/SourceFiles/media/view/media_view_pip.h index f0416e6b2..8788690c4 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.h +++ b/Telegram/SourceFiles/media/view/media_view_pip.h @@ -95,8 +95,8 @@ private: [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( Ui::GL::Capabilities capabilities); - std::unique_ptr _content; - QPointer _parent; + const std::unique_ptr _content; + const QPointer _parent; Fn _paint; RectParts _attached = RectParts(); RectParts _snapped = RectParts(); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 95ee92088..ca5b2e674 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 95ee92088e62dfa20eb11d6fe59b0fb1834a1207 +Subproject commit ca5b2e6746447e39fc1e7deb1fa97e28d518bc7f