First version of windowed media viewer on Windows.

This commit is contained in:
John Preston 2023-02-10 21:00:51 +04:00
parent 5c33f0cc5b
commit 7a5c9a6fb8
4 changed files with 288 additions and 138 deletions

View file

@ -596,11 +596,11 @@ bool Application::isActiveForTrayMenu() const {
} }
bool Application::hideMediaView() { bool Application::hideMediaView() {
if (_mediaView && !_mediaView->isHidden()) { if (_mediaView
_mediaView->hide(); && _mediaView->isFullScreen()
if (const auto window = activeWindow()) { && !_mediaView->isMinimized()
window->reActivate(); && !_mediaView->isHidden()) {
} _mediaView->close();
return true; return true;
} }
return false; return false;
@ -1489,7 +1489,10 @@ void Application::windowActivated(not_null<Window::Controller*> window) {
nowSession->updates().updateOnline(); nowSession->updates().updateOnline();
} }
} }
if (_mediaView && !_mediaView->isHidden()) { if (_mediaView
&& !_mediaView->isHidden()
&& !_mediaView->isMinimized()
&& _mediaView->isFullScreen()) {
_mediaView->activate(); _mediaView->activate();
} }
} }

View file

@ -240,7 +240,6 @@ mediaviewTextTop: 24px;
mediaviewIconOpacity: 0.45; mediaviewIconOpacity: 0.45;
mediaviewIconOverOpacity: 1.; mediaviewIconOverOpacity: 1.;
mediaviewControlMargin: 0px;
mediaviewControlSize: 90px; mediaviewControlSize: 90px;
mediaviewIconSize: size(60px, 56px); mediaviewIconSize: size(60px, 56px);

View file

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

View file

@ -31,12 +31,19 @@ namespace Ui {
class PopupMenu; class PopupMenu;
class LinkButton; class LinkButton;
class RoundButton; class RoundButton;
namespace GL { class RpWindow;
struct ChosenRenderer;
struct Capabilities;
} // namespace GL
} // namespace Ui } // 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 Window {
namespace Theme { namespace Theme {
struct Preview; struct Preview;
@ -74,6 +81,8 @@ public:
}; };
[[nodiscard]] bool isHidden() const; [[nodiscard]] bool isHidden() const;
[[nodiscard]] bool isMinimized() const;
[[nodiscard]] bool isFullScreen() const;
[[nodiscard]] not_null<QWidget*> widget() const; [[nodiscard]] not_null<QWidget*> widget() const;
void hide(); void hide();
void setCursor(style::cursor cursor); void setCursor(style::cursor cursor);
@ -93,6 +102,7 @@ public:
void activateControls(); void activateControls();
void close(); void close();
void toggleFullScreen(bool fullscreen);
void notifyFileDialogShown(bool shown); void notifyFileDialogShown(bool shown);
@ -161,9 +171,12 @@ private:
void update(const QRegion &region); void update(const QRegion &region);
[[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer( [[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
Ui::GL::Capabilities capabilities); Ui::GL::Backend backend);
void paint(not_null<Renderer*> renderer); void paint(not_null<Renderer*> renderer);
void setupWindow();
void orderWidgets();
void showAndActivate();
void handleMousePress(QPoint position, Qt::MouseButton button); void handleMousePress(QPoint position, Qt::MouseButton button);
void handleMouseRelease(QPoint position, Qt::MouseButton button); void handleMouseRelease(QPoint position, Qt::MouseButton button);
void handleMouseMove(QPoint position); void handleMouseMove(QPoint position);
@ -438,11 +451,20 @@ private:
Window::SessionController *findWindow(bool switchTo = true) const; Window::SessionController *findWindow(bool switchTo = true) const;
const bool _supportWindowMode = false;
bool _opengl = false; bool _opengl = false;
const std::unique_ptr<Ui::GL::Window> _wrap;
const not_null<Ui::RpWindow*> _window;
#ifndef Q_OS_MAC
const std::unique_ptr<Ui::Platform::SeparateTitleControls> _controls;
#endif
const not_null<Ui::RpWidget*> _body;
const std::unique_ptr<Ui::RpWidgetWrap> _surface; const std::unique_ptr<Ui::RpWidgetWrap> _surface;
const not_null<QWidget*> _widget; const not_null<QWidget*> _widget;
bool _fullscreen = true;
bool _windowed = false;
base::weak_ptr<Window::Controller> _window; base::weak_ptr<Window::Controller> _openedFrom;
Main::Session *_session = nullptr; Main::Session *_session = nullptr;
rpl::lifetime _sessionLifetime; rpl::lifetime _sessionLifetime;
PhotoData *_photo = nullptr; PhotoData *_photo = nullptr;
@ -562,7 +584,7 @@ private:
ControlsState _controlsState = ControlsShown; ControlsState _controlsState = ControlsShown;
crl::time _controlsAnimStarted = 0; crl::time _controlsAnimStarted = 0;
base::Timer _controlsHideTimer; base::Timer _controlsHideTimer;
anim::value _controlsOpacity; anim::value _controlsOpacity = { 1. };
bool _mousePressed = false; bool _mousePressed = false;
base::unique_qptr<Ui::PopupMenu> _menu; base::unique_qptr<Ui::PopupMenu> _menu;