mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-09-03 07:56:03 +00:00
Separate window for forums/topics/sublists/archive.
This commit is contained in:
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
|
||||
#include "data/data_abstract_structure.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
@@ -91,6 +92,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "payments/payments_checkout_process.h"
|
||||
#include "export/export_manager.h"
|
||||
#include "webrtc/webrtc_environment.h"
|
||||
#include "window/window_separate_id.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
@@ -209,8 +211,7 @@ Application::~Application() {
|
||||
setLastActiveWindow(nullptr);
|
||||
_windowInSettings = _lastActivePrimaryWindow = nullptr;
|
||||
_closingAsyncWindows.clear();
|
||||
_secondaryWindows.clear();
|
||||
_primaryWindows.clear();
|
||||
_windows.clear();
|
||||
_mediaView = nullptr;
|
||||
_notifications->clearAllFast();
|
||||
|
||||
@@ -315,8 +316,8 @@ void Application::run() {
|
||||
// Create mime database, so it won't be slow later.
|
||||
QMimeDatabase().mimeTypeForName(u"text/plain"_q);
|
||||
|
||||
_primaryWindows.emplace(nullptr, std::make_unique<Window::Controller>());
|
||||
setLastActiveWindow(_primaryWindows.front().second.get());
|
||||
_windows.emplace(nullptr, std::make_unique<Window::Controller>());
|
||||
setLastActiveWindow(_windows.front().second.get());
|
||||
_windowInSettings = _lastActivePrimaryWindow = _lastActiveWindow;
|
||||
|
||||
_domain->activeChanges(
|
||||
@@ -405,7 +406,7 @@ void Application::run() {
|
||||
}
|
||||
|
||||
void Application::showAccount(not_null<Main::Account*> account) {
|
||||
if (const auto separate = separateWindowForAccount(account)) {
|
||||
if (const auto separate = separateWindowFor(account)) {
|
||||
_lastActivePrimaryWindow = separate;
|
||||
separate->activate();
|
||||
} else if (const auto last = activePrimaryWindow()) {
|
||||
@@ -413,13 +414,13 @@ void Application::showAccount(not_null<Main::Account*> account) {
|
||||
}
|
||||
}
|
||||
|
||||
void Application::checkWindowAccount(not_null<Window::Controller*> window) {
|
||||
const auto account = window->maybeAccount();
|
||||
for (auto &[key, existing] : _primaryWindows) {
|
||||
if (existing.get() == window && key != account) {
|
||||
void Application::checkWindowId(not_null<Window::Controller*> window) {
|
||||
const auto id = window->id();
|
||||
for (auto &[existingId, existing] : _windows) {
|
||||
if (existing.get() == window && existingId != id) {
|
||||
auto found = std::move(existing);
|
||||
_primaryWindows.remove(key);
|
||||
_primaryWindows.emplace(account, std::move(found));
|
||||
_windows.remove(existingId);
|
||||
_windows.emplace(id, std::move(found));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -495,10 +496,7 @@ void Application::startSystemDarkModeViewer() {
|
||||
|
||||
void Application::enumerateWindows(Fn<void(
|
||||
not_null<Window::Controller*>)> callback) const {
|
||||
for (const auto &window : ranges::views::values(_primaryWindows)) {
|
||||
callback(window.get());
|
||||
}
|
||||
for (const auto &window : ranges::views::values(_secondaryWindows)) {
|
||||
for (const auto &window : ranges::views::values(_windows)) {
|
||||
callback(window.get());
|
||||
}
|
||||
}
|
||||
@@ -607,10 +605,7 @@ void Application::clearEmojiSourceImages() {
|
||||
}
|
||||
|
||||
bool Application::isActiveForTrayMenu() const {
|
||||
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), [=](
|
||||
return ranges::any_of(ranges::views::values(_windows), [=](
|
||||
const std::unique_ptr<Window::Controller> &controller) {
|
||||
return controller->widget()->isActiveForTrayMenu();
|
||||
});
|
||||
@@ -1287,44 +1282,36 @@ 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()) {
|
||||
Window::Controller *Application::separateWindowFor(
|
||||
Window::SeparateId id) const {
|
||||
for (const auto &[existingId, window] : _windows) {
|
||||
if (existingId == id) {
|
||||
return window.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Window::Controller *Application::separateWindowForPeer(
|
||||
not_null<PeerData*> peer) const {
|
||||
for (const auto &[history, window] : _secondaryWindows) {
|
||||
if (history->peer == peer) {
|
||||
return window.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Window::Controller *Application::ensureSeparateWindowForPeer(
|
||||
not_null<PeerData*> peer,
|
||||
Window::Controller *Application::ensureSeparateWindowFor(
|
||||
Window::SeparateId id,
|
||||
MsgId showAtMsgId) {
|
||||
const auto activate = [&](not_null<Window::Controller*> window) {
|
||||
window->activate();
|
||||
return window;
|
||||
};
|
||||
|
||||
if (const auto existing = separateWindowForPeer(peer)) {
|
||||
existing->sessionController()->showPeerHistory(
|
||||
peer,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
showAtMsgId);
|
||||
if (const auto existing = separateWindowFor(id)) {
|
||||
if (id.thread && id.type == Window::SeparateType::Chat) {
|
||||
existing->sessionController()->showThread(
|
||||
id.thread,
|
||||
showAtMsgId,
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
}
|
||||
return activate(existing);
|
||||
}
|
||||
const auto result = _secondaryWindows.emplace(
|
||||
peer->owner().history(peer),
|
||||
std::make_unique<Window::Controller>(peer, showAtMsgId)
|
||||
|
||||
const auto result = _windows.emplace(
|
||||
id,
|
||||
std::make_unique<Window::Controller>(id, showAtMsgId)
|
||||
).first->second.get();
|
||||
processCreatedWindow(result);
|
||||
result->firstShow();
|
||||
@@ -1332,55 +1319,63 @@ Window::Controller *Application::ensureSeparateWindowForPeer(
|
||||
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->firstShow();
|
||||
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)) {
|
||||
Window::Controller *Application::windowFor(Window::SeparateId id) const {
|
||||
if (const auto separate = separateWindowFor(id)) {
|
||||
return separate;
|
||||
} else if (id && id.primary()) {
|
||||
return windowFor(not_null(id.account));
|
||||
}
|
||||
return activePrimaryWindow();
|
||||
}
|
||||
|
||||
Window::Controller *Application::windowForShowingHistory(
|
||||
not_null<PeerData*> peer) const {
|
||||
if (const auto separate = separateWindowFor(peer)) {
|
||||
return separate;
|
||||
}
|
||||
auto result = (Window::Controller*)nullptr;
|
||||
enumerateWindows([&](not_null<Window::Controller*> window) {
|
||||
if (const auto controller = window->sessionController()) {
|
||||
const auto current = controller->activeChatCurrent();
|
||||
if (const auto history = current.history()) {
|
||||
if (history->peer == peer) {
|
||||
result = window;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
Window::Controller *Application::windowForShowingForum(
|
||||
not_null<Data::Forum*> forum) const {
|
||||
const auto id = Window::SeparateId(
|
||||
Window::SeparateType::Forum,
|
||||
forum->history());
|
||||
if (const auto separate = separateWindowFor(id)) {
|
||||
return separate;
|
||||
}
|
||||
auto result = (Window::Controller*)nullptr;
|
||||
enumerateWindows([&](not_null<Window::Controller*> window) {
|
||||
if (const auto controller = window->sessionController()) {
|
||||
const auto current = controller->shownForum().current();
|
||||
if (forum == current) {
|
||||
result = window;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
Window::Controller *Application::findWindow(
|
||||
not_null<QWidget*> widget) const {
|
||||
const auto window = widget->window();
|
||||
if (_lastActiveWindow && _lastActiveWindow->widget() == window) {
|
||||
return _lastActiveWindow;
|
||||
}
|
||||
for (const auto &[account, primary] : _primaryWindows) {
|
||||
if (primary->widget() == window) {
|
||||
return primary.get();
|
||||
}
|
||||
}
|
||||
for (const auto &[history, secondary] : _secondaryWindows) {
|
||||
if (secondary->widget() == window) {
|
||||
return secondary.get();
|
||||
for (const auto &[id, controller] : _windows) {
|
||||
if (controller->widget() == window) {
|
||||
return controller.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -1392,10 +1387,11 @@ Window::Controller *Application::activeWindow() const {
|
||||
|
||||
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()) {
|
||||
for (const auto &[id, controller] : _windows) {
|
||||
if (id.primary()
|
||||
&& !_closingAsyncWindows.contains(controller.get())
|
||||
&& controller.get() != window
|
||||
&& controller->maybeSession()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1457,10 +1453,10 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
|
||||
: nullptr;
|
||||
const auto next = nextFromStack
|
||||
? nextFromStack
|
||||
: (_primaryWindows.front().second.get() != window)
|
||||
? _primaryWindows.front().second.get()
|
||||
: (_primaryWindows.back().second.get() != window)
|
||||
? _primaryWindows.back().second.get()
|
||||
: (_windows.front().second.get() != window)
|
||||
? _windows.front().second.get()
|
||||
: (_windows.back().second.get() != window)
|
||||
? _windows.back().second.get()
|
||||
: nullptr;
|
||||
Assert(next != window);
|
||||
|
||||
@@ -1481,20 +1477,12 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
|
||||
}
|
||||
}
|
||||
_closingAsyncWindows.remove(window);
|
||||
for (auto i = begin(_primaryWindows); i != end(_primaryWindows);) {
|
||||
for (auto i = begin(_windows); i != end(_windows);) {
|
||||
if (i->second.get() == window) {
|
||||
Assert(_lastActiveWindow != window);
|
||||
Assert(_lastActivePrimaryWindow != window);
|
||||
Assert(_windowInSettings != window);
|
||||
i = _primaryWindows.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for (auto i = begin(_secondaryWindows); i != end(_secondaryWindows);) {
|
||||
if (i->second.get() == window) {
|
||||
Assert(_lastActiveWindow != window);
|
||||
i = _secondaryWindows.erase(i);
|
||||
i = _windows.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
@@ -1502,36 +1490,34 @@ void Application::closeWindow(not_null<Window::Controller*> window) {
|
||||
const auto account = domain().started()
|
||||
? &domain().active()
|
||||
: nullptr;
|
||||
if (account && !_primaryWindows.contains(account) && _lastActiveWindow) {
|
||||
if (account
|
||||
&& !_windows.contains(Window::SeparateId(account))
|
||||
&& _lastActiveWindow) {
|
||||
domain().activate(&_lastActiveWindow->account());
|
||||
}
|
||||
}
|
||||
|
||||
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 (const auto session = window->sessionController()) {
|
||||
if (session->activeChatCurrent().peer() == peer) {
|
||||
session->showPeerHistory(
|
||||
window->singlePeer()->id,
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto window = windowFor(&peer->account())) {
|
||||
if (const auto primary = window->sessionController()) {
|
||||
if (primary->activeChatCurrent().peer() == peer) {
|
||||
primary->clearSectionStack();
|
||||
}
|
||||
if (const auto forum = primary->shownForum().current()) {
|
||||
if (peer->forum() == forum) {
|
||||
primary->closeForum();
|
||||
const auto closeOne = [&] {
|
||||
for (const auto &[id, window] : _windows) {
|
||||
if (id.thread && id.thread->peer() == peer) {
|
||||
closeWindow(window.get());
|
||||
return true;
|
||||
} else if (const auto controller = window->sessionController()) {
|
||||
if (controller->activeChatCurrent().peer() == peer) {
|
||||
controller->showByInitialId();
|
||||
}
|
||||
if (const auto forum = controller->shownForum().current()) {
|
||||
if (peer->forum() == forum) {
|
||||
controller->closeForum();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
while (closeOne()) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1737,11 +1723,8 @@ void Application::quitPreventFinished() {
|
||||
}
|
||||
|
||||
void Application::quitDelayed() {
|
||||
for (const auto &[account, window] : _primaryWindows) {
|
||||
window->widget()->hide();
|
||||
}
|
||||
for (const auto &[history, window] : _secondaryWindows) {
|
||||
window->widget()->hide();
|
||||
for (const auto &[id, controller] : _windows) {
|
||||
controller->widget()->hide();
|
||||
}
|
||||
if (!_private->quitTimer.isActive()) {
|
||||
_private->quitTimer.setCallback([] { Sandbox::QuitWhenStarted(); });
|
||||
|
Reference in New Issue
Block a user