2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-09-01 06:55:58 +00:00

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

@@ -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();