Initial support of separate windows for accounts.

This commit is contained in:
John Preston 2023-01-17 19:47:58 +04:00
parent 86ed2745e3
commit 7023b013ce
32 changed files with 323 additions and 143 deletions

View file

@ -123,22 +123,18 @@ using UpdatedFileReferences = Data::UpdatedFileReferences;
[[nodiscard]] std::shared_ptr<Window::Show> ShowForPeer( [[nodiscard]] std::shared_ptr<Window::Show> ShowForPeer(
not_null<PeerData*> peer) { not_null<PeerData*> peer) {
const auto separate = Core::App().separateWindowForPeer(peer); return std::make_shared<Window::Show>(Core::App().windowFor(peer));
const auto window = separate ? separate : Core::App().primaryWindow();
return std::make_shared<Window::Show>(window);
} }
void ShowChannelsLimitBox(not_null<PeerData*> peer) { void ShowChannelsLimitBox(not_null<PeerData*> peer) {
const auto primary = Core::App().primaryWindow(); if (const auto window = Core::App().windowFor(peer)) {
if (!primary) { window->invokeForSessionController(
return; &peer->session().account(),
peer,
[&](not_null<Window::SessionController*> controller) {
controller->show(Box(ChannelsLimitBox, &peer->session()));
});
} }
primary->invokeForSessionController(
&peer->session().account(),
peer,
[&](not_null<Window::SessionController*> controller) {
controller->show(Box(ChannelsLimitBox, &peer->session()));
});
} }
} // namespace } // namespace

View file

