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(
not_null<PeerData*> peer) {
const auto separate = Core::App().separateWindowForPeer(peer);
const auto window = separate ? separate : Core::App().primaryWindow();
return std::make_shared<Window::Show>(window);
return std::make_shared<Window::Show>(Core::App().windowFor(peer));
}
void ShowChannelsLimitBox(not_null<PeerData*> peer) {
const auto primary = Core::App().primaryWindow();
if (!primary) {
return;
if (const auto window = Core::App().windowFor(peer)) {
window->invokeForSessionController(
&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

View File

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

View File

@ -69,10 +69,11 @@ void ChangeFilterById(
MTP_flags(MTPmessages_UpdateDialogFilter::Flag::f_filter),
MTP_int(filter.id()),
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,
// 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
? tr::lng_filters_toast_add
: 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 session = &_peer->session();
const auto getCurrentWindow = [=]() -> Window::SessionController* {
if (const auto window = Core::App().separateWindowForPeer(
participantPeer)) {
return window->sessionController();
} else if (const auto window = Core::App().primaryWindow()) {
if (const auto window = Core::App().windowFor(participantPeer)) {
if (const auto controller = window->sessionController()) {
if (&controller->session() == session) {
return controller;

View File

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

View File

@ -152,13 +152,25 @@ public:
// Windows interface.
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 *activePrimaryWindow() const;
[[nodiscard]] Window::Controller *separateWindowForAccount(
not_null<Main::Account*> account) const;
[[nodiscard]] Window::Controller *separateWindowForPeer(
not_null<PeerData*> peer) const;
Window::Controller *ensureSeparateWindowForPeer(
not_null<PeerData*> peer,
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 windowActivated(not_null<Window::Controller*> window);
bool closeActiveWindow();
@ -325,9 +337,10 @@ private:
void startSystemDarkModeViewer();
void startTray();
void showAccount(not_null<Main::Account*> account);
void enumerateWindows(
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();
void quitDelayed();
@ -375,11 +388,15 @@ private:
const std::unique_ptr<Main::Domain> _domain;
const std::unique_ptr<Export::Manager> _exportManager;
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<
not_null<History*>,
std::unique_ptr<Window::Controller>> _secondaryWindows;
Window::Controller *_lastActiveWindow = nullptr;
Window::Controller *_lastActivePrimaryWindow = nullptr;
std::unique_ptr<Media::View::OverlayWidget> _mediaView;
const std::unique_ptr<Lang::Instance> _langpack;

View File

@ -661,8 +661,8 @@ void Sandbox::closeApplication() {
uint64 Sandbox::execExternal(const QString &cmd) {
DEBUG_LOG(("Sandbox Info: executing external command '%1'").arg(cmd));
if (cmd == "show") {
if (Core::IsAppLaunched() && Core::App().primaryWindow()) {
const auto window = Core::App().primaryWindow();
if (Core::IsAppLaunched() && Core::App().activePrimaryWindow()) {
const auto window = Core::App().activePrimaryWindow();
window->activate();
return Platform::ActivationWindowId(window->widget());
} 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>(
result,
Core::App().primaryWindow()->widget().get(),
Core::App().activePrimaryWindow()->widget().get(), // #TODO windows
nullptr,
nullptr,
Qt::ApplicationShortcut);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -75,7 +75,7 @@ Storage::StartResult Domain::start(const QByteArray &passcode) {
void Domain::finish() {
_accountToActivate = -1;
_active = nullptr;
_active.reset(nullptr);
base::take(_accounts);
}
@ -417,9 +417,13 @@ void Domain::checkForLastProductionConfig(
}
void Domain::maybeActivate(not_null<Main::Account*> account) {
Core::App().preventOrInvoke(crl::guard(account, [=] {
if (Core::App().separateWindowForAccount(account)) {
activate(account);
}));
} else {
Core::App().preventOrInvoke(crl::guard(account, [=] {
activate(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_dice_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 "storage/file_download.h"
#include "storage/download_manager_mtproto.h"
@ -411,12 +413,12 @@ bool Session::uploadsInProgress() const {
}
void Session::uploadsStopWithConfirmation(Fn<void()> done) {
const auto window = Core::App().primaryWindow();
if (!window) {
return;
}
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) {
box->addRow(
object_ptr<Ui::FlatLabel>(

View File

@ -1214,10 +1214,22 @@ bool MainWidget::showHistoryInDifferentWindow(
showAtMsgId);
separate->activate();
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;
}
const auto primary = Core::App().primaryWindow();
const auto primary = Core::App().activePrimaryWindow();
if (&primary->account() != &session().account()) {
primary->showAccount(&session().account());
}

View File

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

View File

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

View File

@ -4835,7 +4835,14 @@ Window::SessionController *OverlayWidget::findWindow(bool switchTo) const {
if (switchTo) {
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) {
anyWindow->invokeForSessionController(
&_session->account(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -206,12 +206,8 @@ void MainWindow::shadowsDeactivate() {
}
void MainWindow::destroyedFromSystem() {
if (isPrimary()) {
if (!Core::App().closeNonLastAsync(&controller())) {
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() {
Expects(Core::App().primaryWindow() != nullptr);
return Core::App().primaryWindow()->widget();
Expects(Core::App().activePrimaryWindow() != nullptr);
return Core::App().activePrimaryWindow()->widget();
}
} // namespace
@ -135,7 +136,7 @@ void Tray::updateIcon() {
}
const auto counter = Core::App().unreadBadge();
const auto muted = Core::App().unreadBadgeMuted();
const auto controller = Core::App().primaryWindow();
const auto controller = Core::App().activePrimaryWindow();
const auto session = !controller
? nullptr
: !controller->sessionController()

View File

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

View File

@ -565,7 +565,8 @@ void System::showNext() {
const auto &settings = Core::App().settings();
if (alertThread) {
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()) {
handle->alert(kSystemAlertDuration);
// (handle, SLOT(_q_clearAlert())); in the future.

View File

@ -47,15 +47,17 @@ namespace Notifications {
namespace Default {
namespace {
QPoint notificationStartPosition() {
[[nodiscard]] QPoint notificationStartPosition() {
const auto corner = Core::App().settings().notificationsCorner();
const auto window = Core::App().primaryWindow();
const auto window = Core::App().activePrimaryWindow();
const auto r = window
? window->widget()->desktopRect()
: QGuiApplication::primaryScreen()->availableGeometry();
const auto isLeft = Core::Settings::IsLeftCorner(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());
return QPoint(x, y);
}

View File

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

View File

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

View File

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