@ -20,7 +20,7 @@ void showBox(
LayerOptions options, LayerOptions options,
anim::type animated) { anim::type animated) {
const auto window = Core::IsAppLaunched() const auto window = Core::IsAppLaunched()
? Core::App().primaryWindow() ? Core::App().activePrimaryWindow()
: nullptr; : nullptr;
if (window) { if (window) {
window->show(std::move(content), options, animated); window->show(std::move(content), options, animated);
@ -31,7 +31,7 @@ void showBox(
void hideLayer(anim::type animated) { void hideLayer(anim::type animated) {
const auto window = Core::IsAppLaunched() const auto window = Core::IsAppLaunched()
? Core::App().primaryWindow() ? Core::App().activePrimaryWindow()
: nullptr; : nullptr;
if (window) { if (window) {
window->hideLayer(animated); window->hideLayer(animated);
@ -40,7 +40,7 @@ void hideLayer(anim::type animated) {
bool isLayerShown() { bool isLayerShown() {
const auto window = Core::IsAppLaunched() const auto window = Core::IsAppLaunched()
? Core::App().primaryWindow() ? Core::App().activePrimaryWindow()
: nullptr; : nullptr;
return window && window->isLayerShown(); return window && window->isLayerShown();
} }

View file

@ -69,10 +69,11 @@ void ChangeFilterById(
MTP_flags(MTPmessages_UpdateDialogFilter::Flag::f_filter), MTP_flags(MTPmessages_UpdateDialogFilter::Flag::f_filter),
MTP_int(filter.id()), MTP_int(filter.id()),
filter.tl() filter.tl()
)).done([=, chat = history->peer->name(), name = filter.title()]{ )).done([=, chat = history->peer->name(), name = filter.title()] {
// Since only the primary window has dialogs list, // Since only the primary window has dialogs list,
// We can safely show toast there. // We can safely show toast there.
if (const auto controller = Core::App().primaryWindow()) { const auto account = &history->session().account();
if (const auto controller = Core::App().windowFor(account)) {
auto text = (add auto text = (add
? tr::lng_filters_toast_add ? tr::lng_filters_toast_add
: tr::lng_filters_toast_remove)( : tr::lng_filters_toast_remove)(

View file

@ -1194,10 +1194,7 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
const auto admin = IsGroupCallAdmin(_peer, participantPeer); const auto admin = IsGroupCallAdmin(_peer, participantPeer);
const auto session = &_peer->session(); const auto session = &_peer->session();
const auto getCurrentWindow = [=]() -> Window::SessionController* { const auto getCurrentWindow = [=]() -> Window::SessionController* {
if (const auto window = Core::App().separateWindowForPeer( if (const auto window = Core::App().windowFor(participantPeer)) {
participantPeer)) {
return window->sessionController();
} else if (const auto window = Core::App().primaryWindow()) {
if (const auto controller = window->sessionController()) { if (const auto controller = window->sessionController()) {
if (&controller->session() == session) { if (&controller->session() == session) {
return controller; return controller;

View file

@ -186,8 +186,9 @@ Application::~Application() {
// Depend on primaryWindow() for now :( // Depend on primaryWindow() for now :(
Shortcuts::Finish(); Shortcuts::Finish();
_closingAsyncWindows.clear();
_secondaryWindows.clear(); _secondaryWindows.clear();
_primaryWindow = nullptr; _primaryWindows.clear();
_mediaView = nullptr; _mediaView = nullptr;
_notifications->clearAllFast(); _notifications->clearAllFast();
@ -280,13 +281,15 @@ void Application::run() {
// Create mime database, so it won't be slow later. // Create mime database, so it won't be slow later.
QMimeDatabase().mimeTypeForName(u"text/plain"_q); QMimeDatabase().mimeTypeForName(u"text/plain"_q);
_primaryWindow = std::make_unique<Window::Controller>(); _primaryWindows.emplace(nullptr, std::make_unique<Window::Controller>());
_lastActiveWindow = _primaryWindow.get(); _lastActiveWindow
= _lastActivePrimaryWindow
= _primaryWindows.front().second.get();
_domain->activeChanges( _domain->activeChanges(
) | rpl::start_with_next([=](not_null<Main::Account*> account) { ) | rpl::start_with_next([=](not_null<Main::Account*> account) {
_primaryWindow->showAccount(account); showAccount(account);
}, _primaryWindow->widget()->lifetime()); }, _lifetime);
( (
_domain->activeValue( _domain->activeValue(
@ -303,15 +306,15 @@ void Application::run() {
) | rpl::start_with_next([=](not_null<Main::Account*> account) { ) | rpl::start_with_next([=](not_null<Main::Account*> account) {
const auto ordered = _domain->orderedAccounts(); const auto ordered = _domain->orderedAccounts();
const auto it = ranges::find(ordered, account); const auto it = ranges::find(ordered, account);
if (it != end(ordered)) { if (_lastActivePrimaryWindow && it != end(ordered)) {
const auto index = std::distance(begin(ordered), it); const auto index = std::distance(begin(ordered), it);
if ((index + 1) > _domain->maxAccounts()) { if ((index + 1) > _domain->maxAccounts()) {
_primaryWindow->show(Box( _lastActivePrimaryWindow->show(Box(
AccountsLimitBox, AccountsLimitBox,
&account->session())); &account->session()));
} }
} }
}, _primaryWindow->widget()->lifetime()); }, _lifetime);
QCoreApplication::instance()->installEventFilter(this); QCoreApplication::instance()->installEventFilter(this);
@ -332,20 +335,20 @@ void Application::run() {
startTray(); startTray();
_primaryWindow->widget()->show(); _lastActivePrimaryWindow->widget()->show();
const auto currentGeometry = _primaryWindow->widget()->geometry(); const auto current = _lastActivePrimaryWindow->widget()->geometry();
_mediaView = std::make_unique<Media::View::OverlayWidget>(); _mediaView = std::make_unique<Media::View::OverlayWidget>();
_primaryWindow->widget()->Ui::RpWidget::setGeometry(currentGeometry); _lastActivePrimaryWindow->widget()->Ui::RpWidget::setGeometry(current);
DEBUG_LOG(("Application Info: showing.")); DEBUG_LOG(("Application Info: showing."));
_primaryWindow->finishFirstShow(); _lastActivePrimaryWindow->finishFirstShow();
if (!_primaryWindow->locked() && cStartToSettings()) { if (!_lastActivePrimaryWindow->locked() && cStartToSettings()) {
_primaryWindow->showSettings(); _lastActivePrimaryWindow->showSettings();
} }
_primaryWindow->updateIsActiveFocus(); _lastActivePrimaryWindow->updateIsActiveFocus();
for (const auto &error : Shortcuts::Errors()) { for (const auto &error : Shortcuts::Errors()) {
LOG(("Shortcuts Error: %1").arg(error)); LOG(("Shortcuts Error: %1").arg(error));
@ -362,11 +365,6 @@ void Application::run() {
_mediaView->show(std::move(request)); _mediaView->show(std::move(request));
} }
}, _lifetime); }, _lifetime);
_primaryWindow->openInMediaViewRequests(
) | rpl::start_to_stream(
_openInMediaViewRequests,
_primaryWindow->lifetime());
{ {
const auto countries = std::make_shared<Countries::Manager>( const auto countries = std::make_shared<Countries::Manager>(
_domain.get()); _domain.get());
@ -374,6 +372,25 @@ void Application::run() {
[[maybe_unused]] const auto countriesCopy = countries; [[maybe_unused]] const auto countriesCopy = countries;
}); });
} }
processCreatedWindow(_lastActivePrimaryWindow);
}
void Application::showAccount(not_null<Main::Account*> account) {
if (const auto separate = separateWindowForAccount(account)) {
_lastActivePrimaryWindow = separate;
separate->activate();
} else if (const auto last = activePrimaryWindow()) {
for (auto &[key, window] : _primaryWindows) {
if (window.get() == last && key != account.get()) {
auto found = std::move(window);
_primaryWindows.remove(key);
_primaryWindows.emplace(account, std::move(found));
break;
}
}
last->showAccount(account);
}
} }
void Application::showOpenGLCrashNotification() { void Application::showOpenGLCrashNotification() {
@ -390,7 +407,7 @@ void Application::showOpenGLCrashNotification() {
Core::App().settings().setDisableOpenGL(true); Core::App().settings().setDisableOpenGL(true);
Local::writeSettings(); Local::writeSettings();
}; };
_primaryWindow->show(Ui::MakeConfirmBox({ _lastActivePrimaryWindow->show(Ui::MakeConfirmBox({
.text = "" .text = ""
"There may be a problem with your graphics drivers and OpenGL. " "There may be a problem with your graphics drivers and OpenGL. "
"Try updating your drivers.\n\n" "Try updating your drivers.\n\n"
@ -447,15 +464,15 @@ void Application::startSystemDarkModeViewer() {
void Application::enumerateWindows(Fn<void( void Application::enumerateWindows(Fn<void(
not_null<Window::Controller*>)> callback) const { not_null<Window::Controller*>)> callback) const {
if (_primaryWindow) { for (const auto &window : ranges::views::values(_primaryWindows)) {
callback(_primaryWindow.get()); callback(window.get());
} }
for (const auto &window : ranges::views::values(_secondaryWindows)) { for (const auto &window : ranges::views::values(_secondaryWindows)) {
callback(window.get()); callback(window.get());
} }
} }
void Application::processSecondaryWindow( void Application::processCreatedWindow(
not_null<Window::Controller*> window) { not_null<Window::Controller*> window) {
window->openInMediaViewRequests( window->openInMediaViewRequests(
) | rpl::start_to_stream(_openInMediaViewRequests, window->lifetime()); ) | rpl::start_to_stream(_openInMediaViewRequests, window->lifetime());
@ -468,21 +485,29 @@ void Application::startTray() {
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
enumerateWindows([&](WindowRaw w) { w->updateIsActive(); }); enumerateWindows([&](WindowRaw w) { w->updateIsActive(); });
_tray->updateMenuText(); _tray->updateMenuText();
}, _primaryWindow->widget()->lifetime()); }, _lifetime);
_tray->showFromTrayRequests( _tray->showFromTrayRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
const auto last = _lastActiveWindow; const auto last = _lastActiveWindow;
enumerateWindows([&](WindowRaw w) { w->widget()->showFromTray(); }); const auto primary = _lastActivePrimaryWindow;
if (last) { enumerateWindows([&](WindowRaw w) {
if (w != last && w != primary) {
w->widget()->showFromTray();
}
});
if (primary) {
primary->widget()->showFromTray();
}
if (last && last != primary) {
last->widget()->showFromTray(); last->widget()->showFromTray();
} }
}, _primaryWindow->widget()->lifetime()); }, _lifetime);
_tray->hideToTrayRequests( _tray->hideToTrayRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
enumerateWindows([&](WindowRaw w) { w->widget()->minimizeToTray(); }); enumerateWindows([&](WindowRaw w) { w->widget()->minimizeToTray(); });
}, _primaryWindow->widget()->lifetime()); }, _lifetime);
} }
auto Application::prepareEmojiSourceImages() auto Application::prepareEmojiSourceImages()
@ -504,10 +529,10 @@ void Application::clearEmojiSourceImages() {
} }
bool Application::isActiveForTrayMenu() const { bool Application::isActiveForTrayMenu() const {
if (_primaryWindow && _primaryWindow->widget()->isActiveForTrayMenu()) { return ranges::any_of(ranges::views::values(_primaryWindows), [=](
return true; const std::unique_ptr<Window::Controller> &controller) {
} return controller->widget()->isActiveForTrayMenu();
return ranges::any_of(ranges::views::values(_secondaryWindows), [=]( }) || ranges::any_of(ranges::views::values(_secondaryWindows), [=](
const std::unique_ptr<Window::Controller> &controller) { const std::unique_ptr<Window::Controller> &controller) {
return controller->widget()->isActiveForTrayMenu(); return controller->widget()->isActiveForTrayMenu();
}); });
@ -562,8 +587,8 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
cSetStartUrl(url.mid(0, 8192)); cSetStartUrl(url.mid(0, 8192));
checkStartUrl(); checkStartUrl();
} }
if (StartUrlRequiresActivate(url)) { if (_lastActivePrimaryWindow && StartUrlRequiresActivate(url)) {
_primaryWindow->activate(); _lastActivePrimaryWindow->activate();
} }
} }
} break; } break;
@ -804,15 +829,15 @@ void Application::checkLocalTime() {
void Application::handleAppActivated() { void Application::handleAppActivated() {
checkLocalTime(); checkLocalTime();
if (_primaryWindow) { if (_lastActiveWindow) {
_primaryWindow->updateIsActiveFocus(); _lastActiveWindow->updateIsActiveFocus();
} }
} }
void Application::handleAppDeactivated() { void Application::handleAppDeactivated() {
if (_primaryWindow) { enumerateWindows([&](not_null<Window::Controller*> w) {
_primaryWindow->updateIsActiveBlur(); w->updateIsActiveBlur();
} });
const auto session = _lastActiveWindow const auto session = _lastActiveWindow
? _lastActiveWindow->maybeSession() ? _lastActiveWindow->maybeSession()
: nullptr; : nullptr;
@ -845,8 +870,8 @@ void Application::switchDebugMode() {
Logs::SetDebugEnabled(true); Logs::SetDebugEnabled(true);
_launcher->writeDebugModeSetting(); _launcher->writeDebugModeSetting();
DEBUG_LOG(("Debug logs started.")); DEBUG_LOG(("Debug logs started."));
if (_primaryWindow) { if (_lastActivePrimaryWindow) {
_primaryWindow->hideLayer(); _lastActivePrimaryWindow->hideLayer();
} }
} }
} }
@ -959,13 +984,17 @@ bool Application::canApplyLangPackWithoutRestart() const {
} }
void Application::checkSendPaths() { void Application::checkSendPaths() {
if (!cSendPaths().isEmpty() && _primaryWindow && !_primaryWindow->locked()) { if (!cSendPaths().isEmpty()
_primaryWindow->widget()->sendPaths(); && _lastActivePrimaryWindow
&& !_lastActivePrimaryWindow->locked()) {
_lastActivePrimaryWindow->widget()->sendPaths();
} }
} }
void Application::checkStartUrl() { void Application::checkStartUrl() {
if (!cStartUrl().isEmpty() && _primaryWindow && !_primaryWindow->locked()) { if (!cStartUrl().isEmpty()
&& _lastActivePrimaryWindow
&& !_lastActivePrimaryWindow->locked()) {
const auto url = cStartUrl(); const auto url = cStartUrl();
cSetStartUrl(QString()); cSetStartUrl(QString());
if (!openLocalUrl(url, {})) { if (!openLocalUrl(url, {})) {
@ -1029,8 +1058,8 @@ bool Application::openCustomUrl(
const auto my = context.value<ClickHandlerContext>(); const auto my = context.value<ClickHandlerContext>();
const auto controller = my.sessionWindow.get() const auto controller = my.sessionWindow.get()
? my.sessionWindow.get() ? my.sessionWindow.get()
: _primaryWindow : _lastActivePrimaryWindow
? _primaryWindow->sessionController() ? _lastActivePrimaryWindow->sessionController()
: nullptr; : nullptr;
using namespace qthelp; using namespace qthelp;
@ -1042,11 +1071,10 @@ bool Application::openCustomUrl(
} }
} }
return false; return false;
} }
void Application::preventOrInvoke(Fn<void()> &&callback) { void Application::preventOrInvoke(Fn<void()> &&callback) {
_primaryWindow->preventOrInvoke(std::move(callback)); _lastActivePrimaryWindow->preventOrInvoke(std::move(callback));
} }
void Application::lockByPasscode() { void Application::lockByPasscode() {
@ -1150,7 +1178,7 @@ void Application::localPasscodeChanged() {
} }
bool Application::hasActiveWindow(not_null<Main::Session*> session) const { bool Application::hasActiveWindow(not_null<Main::Session*> session) const {
if (Quitting() || !_primaryWindow) { if (Quitting() || !_lastActiveWindow) {
return false; return false;
} else if (_calls->hasActivePanel(session)) { } else if (_calls->hasActivePanel(session)) {
return true; return true;
@ -1161,8 +1189,18 @@ bool Application::hasActiveWindow(not_null<Main::Session*> session) const {
return false; return false;
} }
Window::Controller *Application::primaryWindow() const { Window::Controller *Application::activePrimaryWindow() const {
return _primaryWindow.get(); return _lastActivePrimaryWindow;
}
Window::Controller *Application::separateWindowForAccount(
not_null<Main::Account*> account) const {
for (const auto &[openedAccount, window] : _primaryWindows) {
if (openedAccount == account.get()) {
return window.get();
}
}
return nullptr;
} }
Window::Controller *Application::separateWindowForPeer( Window::Controller *Application::separateWindowForPeer(
@ -1194,22 +1232,98 @@ Window::Controller *Application::ensureSeparateWindowForPeer(
peer->owner().history(peer), peer->owner().history(peer),
std::make_unique<Window::Controller>(peer, showAtMsgId) std::make_unique<Window::Controller>(peer, showAtMsgId)
).first->second.get(); ).first->second.get();
processSecondaryWindow(result); processCreatedWindow(result);
result->widget()->show(); result->widget()->show();
result->finishFirstShow(); result->finishFirstShow();
return activate(result); return activate(result);
} }
Window::Controller *Application::ensureSeparateWindowForAccount(
not_null<Main::Account*> account) {
const auto activate = [&](not_null<Window::Controller*> window) {
window->activate();
return window;
};
if (const auto existing = separateWindowForAccount(account)) {
return activate(existing);
}
const auto result = _primaryWindows.emplace(
account,
std::make_unique<Window::Controller>(account)
).first->second.get();
processCreatedWindow(result);
result->widget()->show();
result->finishFirstShow();
return activate(result);
}
Window::Controller *Application::windowFor(not_null<PeerData*> peer) const {
if (const auto separate = separateWindowForPeer(peer)) {
return separate;
}
return windowFor(&peer->account());
}
Window::Controller *Application::windowFor(
not_null<Main::Account*> account) const {
if (const auto separate = separateWindowForAccount(account)) {
return separate;
}
return activePrimaryWindow();
}
Window::Controller *Application::activeWindow() const { Window::Controller *Application::activeWindow() const {
return _lastActiveWindow; return _lastActiveWindow;
} }
bool Application::closeNonLastAsync(not_null<Window::Controller*> window) {
const auto hasOther = [&] {
for (const auto &[account, primary] : _primaryWindows) {
if (!_closingAsyncWindows.contains(primary.get())
&& primary.get() != window
&& primary->maybeSession()) {
return true;
}
}
return false;
}();
if (!hasOther) {
return false;
}
_closingAsyncWindows.emplace(window);
crl::on_main(window, [=] { closeWindow(window); });
return true;
}
void Application::closeWindow(not_null<Window::Controller*> window) { void Application::closeWindow(not_null<Window::Controller*> window) {
const auto next = (_primaryWindows.front().second.get() != window)
? _primaryWindows.front().second.get()
: (_primaryWindows.back().second.get() != window)
? _primaryWindows.back().second.get()
: nullptr;
if (_lastActivePrimaryWindow == window) {
_lastActivePrimaryWindow = next;
}
if (_lastActiveWindow == window) {
_lastActiveWindow = next;
if (_lastActiveWindow) {
_lastActiveWindow->activate();
}
}
_closingAsyncWindows.remove(window);
for (auto i = begin(_primaryWindows); i != end(_primaryWindows);) {
if (i->second.get() == window) {
Assert(_lastActiveWindow != window);
Assert(_lastActivePrimaryWindow != window);
i = _primaryWindows.erase(i);
} else {
++i;
}
}
for (auto i = begin(_secondaryWindows); i != end(_secondaryWindows);) { for (auto i = begin(_secondaryWindows); i != end(_secondaryWindows);) {
if (i->second.get() == window) { if (i->second.get() == window) {
if (_lastActiveWindow == window) { Assert(_lastActiveWindow != window);
_lastActiveWindow = _primaryWindow.get();
}
i = _secondaryWindows.erase(i); i = _secondaryWindows.erase(i);
} else { } else {
++i; ++i;
@ -1218,11 +1332,12 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
} }
void Application::closeChatFromWindows(not_null<PeerData*> peer) { void Application::closeChatFromWindows(not_null<PeerData*> peer) {
if (const auto window = windowFor(peer)
; window && !window->isPrimary()) {
closeWindow(window);
}
for (const auto &[history, window] : _secondaryWindows) { for (const auto &[history, window] : _secondaryWindows) {
if (history->peer == peer) { if (const auto session = window->sessionController()) {
closeWindow(window.get());
break;
} else if (const auto session = window->sessionController()) {
if (session->activeChatCurrent().peer() == peer) { if (session->activeChatCurrent().peer() == peer) {
session->showPeerHistory( session->showPeerHistory(
window->singlePeer()->id, window->singlePeer()->id,
@ -1230,8 +1345,8 @@ void Application::closeChatFromWindows(not_null<PeerData*> peer) {
} }
} }
} }
if (_primaryWindow && _primaryWindow->sessionController()) { if (const auto window = windowFor(&peer->account())) {
const auto primary = _primaryWindow->sessionController(); const auto primary = window->sessionController();
if ((primary->activeChatCurrent().peer() == peer) if ((primary->activeChatCurrent().peer() == peer)
&& (&primary->session() == &peer->session())) { && (&primary->session() == &peer->session())) {
primary->clearSectionStack(); primary->clearSectionStack();
@ -1249,6 +1364,10 @@ void Application::windowActivated(not_null<Window::Controller*> window) {
const auto now = window; const auto now = window;
_lastActiveWindow = window; _lastActiveWindow = window;
if (window->isPrimary()) {
_lastActivePrimaryWindow = window;
}
const auto wasSession = was ? was->maybeSession() : nullptr; const auto wasSession = was ? was->maybeSession() : nullptr;
const auto nowSession = now->maybeSession(); const auto nowSession = now->maybeSession();
if (wasSession != nowSession) { if (wasSession != nowSession) {
@ -1410,8 +1529,8 @@ void Application::quitPreventFinished() {
} }
void Application::quitDelayed() { void Application::quitDelayed() {
if (_primaryWindow) { for (const auto &[account, window] : _primaryWindows) {
_primaryWindow->widget()->hide(); window->widget()->hide();
} }
for (const auto &[history, window] : _secondaryWindows) { for (const auto &[history, window] : _secondaryWindows) {
window->widget()->hide(); window->widget()->hide();

View file

@ -152,13 +152,25 @@ public:
// Windows interface. // Windows interface.
bool hasActiveWindow(not_null<Main::Session*> session) const; bool hasActiveWindow(not_null<Main::Session*> session) const;
[[nodiscard]] Window::Controller *primaryWindow() const;
// Don't auto-switch.
[[nodiscard]] Window::Controller *activeWindow() const; [[nodiscard]] Window::Controller *activeWindow() const;
[[nodiscard]] Window::Controller *activePrimaryWindow() const;
[[nodiscard]] Window::Controller *separateWindowForAccount(
not_null<Main::Account*> account) const;
[[nodiscard]] Window::Controller *separateWindowForPeer( [[nodiscard]] Window::Controller *separateWindowForPeer(
not_null<PeerData*> peer) const; not_null<PeerData*> peer) const;
Window::Controller *ensureSeparateWindowForPeer( Window::Controller *ensureSeparateWindowForPeer(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId showAtMsgId); MsgId showAtMsgId);
Window::Controller *ensureSeparateWindowForAccount(
not_null<Main::Account*> account);
[[nodiscard]] Window::Controller *windowFor( // Doesn't auto-switch.
not_null<PeerData*> peer) const;
[[nodiscard]] Window::Controller *windowFor( // Doesn't auto-switch.
not_null<Main::Account*> account) const;
[[nodiscard]] bool closeNonLastAsync(
not_null<Window::Controller*> window);
void closeWindow(not_null<Window::Controller*> window); void closeWindow(not_null<Window::Controller*> window);
void windowActivated(not_null<Window::Controller*> window); void windowActivated(not_null<Window::Controller*> window);
bool closeActiveWindow(); bool closeActiveWindow();
@ -325,9 +337,10 @@ private:
void startSystemDarkModeViewer(); void startSystemDarkModeViewer();
void startTray(); void startTray();
void showAccount(not_null<Main::Account*> account);
void enumerateWindows( void enumerateWindows(
Fn<void(not_null<Window::Controller*>)> callback) const; Fn<void(not_null<Window::Controller*>)> callback) const;
void processSecondaryWindow(not_null<Window::Controller*> window); void processCreatedWindow(not_null<Window::Controller*> window);
friend void QuitAttempt(); friend void QuitAttempt();
void quitDelayed(); void quitDelayed();
@ -375,11 +388,15 @@ private:
const std::unique_ptr<Main::Domain> _domain; const std::unique_ptr<Main::Domain> _domain;
const std::unique_ptr<Export::Manager> _exportManager; const std::unique_ptr<Export::Manager> _exportManager;
const std::unique_ptr<Calls::Instance> _calls; const std::unique_ptr<Calls::Instance> _calls;
std::unique_ptr<Window::Controller> _primaryWindow; base::flat_map<
Main::Account*,
std::unique_ptr<Window::Controller>> _primaryWindows;
base::flat_set<not_null<Window::Controller*>> _closingAsyncWindows;
base::flat_map< base::flat_map<
not_null<History*>, not_null<History*>,
std::unique_ptr<Window::Controller>> _secondaryWindows; std::unique_ptr<Window::Controller>> _secondaryWindows;
Window::Controller *_lastActiveWindow = nullptr; Window::Controller *_lastActiveWindow = nullptr;
Window::Controller *_lastActivePrimaryWindow = nullptr;
std::unique_ptr<Media::View::OverlayWidget> _mediaView; std::unique_ptr<Media::View::OverlayWidget> _mediaView;
const std::unique_ptr<Lang::Instance> _langpack; const std::unique_ptr<Lang::Instance> _langpack;

View file

@ -661,8 +661,8 @@ void Sandbox::closeApplication() {
uint64 Sandbox::execExternal(const QString &cmd) { uint64 Sandbox::execExternal(const QString &cmd) {
DEBUG_LOG(("Sandbox Info: executing external command '%1'").arg(cmd)); DEBUG_LOG(("Sandbox Info: executing external command '%1'").arg(cmd));
if (cmd == "show") { if (cmd == "show") {
if (Core::IsAppLaunched() && Core::App().primaryWindow()) { if (Core::IsAppLaunched() && Core::App().activePrimaryWindow()) {
const auto window = Core::App().primaryWindow(); const auto window = Core::App().activePrimaryWindow();
window->activate(); window->activate();
return Platform::ActivationWindowId(window->widget()); return Platform::ActivationWindowId(window->widget());
} else if (const auto window = PreLaunchWindow::instance()) { } else if (const auto window = PreLaunchWindow::instance()) {

View file

@ -443,7 +443,7 @@ void Manager::set(const QString &keys, Command command, bool replace) {
} }
auto shortcut = base::make_unique_q<QShortcut>( auto shortcut = base::make_unique_q<QShortcut>(
result, result,
Core::App().primaryWindow()->widget().get(), Core::App().activePrimaryWindow()->widget().get(), // #TODO windows
nullptr, nullptr,
nullptr, nullptr,
Qt::ApplicationShortcut); Qt::ApplicationShortcut);

View file

@ -124,7 +124,8 @@ QString UiIntegration::angleBackendFilePath() {
} }
void UiIntegration::textActionsUpdated() { void UiIntegration::textActionsUpdated() {
if (const auto window = Core::App().primaryWindow()) { // #TODO windows global menu
if (const auto window = Core::App().activePrimaryWindow()) {
window->widget()->updateGlobalMenu(); window->widget()->updateGlobalMenu();
} }
} }

View file

@ -1649,7 +1649,7 @@ void UpdateApplication() {
} else { } else {
cSetAutoUpdate(true); cSetAutoUpdate(true);
const auto window = Core::IsAppLaunched() const auto window = Core::IsAppLaunched()
? Core::App().primaryWindow() ? Core::App().activePrimaryWindow()
: nullptr; : nullptr;
if (window) { if (window) {
if (const auto controller = window->sessionController()) { if (const auto controller = window->sessionController()) {

View file

@ -508,9 +508,13 @@ HistoryItem *DownloadManager::lookupLoadingItem(
void DownloadManager::loadingStopWithConfirmation( void DownloadManager::loadingStopWithConfirmation(
Fn<void()> callback, Fn<void()> callback,
Main::Session *onlyInSession) { Main::Session *onlyInSession) {
const auto window = Core::App().primaryWindow();
const auto item = lookupLoadingItem(onlyInSession); const auto item = lookupLoadingItem(onlyInSession);
if (!window || !item) { if (!item) {
return;
}
const auto window = Core::App().windowFor(
&item->history()->session().account());
if (!window) {
return; return;
} }
const auto weak = base::make_weak(&item->history()->session()); const auto weak = base::make_weak(&item->history()->session());

View file

@ -70,7 +70,7 @@ namespace {
constexpr auto kHashtagResultsLimit = 5; constexpr auto kHashtagResultsLimit = 5;
constexpr auto kStartReorderThreshold = 30; constexpr auto kStartReorderThreshold = 30;
base::options::toggle TabbedPanelShowOnClick({ base::options::toggle CtrlClickChatNewWindow({
.id = kOptionCtrlClickChatNewWindow, .id = kOptionCtrlClickChatNewWindow,
.name = "New chat window by Ctrl+Click", .name = "New chat window by Ctrl+Click",
.description = "Open chat in a new window by Ctrl+Click " .description = "Open chat in a new window by Ctrl+Click "
@ -3310,7 +3310,7 @@ bool InnerWidget::chooseRow(
const auto modifyChosenRow = []( const auto modifyChosenRow = [](
ChosenRow row, ChosenRow row,
Qt::KeyboardModifiers modifiers) { Qt::KeyboardModifiers modifiers) {
if (TabbedPanelShowOnClick.value()) { if (CtrlClickChatNewWindow.value()) {
row.newWindow = (modifiers & Qt::ControlModifier); row.newWindow = (modifiers & Qt::ControlModifier);
} }
return row; return row;

View file

@ -732,8 +732,9 @@ HistoryWidget::HistoryWidget(
if (flags & PeerUpdateFlag::UnavailableReason) { if (flags & PeerUpdateFlag::UnavailableReason) {
const auto unavailable = _peer->computeUnavailableReason(); const auto unavailable = _peer->computeUnavailableReason();
if (!unavailable.isEmpty()) { if (!unavailable.isEmpty()) {
const auto account = &_peer->account();
closeCurrent(); closeCurrent();
if (const auto primary = Core::App().primaryWindow()) { if (const auto primary = Core::App().windowFor(account)) {
primary->show(Ui::MakeInformBox(unavailable)); primary->show(Ui::MakeInformBox(unavailable));
} }
return; return;
@ -3017,7 +3018,7 @@ void HistoryWidget::messagesFailed(const MTP::Error &error, int requestId) {
|| error.type() == u"USER_BANNED_IN_CHANNEL"_q) { || error.type() == u"USER_BANNED_IN_CHANNEL"_q) {
auto was = _peer; auto was = _peer;
closeCurrent(); closeCurrent();
if (const auto primary = Core::App().primaryWindow()) { if (const auto primary = Core::App().windowFor(&was->account())) {
Ui::ShowMultilineToast({ Ui::ShowMultilineToast({
.parentOverride = Window::Show(primary).toastParent(), .parentOverride = Window::Show(primary).toastParent(),
.text = { (was && was->isMegagroup()) .text = { (was && was->isMegagroup())

View file

@ -75,7 +75,7 @@ Storage::StartResult Domain::start(const QByteArray &passcode) {
void Domain::finish() { void Domain::finish() {
_accountToActivate = -1; _accountToActivate = -1;
_active = nullptr; _active.reset(nullptr);
base::take(_accounts); base::take(_accounts);
} }
@ -417,9 +417,13 @@ void Domain::checkForLastProductionConfig(
} }
void Domain::maybeActivate(not_null<Main::Account*> account) { void Domain::maybeActivate(not_null<Main::Account*> account) {
Core::App().preventOrInvoke(crl::guard(account, [=] { if (Core::App().separateWindowForAccount(account)) {
activate(account); activate(account);
})); } else {
Core::App().preventOrInvoke(crl::guard(account, [=] {
activate(account);
}));
}
} }
void Domain::activate(not_null<Main::Account*> account) { void Domain::activate(not_null<Main::Account*> account) {

View file

@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/stickers_emoji_pack.h" #include "chat_helpers/stickers_emoji_pack.h"
#include "chat_helpers/stickers_dice_pack.h" #include "chat_helpers/stickers_dice_pack.h"
#include "chat_helpers/stickers_gift_box_pack.h" #include "chat_helpers/stickers_gift_box_pack.h"
#include "history/history.h"
#include "history/history_item.h"
#include "inline_bots/bot_attach_web_view.h" #include "inline_bots/bot_attach_web_view.h"
#include "storage/file_download.h" #include "storage/file_download.h"
#include "storage/download_manager_mtproto.h" #include "storage/download_manager_mtproto.h"
@ -411,12 +413,12 @@ bool Session::uploadsInProgress() const {
} }
void Session::uploadsStopWithConfirmation(Fn<void()> done) { void Session::uploadsStopWithConfirmation(Fn<void()> done) {
const auto window = Core::App().primaryWindow();
if (!window) {
return;
}
const auto id = _uploader->currentUploadId(); const auto id = _uploader->currentUploadId();
const auto exists = !!data().message(id); const auto message = data().message(id);
const auto exists = (message != nullptr);
const auto window = message
? Core::App().windowFor(message->history()->peer)
: Core::App().activePrimaryWindow();
auto box = Box([=](not_null<Ui::GenericBox*> box) { auto box = Box([=](not_null<Ui::GenericBox*> box) {
box->addRow( box->addRow(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(

View file

@ -1214,10 +1214,22 @@ bool MainWidget::showHistoryInDifferentWindow(
showAtMsgId); showAtMsgId);
separate->activate(); separate->activate();
return true; return true;
} else if (isPrimary() || (singlePeer()->id == peerId)) { } else if (isPrimary()) {
const auto primary = Core::App().separateWindowForAccount(
&peer->account());
if (primary != &_controller->window()) {
primary->sessionController()->showPeerHistory(
peerId,
params,
showAtMsgId);
primary->activate();
return true;
}
return false;
} else if (singlePeer()->id == peerId) {
return false; return false;
} }
const auto primary = Core::App().primaryWindow(); const auto primary = Core::App().activePrimaryWindow();
if (&primary->account() != &session().account()) { if (&primary->account() != &session().account()) {
primary->showAccount(&session().account()); primary->showAccount(&session().account());
} }

View file

@ -666,11 +666,8 @@ void MainWindow::closeEvent(QCloseEvent *e) {
e->accept(); e->accept();
Core::Quit(); Core::Quit();
return; return;
} else if (!isPrimary()) { } else if (Core::App().closeNonLastAsync(&controller())) {
e->accept(); e->accept();
crl::on_main(this, [=] {
Core::App().closeWindow(&controller());
});
return; return;
} }
e->ignore(); e->ignore();

View file

@ -308,7 +308,8 @@ void Instance::clearStreamed(not_null<Data*> data, bool savePosition) {
data->streamed = nullptr; data->streamed = nullptr;
_roundPlaying = false; _roundPlaying = false;
if (const auto window = Core::App().primaryWindow()) { // #TODO windows
if (const auto window = Core::App().activePrimaryWindow()) {
if (const auto controller = window->sessionController()) { if (const auto controller = window->sessionController()) {
controller->disableGifPauseReason( controller->disableGifPauseReason(
Window::GifPauseReason::RoundPlaying); Window::GifPauseReason::RoundPlaying);
@ -1292,7 +1293,8 @@ void Instance::handleStreamingUpdate(
requestRoundVideoRepaint(); requestRoundVideoRepaint();
}); });
_roundPlaying = true; _roundPlaying = true;
if (const auto window = Core::App().primaryWindow()) { // #TODO windows
if (const auto window = Core::App().activePrimaryWindow()) {
if (const auto controller = window->sessionController()) { if (const auto controller = window->sessionController()) {
controller->enableGifPauseReason( controller->enableGifPauseReason(
Window::GifPauseReason::RoundPlaying); Window::GifPauseReason::RoundPlaying);

View file

@ -4835,7 +4835,14 @@ Window::SessionController *OverlayWidget::findWindow(bool switchTo) const {
if (switchTo) { if (switchTo) {
auto controllerPtr = (Window::SessionController*)nullptr; auto controllerPtr = (Window::SessionController*)nullptr;
const auto anyWindow = window ? window : Core::App().primaryWindow(); const auto account = &_session->account();
const auto sessionWindow = Core::App().windowFor(account);
const auto anyWindow = (sessionWindow
&& &sessionWindow->account() == account)
? sessionWindow
: window
? window
: sessionWindow;
if (anyWindow) { if (anyWindow) {
anyWindow->invokeForSessionController( anyWindow->invokeForSessionController(
&_session->account(), &_session->account(),

View file

@ -270,7 +270,7 @@ void LaunchGApplication() {
app->signal_activate().connect([] { app->signal_activate().connect([] {
Core::Sandbox::Instance().customEnterFromEventLoop([] { Core::Sandbox::Instance().customEnterFromEventLoop([] {
const auto window = Core::IsAppLaunched() const auto window = Core::IsAppLaunched()
? Core::App().primaryWindow() ? Core::App().activePrimaryWindow()
: nullptr; : nullptr;
if (window) { if (window) {
window->activate(); window->activate();
@ -298,7 +298,7 @@ void LaunchGApplication() {
} }
if (Core::StartUrlRequiresActivate(url)) { if (Core::StartUrlRequiresActivate(url)) {
const auto window = Core::IsAppLaunched() const auto window = Core::IsAppLaunched()
? Core::App().primaryWindow() ? Core::App().activePrimaryWindow()
: nullptr; : nullptr;
if (window) { if (window) {
window->activate(); window->activate();

View file

@ -26,8 +26,9 @@ namespace Platform {
namespace { namespace {
[[nodiscard]] QWidget *Parent() { [[nodiscard]] QWidget *Parent() {
Expects(Core::App().primaryWindow() != nullptr); Expects(Core::App().activePrimaryWindow() != nullptr);
return Core::App().primaryWindow()->widget();
return Core::App().activePrimaryWindow()->widget();
} }
} // namespace } // namespace

View file

@ -767,7 +767,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
return; return;
} }
const auto active = Core::App().primaryWindow(); const auto active = Core::App().activePrimaryWindow();
const auto controller = active ? active->sessionController() : nullptr; const auto controller = active ? active->sessionController() : nullptr;
const auto openFolder = [=] { const auto openFolder = [=] {
const auto folder = _session->data().folderLoaded(Data::Folder::kId); const auto folder = _session->data().folderLoaded(Data::Folder::kId);

View file

@ -223,8 +223,9 @@ void UpdateIcon(const NSStatusItem *status) {
} }
[[nodiscard]] QWidget *Parent() { [[nodiscard]] QWidget *Parent() {
Expects(Core::App().primaryWindow() != nullptr); Expects(Core::App().activePrimaryWindow() != nullptr);
return Core::App().primaryWindow()->widget();
return Core::App().activePrimaryWindow()->widget();
} }
} // namespace } // namespace

View file

@ -22,8 +22,8 @@ namespace Platform {
// account, with 100% scale and without "px" dimensions, because thats // account, with 100% scale and without "px" dimensions, because thats
// how it will look in real launched macOS app. // how it will look in real launched macOS app.
int PreviewTitleHeight() { int PreviewTitleHeight() {
if (auto window = Core::App().primaryWindow()) { if (const auto window = Core::App().activePrimaryWindow()) {
if (auto height = window->widget()->getCustomTitleHeight()) { if (const auto height = window->widget()->getCustomTitleHeight()) {
return height; return height;
} }
} }

View file

@ -206,12 +206,8 @@ void MainWindow::shadowsDeactivate() {
} }
void MainWindow::destroyedFromSystem() { void MainWindow::destroyedFromSystem() {
if (isPrimary()) { if (!Core::App().closeNonLastAsync(&controller())) {
Core::Quit(); Core::Quit();
} else {
crl::on_main(this, [=] {
Core::App().closeWindow(&controller());
});
} }
} }

View file

@ -90,8 +90,9 @@ constexpr auto kTooltipDelay = crl::time(10000);
} }
[[nodiscard]] QWidget *Parent() { [[nodiscard]] QWidget *Parent() {
Expects(Core::App().primaryWindow() != nullptr); Expects(Core::App().activePrimaryWindow() != nullptr);
return Core::App().primaryWindow()->widget();
return Core::App().activePrimaryWindow()->widget();
} }
} // namespace } // namespace
@ -135,7 +136,7 @@ void Tray::updateIcon() {
} }
const auto counter = Core::App().unreadBadge(); const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted(); const auto muted = Core::App().unreadBadgeMuted();
const auto controller = Core::App().primaryWindow(); const auto controller = Core::App().activePrimaryWindow();
const auto session = !controller const auto session = !controller
? nullptr ? nullptr
: !controller->sessionController() : !controller->sessionController()

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "settings/settings_information.h" #include "settings/settings_information.h"
#include "dialogs/dialogs_inner_widget.h" // kOptionCtrlClickChatNewWindow.
#include "editor/photo_editor_layer_widget.h" #include "editor/photo_editor_layer_widget.h"
#include "settings/settings_common.h" #include "settings/settings_common.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
@ -51,6 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_user_names.h" #include "api/api_user_names.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "base/call_delayed.h" #include "base/call_delayed.h"
#include "base/options.h"
#include "base/unixtime.h" #include "base/unixtime.h"
#include "base/random.h" #include "base/random.h"
#include "styles/style_dialogs.h" // dialogsPremiumIcon #include "styles/style_dialogs.h" // dialogsPremiumIcon
@ -560,7 +562,7 @@ void SetupAccountsWrap(
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> window, not_null<Window::SessionController*> window,
not_null<Main::Account*> account, not_null<Main::Account*> account,
Fn<void()> callback, Fn<void(Qt::KeyboardModifiers)> callback,
bool locked) { bool locked) {
const auto active = (account == &Core::App().activeAccount()); const auto active = (account == &Core::App().activeAccount());
const auto session = &account->session(); const auto session = &account->session();
@ -642,7 +644,7 @@ void SetupAccountsWrap(
raw->clicks( raw->clicks(
) | rpl::start_with_next([=](Qt::MouseButton which) { ) | rpl::start_with_next([=](Qt::MouseButton which) {
if (which == Qt::LeftButton) { if (which == Qt::LeftButton) {
callback(); callback(raw->clickModifiers());
return; return;
} else if (which != Qt::RightButton) { } else if (which != Qt::RightButton) {
return; return;
@ -854,17 +856,24 @@ void AccountsList::rebuild() {
button = nullptr; button = nullptr;
} else if (!button) { } else if (!button) {
const auto nextIsLocked = (inner->count() >= premiumLimit); const auto nextIsLocked = (inner->count() >= premiumLimit);
auto callback = [=] { auto callback = [=](Qt::KeyboardModifiers modifiers) {
if (_reordering) { if (_reordering) {
return; return;
} }
if (account == &Core::App().domain().active()) { if (account == &_controller->session().account()) {
_currentAccountActivations.fire({}); _currentAccountActivations.fire({});
return; return;
} }
const auto newWindow = (modifiers & Qt::ControlModifier)
&& base::options::lookup<bool>(
Dialogs::kOptionCtrlClickChatNewWindow).value();
auto activate = [=, guard = _accountSwitchGuard.make_guard()]{ auto activate = [=, guard = _accountSwitchGuard.make_guard()]{
if (guard) { if (guard) {
_reorder->finishReordering(); _reorder->finishReordering();
if (newWindow) {
Core::App().ensureSeparateWindowForAccount(
account);
}
Core::App().domain().maybeActivate(account); Core::App().domain().maybeActivate(account);
} }
}; };

View file

@ -565,7 +565,8 @@ void System::showNext() {
const auto &settings = Core::App().settings(); const auto &settings = Core::App().settings();
if (alertThread) { if (alertThread) {
if (settings.flashBounceNotify() && !_manager->skipFlashBounce()) { if (settings.flashBounceNotify() && !_manager->skipFlashBounce()) {
if (const auto window = Core::App().primaryWindow()) { const auto peer = alertThread->peer();
if (const auto window = Core::App().windowFor(peer)) {
if (const auto handle = window->widget()->windowHandle()) { if (const auto handle = window->widget()->windowHandle()) {
handle->alert(kSystemAlertDuration); handle->alert(kSystemAlertDuration);
// (handle, SLOT(_q_clearAlert())); in the future. // (handle, SLOT(_q_clearAlert())); in the future.

View file

@ -47,15 +47,17 @@ namespace Notifications {
namespace Default { namespace Default {
namespace { namespace {
QPoint notificationStartPosition() { [[nodiscard]] QPoint notificationStartPosition() {
const auto corner = Core::App().settings().notificationsCorner(); const auto corner = Core::App().settings().notificationsCorner();
const auto window = Core::App().primaryWindow(); const auto window = Core::App().activePrimaryWindow();
const auto r = window const auto r = window
? window->widget()->desktopRect() ? window->widget()->desktopRect()
: QGuiApplication::primaryScreen()->availableGeometry(); : QGuiApplication::primaryScreen()->availableGeometry();
const auto isLeft = Core::Settings::IsLeftCorner(corner); const auto isLeft = Core::Settings::IsLeftCorner(corner);
const auto isTop = Core::Settings::IsTopCorner(corner); const auto isTop = Core::Settings::IsTopCorner(corner);
const auto x = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX); const auto x = (isLeft == rtl())
? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX)
: (r.x() + st::notifyDeltaX);
const auto y = isTop ? r.y() : (r.y() + r.height()); const auto y = isTop ? r.y() : (r.y() + r.height());
return QPoint(x, y); return QPoint(x, y);
} }

View file

@ -43,6 +43,11 @@ namespace Window {
Controller::Controller() : Controller(CreateArgs{}) { Controller::Controller() : Controller(CreateArgs{}) {
} }
Controller::Controller(not_null<Main::Account*> account)
: Controller(CreateArgs{}) {
showAccount(account);
}
Controller::Controller( Controller::Controller(
not_null<PeerData*> singlePeer, not_null<PeerData*> singlePeer,
MsgId showAtMsgId) MsgId showAtMsgId)

View file

@ -25,6 +25,7 @@ namespace Window {
class Controller final : public base::has_weak_ptr { class Controller final : public base::has_weak_ptr {
public: public:
Controller(); Controller();
explicit Controller(not_null<Main::Account*> account);
Controller( Controller(
not_null<PeerData*> singlePeer, not_null<PeerData*> singlePeer,
MsgId showAtMsgId); MsgId showAtMsgId);

View file

@ -71,6 +71,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "main/main_account.h"
#include "main/main_domain.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_session_settings.h" #include "main/main_session_settings.h"
#include "apiwrap.h" #include "apiwrap.h"
@ -977,9 +979,10 @@ void SessionController::showForum(
not_null<Data::Forum*> forum, not_null<Data::Forum*> forum,
const SectionShow &params) { const SectionShow &params) {
if (!isPrimary()) { if (!isPrimary()) {
const auto primary = Core::App().primaryWindow(); auto primary = Core::App().windowFor(&session().account());
if (&primary->account() != &session().account()) { if (&primary->account() != &session().account()) {
primary->showAccount(&session().account()); Core::App().domain().activate(&session().account());
primary = Core::App().windowFor(&session().account());
} }
if (&primary->account() == &session().account()) { if (&primary->account() == &session().account()) {
primary->sessionController()->showForum(forum, params); primary->sessionController()->showForum(forum, params);