Notifications management moved to AuthSession.

Also implemented Global::WorkMode() as an base::Variable.
This commit is contained in:
John Preston 2017-03-04 22:36:59 +03:00
parent b14ba398e6
commit 81790b2271
80 changed files with 1299 additions and 1152 deletions

View file

@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h" #include "auth_session.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "window/notifications_manager.h"
ApiWrap::ApiWrap(QObject *parent) : QObject(parent) ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
, _messageDataResolveDelayed(new SingleDelayedCall(this, "resolveMessageDatas")) { , _messageDataResolveDelayed(new SingleDelayedCall(this, "resolveMessageDatas")) {
@ -1016,7 +1017,7 @@ PeerData *ApiWrap::notifySettingReceived(MTPInputNotifyPeer notifyPeer, const MT
} }
} break; } break;
} }
App::wnd()->notifySettingGot(); AuthSession::Current().notifications()->checkDelayed();
return requestedPeer; return requestedPeer;
} }

View file

@ -203,15 +203,14 @@ namespace {
Media::Player::mixer()->stopAndClear(); Media::Player::mixer()->stopAndClear();
if (auto w = wnd()) { if (auto w = wnd()) {
w->tempDirDelete(Local::ClearManagerAll); w->tempDirDelete(Local::ClearManagerAll);
w->notifyClearFast();
w->setupIntro(); w->setupIntro();
} }
histories().clear();
Messenger::Instance().authSessionDestroy(); Messenger::Instance().authSessionDestroy();
Local::reset(); Local::reset();
Window::Theme::Background()->reset(); Window::Theme::Background()->reset();
cSetOtherOnline(0); cSetOtherOnline(0);
histories().clear();
globalNotifyAllPtr = UnknownNotifySettings; globalNotifyAllPtr = UnknownNotifySettings;
globalNotifyUsersPtr = UnknownNotifySettings; globalNotifyUsersPtr = UnknownNotifySettings;
globalNotifyChatsPtr = UnknownNotifySettings; globalNotifyChatsPtr = UnknownNotifySettings;
@ -2014,9 +2013,7 @@ namespace {
dependent->dependencyItemRemoved(item); dependent->dependencyItemRemoved(item);
} }
} }
if (auto manager = Window::Notifications::GetManager()) { AuthSession::Current().notifications()->clearFromItem(item);
manager->clearFromItem(item);
}
if (Global::started() && !App::quitting()) { if (Global::started() && !App::quitting()) {
Global::RefItemRemoved().notify(item, true); Global::RefItemRemoved().notify(item, true);
} }
@ -2038,13 +2035,13 @@ namespace {
::dependentItems.clear(); ::dependentItems.clear();
QVector<HistoryItem*> toDelete; QVector<HistoryItem*> toDelete;
for_const (HistoryItem *item, msgsData) { for_const (auto item, msgsData) {
if (item->detached()) { if (item->detached()) {
toDelete.push_back(item); toDelete.push_back(item);
} }
} }
for_const (const MsgsData &chMsgsData, channelMsgsData) { for_const (auto &chMsgsData, channelMsgsData) {
for_const (HistoryItem *item, chMsgsData) { for_const (auto item, chMsgsData) {
if (item->detached()) { if (item->detached()) {
toDelete.push_back(item); toDelete.push_back(item);
} }
@ -2052,8 +2049,8 @@ namespace {
} }
msgsData.clear(); msgsData.clear();
channelMsgsData.clear(); channelMsgsData.clear();
for (int32 i = 0, l = toDelete.size(); i < l; ++i) { for_const (auto item, toDelete) {
delete toDelete[i]; delete item;
} }
clearMousedItems(); clearMousedItems();

View file

@ -319,10 +319,6 @@ void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return; if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed); App::setLaunchState(App::QuitProcessed);
if (auto manager = Window::Notifications::GetManager()) {
manager->clearAllFast();
}
if (_messengerInstance) { if (_messengerInstance) {
Messenger::Instance().prepareToDestroy(); Messenger::Instance().prepareToDestroy();
_messengerInstance.reset(); _messengerInstance.reset();

View file

@ -21,18 +21,41 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h" #include "auth_session.h"
#include "messenger.h" #include "messenger.h"
#include "storage/file_download.h"
#include "window/notifications_manager.h"
AuthSession::AuthSession(UserId userId) : _userId(userId) { AuthSession::AuthSession(UserId userId)
: _userId(userId)
, _downloader(std::make_unique<Storage::Downloader>())
, _notifications(std::make_unique<Window::Notifications::System>(this)) {
t_assert(_userId != 0); t_assert(_userId != 0);
} }
AuthSession *AuthSession::Current() { bool AuthSession::Exists() {
return Messenger::Instance().authSession(); return (Messenger::Instance().authSession() != nullptr);
}
AuthSession &AuthSession::Current() {
auto result = Messenger::Instance().authSession();
t_assert(result != nullptr);
return *result;
} }
UserData *AuthSession::CurrentUser() { UserData *AuthSession::CurrentUser() {
if (auto userId = CurrentUserId()) { return App::user(CurrentUserId());
return App::user(userId);
}
return nullptr;
} }
base::Observable<void> &AuthSession::CurrentDownloaderTaskFinished() {
return Current().downloader()->taskFinished();
}
bool AuthSession::validateSelf(const MTPUser &user) {
if (user.type() != mtpc_user || !user.c_user().is_self() || user.c_user().vid.v != userId()) {
LOG(("Auth Error: wrong self user received."));
App::logOutDelayed();
return false;
}
return true;
}
AuthSession::~AuthSession() = default;

View file

@ -20,29 +20,55 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
class AuthSession { namespace Storage {
class Downloader;
} // namespace Storage
namespace Window {
namespace Notifications {
class System;
} // namespace Notifications
} // namespace Window
class AuthSession final {
public: public:
AuthSession(UserId userId); AuthSession(UserId userId);
AuthSession(const AuthSession &other) = delete; AuthSession(const AuthSession &other) = delete;
AuthSession &operator=(const AuthSession &other) = delete; AuthSession &operator=(const AuthSession &other) = delete;
static AuthSession *Current(); static bool Exists();
static AuthSession &Current();
static UserId CurrentUserId() { static UserId CurrentUserId() {
auto current = Current(); return Current().userId();
return current ? current->userId() : 0;
} }
static PeerId CurrentUserPeerId() { static PeerId CurrentUserPeerId() {
auto userId = CurrentUserId(); return peerFromUser(CurrentUserId());
return userId ? peerFromUser(userId) : 0;
} }
static UserData *CurrentUser(); static UserData *CurrentUser();
UserId userId() const { UserId userId() const {
return _userId; return _userId;
} }
bool validateSelf(const MTPUser &user);
Storage::Downloader *downloader() {
return _downloader.get();
}
static base::Observable<void> &CurrentDownloaderTaskFinished();
Window::Notifications::System *notifications() {
return _notifications.get();
}
~AuthSession();
private: private:
UserId _userId = 0; UserId _userId = 0;
const std::unique_ptr<Storage::Downloader> _downloader;
const std::unique_ptr<Window::Notifications::System> _notifications;
}; };

View file

@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "auth_session.h"
AddContactBox::AddContactBox(QWidget*, QString fname, QString lname, QString phone) AddContactBox::AddContactBox(QWidget*, QString fname, QString lname, QString phone)
: _first(this, st::defaultInputField, lang(lng_signup_firstname), fname) : _first(this, st::defaultInputField, lang(lng_signup_firstname), fname)
@ -1119,7 +1120,7 @@ void RevokePublicLinkBox::prepare() {
addButton(lang(lng_cancel), [this] { closeBox(); }); addButton(lang(lng_cancel), [this] { closeBox(); });
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
updateMaxHeight(); updateMaxHeight();
} }

View file

@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_overview.h" #include "styles/style_overview.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "ui/effects/round_checkbox.h" #include "ui/effects/round_checkbox.h"
#include "auth_session.h"
BackgroundBox::BackgroundBox(QWidget*) { BackgroundBox::BackgroundBox(QWidget*) {
} }
@ -63,7 +64,7 @@ BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
updateWallpapers(); updateWallpapers();
} }
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) { subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
if (update.paletteChanged()) { if (update.paletteChanged()) {
_check->invalidateCache(); _check->invalidateCache();

View file

@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include "auth_session.h"
TextParseOptions _confirmBoxTextOptions = { TextParseOptions _confirmBoxTextOptions = {
TextParseLinks | TextParseMultiline | TextParseRichText, // flags TextParseLinks | TextParseMultiline | TextParseRichText, // flags
@ -569,7 +570,7 @@ ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, const MTPChat
if (!location.isNull()) { if (!location.isNull()) {
_photo = ImagePtr(location); _photo = ImagePtr(location);
if (!_photo->loaded()) { if (!_photo->loaded()) {
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
_photo->load(); _photo->load();
} }
} }

View file

@ -43,6 +43,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "observer_peer.h" #include "observer_peer.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "auth_session.h" #include "auth_session.h"
#include "storage/file_download.h"
QString PeerFloodErrorText(PeerFloodType type) { QString PeerFloodErrorText(PeerFloodType type) {
auto link = textcmdLink(CreateInternalLinkHttps(qsl("spambot")), lang(lng_cant_more_info)); auto link = textcmdLink(CreateInternalLinkHttps(qsl("spambot")), lang(lng_cant_more_info));
@ -623,7 +624,7 @@ ContactsBox::Inner::Inner(QWidget *parent, UserData *bot) : TWidget(parent)
} }
void ContactsBox::Inner::init() { void ContactsBox::Inner::init() {
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
connect(_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged())); connect(_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged()));
@ -848,7 +849,7 @@ void ContactsBox::Inner::loadProfilePhotos() {
auto yFrom = _visibleTop - _rowsTop; auto yFrom = _visibleTop - _rowsTop;
auto yTo = yFrom + (_visibleBottom - _visibleTop) * 5; auto yTo = yFrom + (_visibleBottom - _visibleTop) * 5;
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
if (yTo < 0) return; if (yTo < 0) return;
if (yFrom < 0) yFrom = 0; if (yFrom < 0) yFrom = 0;

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include "lang.h" #include "lang.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "auth_session.h"
LocalStorageBox::LocalStorageBox(QWidget *parent) LocalStorageBox::LocalStorageBox(QWidget *parent)
: _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) { : _clear(this, lang(lng_local_storage_clear), st::boxLinkButton) {
@ -40,7 +41,7 @@ void LocalStorageBox::prepare() {
connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int))); connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int)));
connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int))); connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int)));
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
updateControls(); updateControls();

View file

@ -31,7 +31,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "auth_session.h"
#include "storage/file_download.h"
MembersAddButton::MembersAddButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple) MembersAddButton::MembersAddButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
, _st(st) { , _st(st) {
@ -132,7 +133,7 @@ MembersBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter fi
, _kickWidth(st::normalFont->width(_kickText)) , _kickWidth(st::normalFont->width(_kickText))
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right()) , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right())
, _about(_aboutWidth) { , _about(_aboutWidth) {
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)));
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*))); connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
@ -341,7 +342,7 @@ void MembersBox::Inner::loadProfilePhotos() {
auto yFrom = _visibleTop; auto yFrom = _visibleTop;
auto yTo = yFrom + (_visibleBottom - _visibleTop) * 5; auto yTo = yFrom + (_visibleBottom - _visibleTop) * 5;
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
if (yTo < 0) return; if (yTo < 0) return;
if (yFrom < 0) yFrom = 0; if (yFrom < 0) yFrom = 0;

View file

@ -28,11 +28,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_window.h" #include "styles/style_window.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include "auth_session.h"
#include "window/notifications_manager.h"
namespace { namespace {
constexpr int kMaxNotificationsCount = 5; constexpr int kMaxNotificationsCount = 5;
using ChangeType = Window::Notifications::ChangeType;
} // namespace } // namespace
class NotificationsBox::SampleWidget : public QWidget { class NotificationsBox::SampleWidget : public QWidget {
@ -190,7 +194,7 @@ void NotificationsBox::countChanged() {
if (currentCount() != Global::NotificationsCount()) { if (currentCount() != Global::NotificationsCount()) {
Global::SetNotificationsCount(currentCount()); Global::SetNotificationsCount(currentCount());
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::MaxCount); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::MaxCount);
Local::writeUserSettings(); Local::writeUserSettings();
} }
} }
@ -347,7 +351,7 @@ void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) {
_isOverCorner = true; _isOverCorner = true;
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
Global::SetNotificationsDemoIsShown(true); Global::SetNotificationsDemoIsShown(true);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::DemoIsShown);
} }
_overCorner = corner; _overCorner = corner;
@ -382,7 +386,7 @@ void NotificationsBox::clearOverCorner() {
_isOverCorner = false; _isOverCorner = false;
setCursor(style::cur_default); setCursor(style::cur_default);
Global::SetNotificationsDemoIsShown(false); Global::SetNotificationsDemoIsShown(false);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::DemoIsShown);
for_const (auto &samples, _cornerSamples) { for_const (auto &samples, _cornerSamples) {
for_const (auto widget, samples) { for_const (auto widget, samples) {
@ -409,7 +413,7 @@ void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) {
if (_chosenCorner != Global::NotificationsCorner()) { if (_chosenCorner != Global::NotificationsCorner()) {
Global::SetNotificationsCorner(_chosenCorner); Global::SetNotificationsCorner(_chosenCorner);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::Corner); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::Corner);
Local::writeUserSettings(); Local::writeUserSettings();
} }
} }

View file

@ -294,7 +294,7 @@ ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallbac
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update); notifyPeerUpdated(update);
})); }));
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) { subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
if (update.paletteChanged()) { if (update.paletteChanged()) {
@ -435,7 +435,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
yFrom *= _columnCount; yFrom *= _columnCount;
yTo *= _columnCount; yTo *= _columnCount;
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
if (!_chatsIndexed->isEmpty()) { if (!_chatsIndexed->isEmpty()) {
auto i = _chatsIndexed->cfind(yFrom, _rowHeight); auto i = _chatsIndexed->cfind(yFrom, _rowHeight);
@ -953,7 +953,7 @@ void shareGameScoreByHash(const QString &hash) {
} }
auto hashDataInts = reinterpret_cast<int32*>(hashData.data()); auto hashDataInts = reinterpret_cast<int32*>(hashData.data());
if (hashDataInts[0] != AuthSession::CurrentUserId()) { if (!AuthSession::Exists() || hashDataInts[0] != AuthSession::CurrentUserId()) {
Ui::show(Box<InformBox>(lang(lng_share_wrong_user))); Ui::show(Box<InformBox>(lang(lng_share_wrong_user)));
return; return;
} }

View file

@ -35,6 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/effects/slide_animation.h" #include "ui/effects/slide_animation.h"
#include "ui/widgets/discrete_sliders.h" #include "ui/widgets/discrete_sliders.h"
#include "auth_session.h"
namespace { namespace {
@ -576,7 +577,7 @@ StickersBox::Inner::Inner(QWidget *parent, const Stickers::Order &archivedIds) :
} }
void StickersBox::Inner::setup() { void StickersBox::Inner::setup() {
subscribe(FileDownload::ImageLoaded(), [this] { subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
update(); update();
readVisibleSets(); readVisibleSets();
}); });

View file

@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_stickers.h" #include "styles/style_stickers.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "auth_session.h"
StickerSetBox::StickerSetBox(QWidget*, const MTPInputStickerSet &set) StickerSetBox::StickerSetBox(QWidget*, const MTPInputStickerSet &set)
: _set(set) { : _set(set) {
@ -109,7 +110,7 @@ StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : TW
MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&Inner::gotSet), rpcFail(&Inner::failedSet)); MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&Inner::gotSet), rpcFail(&Inner::failedSet));
App::main()->updateStickers(); App::main()->updateStickers();
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
setMouseTracking(true); setMouseTracking(true);

View file

@ -176,7 +176,7 @@ struct vtable_once_impl<Lambda, false, Return, Args...> : public vtable_base<Ret
vtable_once_impl() : Parent( vtable_once_impl() : Parent(
&bad_construct_copy, &bad_construct_copy,
&vtable_once_impl::construct_move_other_method, &vtable_once_impl::construct_move_other_method,
&bad_const_call<Args...>, &bad_const_call<Return, Args...>,
&vtable_once_impl::call_method, &vtable_once_impl::call_method,
&vtable_once_impl::destruct_method) { &vtable_once_impl::destruct_method) {
} }

View file

@ -376,7 +376,7 @@ public:
void setForced(parameter_type<Type> newValue, bool sync = false) { void setForced(parameter_type<Type> newValue, bool sync = false) {
_value = newValue; _value = newValue;
_observable.notify(_value, sync); changed().notify(_value, sync);
} }
void set(parameter_type<Type> newValue, bool sync = false) { void set(parameter_type<Type> newValue, bool sync = false) {
@ -388,16 +388,16 @@ public:
template <typename Callback> template <typename Callback>
void process(Callback callback, bool sync = false) { void process(Callback callback, bool sync = false) {
callback(_value); callback(_value);
_observable.notify(_value, sync); changed().notify(_value, sync);
} }
Observable<Type> &observable() { Observable<Type> &changed() {
return _observable; return _changed;
} }
private: private:
Type _value; Type _value;
Observable<Type> _observable; Observable<Type> _changed;
}; };
@ -416,12 +416,12 @@ protected:
template <typename Type, typename Lambda> template <typename Type, typename Lambda>
int subscribe(base::Variable<Type> &variable, Lambda &&handler) { int subscribe(base::Variable<Type> &variable, Lambda &&handler) {
return subscribe(variable.observable(), std::forward<Lambda>(handler)); return subscribe(variable.changed(), std::forward<Lambda>(handler));
} }
template <typename Type, typename Lambda> template <typename Type, typename Lambda>
int subscribe(base::Variable<Type> *variable, Lambda &&handler) { int subscribe(base::Variable<Type> *variable, Lambda &&handler) {
return subscribe(variable->observable(), std::forward<Lambda>(handler)); return subscribe(variable->changed(), std::forward<Lambda>(handler));
} }
void unsubscribe(int index) { void unsubscribe(int index) {

View file

@ -20,30 +20,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#include "core/task_queue.h" #include "core/task_queue.h"
#include <thread>
#include <condition_variable>
namespace base { namespace base {
namespace { namespace {
auto MainThreadId = QThread::currentThreadId(); auto MainThreadId = std::this_thread::get_id();
const auto MaxThreadsCount = qMax(QThread::idealThreadCount(), 2); const auto MaxThreadsCount = qMax(std::thread::hardware_concurrency(), 2U);
template <typename Lambda>
class Thread : public QThread {
public:
Thread(Lambda code) : _code(std::move(code)) {
}
void run() override {
_code();
}
private:
Lambda _code;
};
template <typename Lambda>
object_ptr<Thread<Lambda>> MakeThread(Lambda code) {
return object_ptr<Thread<Lambda>>(std::move(code));
}
} // namespace } // namespace
@ -76,7 +60,7 @@ class TaskQueue::TaskThreadPool {
public: public:
TaskThreadPool(const Private &) { } TaskThreadPool(const Private &) { }
static const QSharedPointer<TaskThreadPool> &Instance(); static const std::shared_ptr<TaskThreadPool> &Instance();
void AddQueueTask(TaskQueue *queue, Task &&task); void AddQueueTask(TaskQueue *queue, Task &&task);
void RemoveQueue(TaskQueue *queue); void RemoveQueue(TaskQueue *queue);
@ -84,16 +68,15 @@ public:
~TaskThreadPool(); ~TaskThreadPool();
private: private:
void ThreadFunction(); void ThreadFunction();
std::vector<object_ptr<QThread>> threads_; std::vector<std::thread> threads_;
QMutex queues_mutex_; std::mutex queues_mutex_;
// queues_mutex_ must be locked when working with the list. // queues_mutex_ must be locked when working with the list.
TaskQueueList queue_list_; TaskQueueList queue_list_;
QWaitCondition thread_condition_; std::condition_variable thread_condition_;
bool stopped_ = false; bool stopped_ = false;
int tasks_in_process_ = 0; int tasks_in_process_ = 0;
int background_tasks_in_process_ = 0; int background_tasks_in_process_ = 0;
@ -192,7 +175,7 @@ TaskQueue *TaskQueue::TaskQueueList::TakeFirst(int list_index_) {
} }
void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) { void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) {
QMutexLocker lock(&queues_mutex_); std::unique_lock<std::mutex> lock(queues_mutex_);
queue->tasks_.push_back(std::move(task)); queue->tasks_.push_back(std::move(task));
auto list_was_empty = queue_list_.Empty(kAllQueuesList); auto list_was_empty = queue_list_.Empty(kAllQueuesList);
@ -207,18 +190,17 @@ void TaskQueue::TaskThreadPool::AddQueueTask(TaskQueue *queue, Task &&task) {
} }
} }
if (will_create_thread) { if (will_create_thread) {
threads_.push_back(MakeThread([this]() { threads_.emplace_back([this]() {
ThreadFunction(); ThreadFunction();
})); });
threads_.back()->start();
} else if (some_threads_are_vacant) { } else if (some_threads_are_vacant) {
t_assert(threads_count > tasks_in_process_); t_assert(threads_count > tasks_in_process_);
thread_condition_.wakeOne(); thread_condition_.notify_one();
} }
} }
void TaskQueue::TaskThreadPool::RemoveQueue(TaskQueue *queue) { void TaskQueue::TaskThreadPool::RemoveQueue(TaskQueue *queue) {
QMutexLocker lock(&queues_mutex_); std::unique_lock<std::mutex> lock(queues_mutex_);
if (queue_list_.IsInList(queue)) { if (queue_list_.IsInList(queue)) {
queue_list_.Unregister(queue); queue_list_.Unregister(queue);
} }
@ -229,18 +211,18 @@ void TaskQueue::TaskThreadPool::RemoveQueue(TaskQueue *queue) {
TaskQueue::TaskThreadPool::~TaskThreadPool() { TaskQueue::TaskThreadPool::~TaskThreadPool() {
{ {
QMutexLocker lock(&queues_mutex_); std::unique_lock<std::mutex> lock(queues_mutex_);
queue_list_.Clear(); queue_list_.Clear();
stopped_ = true; stopped_ = true;
} }
thread_condition_.wakeAll(); thread_condition_.notify_all();
for (auto &thread : threads_) { for (auto &thread : threads_) {
thread->wait(); thread.join();
} }
} }
const QSharedPointer<TaskQueue::TaskThreadPool> &TaskQueue::TaskThreadPool::Instance() { // static const std::shared_ptr<TaskQueue::TaskThreadPool> &TaskQueue::TaskThreadPool::Instance() { // static
static auto Pool = MakeShared<TaskThreadPool>(Private()); static auto Pool = std::make_shared<TaskThreadPool>(Private());
return Pool; return Pool;
} }
@ -259,7 +241,7 @@ void TaskQueue::TaskThreadPool::ThreadFunction() {
while (true) { while (true) {
Task task; Task task;
{ {
QMutexLocker lock(&queues_mutex_); std::unique_lock<std::mutex> lock(queues_mutex_);
// Finish the previous task processing. // Finish the previous task processing.
if (task_was_processed) { if (task_was_processed) {
@ -285,7 +267,7 @@ void TaskQueue::TaskThreadPool::ThreadFunction() {
if (stopped_) { if (stopped_) {
return; return;
} }
thread_condition_.wait(&queues_mutex_); thread_condition_.wait(lock);
} }
// Select a task we will be processing. // Select a task we will be processing.
@ -331,7 +313,7 @@ TaskQueue::TaskQueue(Type type, Priority priority)
TaskQueue::~TaskQueue() { TaskQueue::~TaskQueue() {
if (type_ != Type::Main && type_ != Type::Special) { if (type_ != Type::Main && type_ != Type::Special) {
if (auto thread_pool = weak_thread_pool_.toStrongRef()) { if (auto thread_pool = weak_thread_pool_.lock()) {
thread_pool->RemoveQueue(this); thread_pool->RemoveQueue(this);
} }
} }
@ -339,7 +321,7 @@ TaskQueue::~TaskQueue() {
void TaskQueue::Put(Task &&task) { void TaskQueue::Put(Task &&task) {
if (type_ == Type::Main) { if (type_ == Type::Main) {
QMutexLocker lock(&tasks_mutex_); std::unique_lock<std::mutex> lock(tasks_mutex_);
tasks_.push_back(std::move(task)); tasks_.push_back(std::move(task));
Sandbox::MainThreadTaskAdded(); Sandbox::MainThreadTaskAdded();
@ -350,14 +332,14 @@ void TaskQueue::Put(Task &&task) {
} }
void TaskQueue::ProcessMainTasks() { // static void TaskQueue::ProcessMainTasks() { // static
t_assert(QThread::currentThreadId() == MainThreadId); t_assert(std::this_thread::get_id() == MainThreadId);
while (ProcessOneMainTask()) { while (ProcessOneMainTask()) {
} }
} }
void TaskQueue::ProcessMainTasks(TimeMs max_time_spent) { // static void TaskQueue::ProcessMainTasks(TimeMs max_time_spent) { // static
t_assert(QThread::currentThreadId() == MainThreadId); t_assert(std::this_thread::get_id() == MainThreadId);
auto start_time = getms(); auto start_time = getms();
while (ProcessOneMainTask()) { while (ProcessOneMainTask()) {
@ -370,7 +352,7 @@ void TaskQueue::ProcessMainTasks(TimeMs max_time_spent) { // static
bool TaskQueue::ProcessOneMainTask() { // static bool TaskQueue::ProcessOneMainTask() { // static
Task task; Task task;
{ {
QMutexLocker lock(&Main().tasks_mutex_); std::unique_lock<std::mutex> lock(Main().tasks_mutex_);
auto &tasks = Main().tasks_; auto &tasks = Main().tasks_;
if (tasks.empty()) { if (tasks.empty()) {
return false; return false;
@ -386,7 +368,7 @@ bool TaskQueue::ProcessOneMainTask() { // static
bool TaskQueue::IsMyThread() const { bool TaskQueue::IsMyThread() const {
if (type_ == Type::Main) { if (type_ == Type::Main) {
return (QThread::currentThreadId() == MainThreadId); return (std::this_thread::get_id() == MainThreadId);
} }
t_assert(type_ != Type::Special); t_assert(type_ != Type::Special);
return false; return false;

View file

@ -20,6 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include <mutex>
#include <memory>
namespace base { namespace base {
using Task = lambda_once<void()>; using Task = lambda_once<void()>;
@ -70,11 +73,11 @@ private:
const Priority priority_; const Priority priority_;
std::deque<Task> tasks_; std::deque<Task> tasks_;
QMutex tasks_mutex_; // Only for the main queue. std::mutex tasks_mutex_; // Only for the main queue.
// Only for the other queues, not main. // Only for the other queues, not main.
class TaskThreadPool; class TaskThreadPool;
QWeakPointer<TaskThreadPool> weak_thread_pool_; std::weak_ptr<TaskThreadPool> weak_thread_pool_;
class TaskQueueList; class TaskQueueList;

View file

@ -45,6 +45,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "autoupdater.h" #include "autoupdater.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "auth_session.h" #include "auth_session.h"
#include "window/notifications_manager.h"
namespace { namespace {
@ -95,7 +96,7 @@ DialogsInner::DialogsInner(QWidget *parent, QWidget *main) : SplittedWidget(pare
connect(_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer())); connect(_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer()));
_cancelSearchInPeer->hide(); _cancelSearchInPeer->hide();
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) { subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item); itemRemoved(item);
}); });
@ -999,7 +1000,7 @@ void DialogsInner::removeDialog(History *history) {
if (_dialogsImportant) { if (_dialogsImportant) {
history->removeFromChatList(Dialogs::Mode::Important, _dialogsImportant.get()); history->removeFromChatList(Dialogs::Mode::Important, _dialogsImportant.get());
} }
if (App::wnd()) App::wnd()->notifyClear(history); AuthSession::Current().notifications()->clearFromHistory(history);
if (_contacts->contains(history->peer->id)) { if (_contacts->contains(history->peer->id)) {
if (!_contactsNoDialogs->contains(history->peer->id)) { if (!_contactsNoDialogs->contains(history->peer->id)) {
_contactsNoDialogs->addByName(history); _contactsNoDialogs->addByName(history);
@ -1889,7 +1890,7 @@ void DialogsInner::loadPeerPhotos() {
auto yFrom = _visibleTop; auto yFrom = _visibleTop;
auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1); auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1);
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
if (_state == DefaultState) { if (_state == DefaultState) {
auto otherStart = shownDialogs()->size() * st::dialogsRowHeight; auto otherStart = shownDialogs()->size() * st::dialogsRowHeight;
if (yFrom < otherStart) { if (yFrom < otherStart) {

View file

@ -686,7 +686,6 @@ struct Data {
int NotificationsCount = 3; int NotificationsCount = 3;
Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight; Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight;
bool NotificationsDemoIsShown = false; bool NotificationsDemoIsShown = false;
base::Observable<Notify::ChangeType> NotifySettingsChanged;
DBIConnectionType ConnectionType = dbictAuto; DBIConnectionType ConnectionType = dbictAuto;
bool TryIPv6 = (cPlatform() == dbipWindows) ? false : true; bool TryIPv6 = (cPlatform() == dbipWindows) ? false : true;
@ -699,6 +698,8 @@ struct Data {
bool LocalPasscode = false; bool LocalPasscode = false;
base::Observable<void> LocalPasscodeChanged; base::Observable<void> LocalPasscodeChanged;
base::Variable<DBIWorkMode> WorkMode = { dbiwmWindowAndTray };
base::Observable<HistoryItem*> ItemRemoved; base::Observable<HistoryItem*> ItemRemoved;
base::Observable<void> UnreadCounterUpdate; base::Observable<void> UnreadCounterUpdate;
base::Observable<void> PeerChooseCancel; base::Observable<void> PeerChooseCancel;
@ -807,7 +808,6 @@ DefineVar(Global, bool, NativeNotifications);
DefineVar(Global, int, NotificationsCount); DefineVar(Global, int, NotificationsCount);
DefineVar(Global, Notify::ScreenCorner, NotificationsCorner); DefineVar(Global, Notify::ScreenCorner, NotificationsCorner);
DefineVar(Global, bool, NotificationsDemoIsShown); DefineVar(Global, bool, NotificationsDemoIsShown);
DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DefineVar(Global, DBIConnectionType, ConnectionType); DefineVar(Global, DBIConnectionType, ConnectionType);
DefineVar(Global, bool, TryIPv6); DefineVar(Global, bool, TryIPv6);
@ -820,6 +820,8 @@ DefineVar(Global, int, AutoLock);
DefineVar(Global, bool, LocalPasscode); DefineVar(Global, bool, LocalPasscode);
DefineRefVar(Global, base::Observable<void>, LocalPasscodeChanged); DefineRefVar(Global, base::Observable<void>, LocalPasscodeChanged);
DefineRefVar(Global, base::Variable<DBIWorkMode>, WorkMode);
DefineRefVar(Global, base::Observable<HistoryItem*>, ItemRemoved); DefineRefVar(Global, base::Observable<HistoryItem*>, ItemRemoved);
DefineRefVar(Global, base::Observable<void>, UnreadCounterUpdate); DefineRefVar(Global, base::Observable<void>, UnreadCounterUpdate);
DefineRefVar(Global, base::Observable<void>, PeerChooseCancel); DefineRefVar(Global, base::Observable<void>, PeerChooseCancel);

View file

@ -187,15 +187,6 @@ void historyMuteUpdated(History *history);
void handlePendingHistoryUpdate(); void handlePendingHistoryUpdate();
void unreadCounterUpdated(); void unreadCounterUpdated();
enum class ChangeType {
SoundEnabled,
IncludeMuted,
DesktopEnabled,
ViewParams,
MaxCount,
Corner,
DemoIsShown,
};
enum class ScreenCorner { enum class ScreenCorner {
TopLeft = 0, TopLeft = 0,
@ -214,14 +205,6 @@ inline bool IsTopCorner(ScreenCorner corner) {
} // namespace Notify } // namespace Notify
namespace base {
template <>
struct custom_is_fast_copy_type<Notify::ChangeType> : public std::true_type {
};
} // namespace base
#define DeclareReadOnlyVar(Type, Name) const Type &Name(); #define DeclareReadOnlyVar(Type, Name) const Type &Name();
#define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \ #define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \
Type &Ref##Name(); Type &Ref##Name();
@ -395,7 +378,6 @@ DeclareVar(bool, NativeNotifications);
DeclareVar(int, NotificationsCount); DeclareVar(int, NotificationsCount);
DeclareVar(Notify::ScreenCorner, NotificationsCorner); DeclareVar(Notify::ScreenCorner, NotificationsCorner);
DeclareVar(bool, NotificationsDemoIsShown); DeclareVar(bool, NotificationsDemoIsShown);
DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DeclareVar(DBIConnectionType, ConnectionType); DeclareVar(DBIConnectionType, ConnectionType);
DeclareVar(bool, TryIPv6); DeclareVar(bool, TryIPv6);
@ -408,6 +390,8 @@ DeclareVar(int, AutoLock);
DeclareVar(bool, LocalPasscode); DeclareVar(bool, LocalPasscode);
DeclareRefVar(base::Observable<void>, LocalPasscodeChanged); DeclareRefVar(base::Observable<void>, LocalPasscodeChanged);
DeclareRefVar(base::Variable<DBIWorkMode>, WorkMode);
DeclareRefVar(base::Observable<HistoryItem*>, ItemRemoved); DeclareRefVar(base::Observable<HistoryItem*>, ItemRemoved);
DeclareRefVar(base::Observable<void>, UnreadCounterUpdate); DeclareRefVar(base::Observable<void>, UnreadCounterUpdate);
DeclareRefVar(base::Observable<void>, PeerChooseCancel); DeclareRefVar(base::Observable<void>, PeerChooseCancel);

View file

@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/top_bar_widget.h" #include "window/top_bar_widget.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "auth_session.h" #include "auth_session.h"
#include "window/notifications_manager.h"
namespace { namespace {
@ -1503,7 +1504,7 @@ MsgId History::inboxRead(MsgId upTo) {
} }
showFrom = nullptr; showFrom = nullptr;
App::wnd()->notifyClear(this); AuthSession::Current().notifications()->clearFromHistory(this);
return upTo; return upTo;
} }

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "structs.h" #include "structs.h"
#include "dialogs/dialogs_common.h" #include "dialogs/dialogs_common.h"
#include "ui/effects/send_action_animations.h" #include "ui/effects/send_action_animations.h"
#include "core/observer.h"
void historyInit(); void historyInit();

View file

@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_history.h" #include "styles/style_history.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_stickers.h" #include "styles/style_stickers.h"
#include "auth_session.h"
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent) FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
, _scroll(this, st::mentionScroll) { , _scroll(this, st::mentionScroll) {
@ -533,7 +534,7 @@ FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, Mentio
, _previewShown(false) { , _previewShown(false) {
_previewTimer.setSingleShot(true); _previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview())); connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
} }
void FieldAutocompleteInner::paintEvent(QPaintEvent *e) { void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {

View file

@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_history.h" #include "styles/style_history.h"
#include "window/notifications_manager.h"
namespace { namespace {
@ -2032,10 +2033,8 @@ bool HistoryService::updateDependent(bool force) {
} }
updateDependentText(); updateDependentText();
} }
if (force) { if (force && gotDependencyItem) {
if (gotDependencyItem && App::wnd()) { AuthSession::Current().notifications()->checkDelayed();
App::wnd()->notifySettingGot();
}
} }
return (dependent->msg || !dependent->msgId); return (dependent->msg || !dependent->msgId);
} }

View file

@ -61,6 +61,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "platform/platform_file_utilities.h" #include "platform/platform_file_utilities.h"
#include "auth_session.h" #include "auth_session.h"
#include "window/notifications_manager.h"
namespace { namespace {
@ -3130,7 +3131,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _topShadow(this, st::shadowFg) { , _topShadow(this, st::shadowFg) {
setAcceptDrops(true); setAcceptDrops(true);
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked())); connect(_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked()));
connect(_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide())); connect(_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide()));
@ -4341,7 +4342,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
if (_peer) { if (_peer) {
App::forgetMedia(); App::forgetMedia();
_serviceImageCacheSize = imageCacheSize(); _serviceImageCacheSize = imageCacheSize();
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
_history = App::history(_peer->id); _history = App::history(_peer->id);
_migrated = _peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0; _migrated = _peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0;
@ -4797,7 +4798,7 @@ void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
return; return;
} }
} }
App::wnd()->notifySchedule(history, item); AuthSession::Current().notifications()->schedule(history, item);
history->setUnreadCount(history->unreadCount() + 1); history->setUnreadCount(history->unreadCount() + 1);
} }
@ -6803,8 +6804,6 @@ void HistoryWidget::sendFileConfirmed(const FileLoadResultPtr &file) {
} }
void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) { void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) {
if (!AuthSession::Current()) return;
if (auto item = App::histItemById(newId)) { if (auto item = App::histItemById(newId)) {
uint64 randomId = rand_value<uint64>(); uint64 randomId = rand_value<uint64>();
App::historyRegRandom(randomId, newId); App::historyRegRandom(randomId, newId);
@ -6853,8 +6852,6 @@ namespace {
} }
void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) { void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) {
if (!AuthSession::Current()) return;
if (auto item = dynamic_cast<HistoryMessage*>(App::histItemById(newId))) { if (auto item = dynamic_cast<HistoryMessage*>(App::histItemById(newId))) {
auto media = item->getMedia(); auto media = item->getMedia();
if (auto document = media ? media->getDocument() : nullptr) { if (auto document = media ? media->getDocument() : nullptr) {
@ -6881,8 +6878,6 @@ void HistoryWidget::onDocumentUploaded(const FullMsgId &newId, bool silent, cons
} }
void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb) { void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb) {
if (!AuthSession::Current()) return;
if (auto item = dynamic_cast<HistoryMessage*>(App::histItemById(newId))) { if (auto item = dynamic_cast<HistoryMessage*>(App::histItemById(newId))) {
auto media = item->getMedia(); auto media = item->getMedia();
if (auto document = media ? media->getDocument() : nullptr) { if (auto document = media ? media->getDocument() : nullptr) {
@ -6909,8 +6904,6 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, bool silent,
} }
void HistoryWidget::onPhotoProgress(const FullMsgId &newId) { void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
if (!AuthSession::Current()) return;
if (auto item = App::histItemById(newId)) { if (auto item = App::histItemById(newId)) {
auto photo = (item->getMedia() && item->getMedia()->type() == MediaTypePhoto) ? static_cast<HistoryPhoto*>(item->getMedia())->photo() : nullptr; auto photo = (item->getMedia() && item->getMedia()->type() == MediaTypePhoto) ? static_cast<HistoryPhoto*>(item->getMedia())->photo() : nullptr;
if (!item->isPost()) { if (!item->isPost()) {
@ -6921,8 +6914,6 @@ void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
} }
void HistoryWidget::onDocumentProgress(const FullMsgId &newId) { void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
if (!AuthSession::Current()) return;
if (auto item = App::histItemById(newId)) { if (auto item = App::histItemById(newId)) {
auto media = item->getMedia(); auto media = item->getMedia();
auto document = media ? media->getDocument() : nullptr; auto document = media ? media->getDocument() : nullptr;
@ -6934,8 +6925,6 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
} }
void HistoryWidget::onPhotoFailed(const FullMsgId &newId) { void HistoryWidget::onPhotoFailed(const FullMsgId &newId) {
if (!AuthSession::Current()) return;
HistoryItem *item = App::histItemById(newId); HistoryItem *item = App::histItemById(newId);
if (item) { if (item) {
if (!item->isPost()) { if (!item->isPost()) {
@ -6946,8 +6935,6 @@ void HistoryWidget::onPhotoFailed(const FullMsgId &newId) {
} }
void HistoryWidget::onDocumentFailed(const FullMsgId &newId) { void HistoryWidget::onDocumentFailed(const FullMsgId &newId) {
if (!AuthSession::Current()) return;
if (auto item = App::histItemById(newId)) { if (auto item = App::histItemById(newId)) {
auto media = item->getMedia(); auto media = item->getMedia();
auto document = media ? media->getDocument() : nullptr; auto document = media ? media->getDocument() : nullptr;

View file

@ -425,6 +425,15 @@ QString Widget::Step::nextButtonText() const {
} }
void Widget::Step::finish(const MTPUser &user, QImage photo) { void Widget::Step::finish(const MTPUser &user, QImage photo) {
if (user.type() != mtpc_user || !user.c_user().is_self()) {
// No idea what to do here.
// We could've reset intro and MTP, but this really should not happen.
Ui::show(Box<InformBox>("Internal error: bad user.is_self() after sign in."));
return;
}
Messenger::Instance().authSessionCreate(user.c_user().vid.v);
App::wnd()->setupMain(&user); App::wnd()->setupMain(&user);
// "this" is already deleted here by creating the main widget. // "this" is already deleted here by creating the main widget.

View file

@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_stickers.h" #include "styles/style_stickers.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "window/window_main_menu.h" #include "window/window_main_menu.h"
#include "auth_session.h"
namespace { namespace {
@ -720,7 +721,7 @@ LayerStackWidget::~LayerStackWidget() {
MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent) MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent)
, _emojiSize(Ui::Emoji::Size(Ui::Emoji::Index() + 1) / cIntRetinaFactor()) { , _emojiSize(Ui::Emoji::Size(Ui::Emoji::Index() + 1) / cIntRetinaFactor()) {
setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TransparentForMouseEvents);
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
} }
void MediaPreviewWidget::paintEvent(QPaintEvent *e) { void MediaPreviewWidget::paintEvent(QPaintEvent *e) {

View file

@ -63,6 +63,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mtproto/dc_options.h" #include "mtproto/dc_options.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "auth_session.h" #include "auth_session.h"
#include "window/notifications_manager.h"
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr) StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
, _memento(std::move(memento)) { , _memento(std::move(memento)) {
@ -810,7 +811,6 @@ void MainWidget::deleteHistoryPart(DeleteHistoryRequest request, const MTPmessag
} }
int32 offset = d.voffset.v; int32 offset = d.voffset.v;
if (!AuthSession::Current()) return;
if (offset <= 0) { if (offset <= 0) {
cRefReportSpamStatuses().remove(peer->id); cRefReportSpamStatuses().remove(peer->id);
Local::writeReportSpamStatuses(); Local::writeReportSpamStatuses();
@ -909,7 +909,6 @@ void MainWidget::deleteAllFromUserPart(DeleteAllFromUserParams params, const MTP
} }
int32 offset = d.voffset.v; int32 offset = d.voffset.v;
if (!AuthSession::Current()) return;
if (offset > 0) { if (offset > 0) {
MTP::send(MTPchannels_DeleteUserHistory(params.channel->inputChannel, params.from->inputUser), rpcDone(&MainWidget::deleteAllFromUserPart, params)); MTP::send(MTPchannels_DeleteUserHistory(params.channel->inputChannel, params.from->inputUser), rpcDone(&MainWidget::deleteAllFromUserPart, params));
} else if (History *h = App::historyLoaded(params.channel)) { } else if (History *h = App::historyLoaded(params.channel)) {
@ -1504,7 +1503,6 @@ void MainWidget::overviewLoaded(History *history, const MTPmessages_Messages &re
} }
void MainWidget::sendReadRequest(PeerData *peer, MsgId upTo) { void MainWidget::sendReadRequest(PeerData *peer, MsgId upTo) {
if (!AuthSession::Current()) return;
if (peer->isChannel()) { if (peer->isChannel()) {
_readRequests.insert(peer, qMakePair(MTP::send(MTPchannels_ReadHistory(peer->asChannel()->inputChannel, MTP_int(upTo)), rpcDone(&MainWidget::channelReadDone, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo)); _readRequests.insert(peer, qMakePair(MTP::send(MTPchannels_ReadHistory(peer->asChannel()->inputChannel, MTP_int(upTo)), rpcDone(&MainWidget::channelReadDone, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo));
} else { } else {
@ -2106,8 +2104,6 @@ void MainWidget::fillPeerMenu(PeerData *peer, base::lambda<QAction*(const QStrin
} }
void MainWidget::onViewsIncrement() { void MainWidget::onViewsIncrement() {
if (!App::main() || !AuthSession::Current()) return;
for (ViewsIncrement::iterator i = _viewsToIncrement.begin(); i != _viewsToIncrement.cend();) { for (ViewsIncrement::iterator i = _viewsToIncrement.begin(); i != _viewsToIncrement.cend();) {
if (_viewsIncrementRequests.contains(i.key())) { if (_viewsIncrementRequests.contains(i.key())) {
++i; ++i;
@ -3628,8 +3624,6 @@ bool MainWidget::failDifference(const RPCError &error) {
} }
void MainWidget::onGetDifferenceTimeByPts() { void MainWidget::onGetDifferenceTimeByPts() {
if (!AuthSession::Current()) return;
auto now = getms(true), wait = 0LL; auto now = getms(true), wait = 0LL;
if (_getDifferenceTimeByPts) { if (_getDifferenceTimeByPts) {
if (_getDifferenceTimeByPts > now) { if (_getDifferenceTimeByPts > now) {
@ -3655,8 +3649,6 @@ void MainWidget::onGetDifferenceTimeByPts() {
} }
void MainWidget::onGetDifferenceTimeAfterFail() { void MainWidget::onGetDifferenceTimeAfterFail() {
if (!AuthSession::Current()) return;
auto now = getms(true), wait = 0LL; auto now = getms(true), wait = 0LL;
if (_getDifferenceTimeAfterFail) { if (_getDifferenceTimeAfterFail) {
if (_getDifferenceTimeAfterFail > now) { if (_getDifferenceTimeAfterFail > now) {
@ -3731,24 +3723,21 @@ void MainWidget::mtpPing() {
MTP::ping(); MTP::ping();
} }
void MainWidget::start(const MTPUser &user) { void MainWidget::start(const MTPUser *self) {
int32 uid = user.c_user().vid.v; if (!self) {
if (!uid) { MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())), rpcDone(&MainWidget::startWithSelf));
LOG(("MTP Error: incorrect user received"));
App::logOut();
return; return;
} }
if (AuthSession::CurrentUserId() != uid) { if (!AuthSession::Current().validateSelf(*self)) {
Messenger::Instance().authSessionCreate(uid); return;
Local::writeMtpData();
} }
Local::readSavedPeers(); Local::readSavedPeers();
cSetOtherOnline(0); cSetOtherOnline(0);
if (auto self = App::feedUsers(MTP_vector<MTPUser>(1, user))) { if (auto user = App::feedUsers(MTP_vector<MTPUser>(1, *self))) {
self->loadUserpic(); user->loadUserpic();
} }
MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState)); MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState));
update(); update();
@ -4039,12 +4028,13 @@ bool MainWidget::inviteImportFail(const RPCError &error) {
return true; return true;
} }
void MainWidget::startFull(const MTPVector<MTPUser> &users) { void MainWidget::startWithSelf(const MTPVector<MTPUser> &users) {
const auto &v(users.c_vector().v); auto &v = users.c_vector().v;
if (v.isEmpty() || v[0].type() != mtpc_user || !v[0].c_user().is_self()) { // wtf?.. if (v.isEmpty()) {
LOG(("Auth Error: self user not received."));
return App::logOutDelayed(); return App::logOutDelayed();
} }
start(v[0]); start(&v[0]);
} }
void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *h) { void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *h) {
@ -4100,7 +4090,7 @@ void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNoti
if (!h) h = App::history(updatePeer->id); if (!h) h = App::history(updatePeer->id);
int32 changeIn = 0; int32 changeIn = 0;
if (isNotifyMuted(setTo, &changeIn)) { if (isNotifyMuted(setTo, &changeIn)) {
App::wnd()->notifyClear(h); AuthSession::Current().notifications()->clearFromHistory(h);
h->setMute(true); h->setMute(true);
App::regMuted(updatePeer, changeIn); App::regMuted(updatePeer, changeIn);
} else { } else {
@ -4379,7 +4369,7 @@ void MainWidget::checkIdleFinish() {
} }
void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) { void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
if (end <= from || !AuthSession::Current()) return; if (end <= from) return;
App::wnd()->checkAutoLock(); App::wnd()->checkAutoLock();
@ -4638,8 +4628,6 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} }
void MainWidget::feedUpdate(const MTPUpdate &update) { void MainWidget::feedUpdate(const MTPUpdate &update) {
if (!AuthSession::Current()) return;
switch (update.type()) { switch (update.type()) {
case mtpc_updateNewMessage: { case mtpc_updateNewMessage: {
auto &d = update.c_updateNewMessage(); auto &d = update.c_updateNewMessage();

View file

@ -158,7 +158,7 @@ public:
void showAnimated(const QPixmap &bgAnimCache, bool back = false); void showAnimated(const QPixmap &bgAnimCache, bool back = false);
void start(const MTPUser &user); void start(const MTPUser *self = nullptr);
void checkStartUrl(); void checkStartUrl();
void openLocalUrl(const QString &str); void openLocalUrl(const QString &str);
@ -166,7 +166,6 @@ public:
void joinGroupByHash(const QString &hash); void joinGroupByHash(const QString &hash);
void stickersBox(const MTPInputStickerSet &set); void stickersBox(const MTPInputStickerSet &set);
void startFull(const MTPVector<MTPUser> &users);
bool started(); bool started();
void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0); void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0);
@ -518,6 +517,8 @@ private:
Window::SectionSlideParams prepareOverviewAnimation(); Window::SectionSlideParams prepareOverviewAnimation();
Window::SectionSlideParams prepareDialogsAnimation(); Window::SectionSlideParams prepareDialogsAnimation();
void startWithSelf(const MTPVector<MTPUser> &users);
void saveSectionInStack(); void saveSectionInStack();
bool _started = false; bool _started = false;

View file

@ -100,17 +100,6 @@ MainWindow::MainWindow() {
iconbig32 = iconbig256.scaledToWidth(32, Qt::SmoothTransformation); iconbig32 = iconbig256.scaledToWidth(32, Qt::SmoothTransformation);
iconbig64 = iconbig256.scaledToWidth(64, Qt::SmoothTransformation); iconbig64 = iconbig256.scaledToWidth(64, Qt::SmoothTransformation);
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType type) {
if (type == Notify::ChangeType::DesktopEnabled) {
updateTrayMenu();
notifyClear();
} else if (type == Notify::ChangeType::ViewParams) {
notifyUpdateAll();
} else if (type == Notify::ChangeType::IncludeMuted) {
Notify::unreadCounterUpdated();
}
});
resize(st::windowDefaultWidth, st::windowDefaultHeight); resize(st::windowDefaultWidth, st::windowDefaultHeight);
setLocale(QLocale(QLocale::English, QLocale::UnitedStates)); setLocale(QLocale(QLocale::English, QLocale::UnitedStates));
@ -118,8 +107,6 @@ MainWindow::MainWindow() {
_inactiveTimer.setSingleShot(true); _inactiveTimer.setSingleShot(true);
connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer())); connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer()));
connect(&_notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyShowNext()));
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock())); connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); }); subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); });
@ -156,7 +143,7 @@ void MainWindow::onStateChanged(Qt::WindowState state) {
updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout()); updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout());
psUpdateSysMenu(state); psUpdateSysMenu(state);
if (state == Qt::WindowMinimized && cWorkMode() == dbiwmTrayOnly) { if (state == Qt::WindowMinimized && Global::WorkMode().value() == dbiwmTrayOnly) {
App::wnd()->minimizeToTray(); App::wnd()->minimizeToTray();
} }
savePosition(state); savePosition(state);
@ -200,7 +187,7 @@ void MainWindow::firstShow() {
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true); trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true);
trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()))->setEnabled(true); trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()))->setEnabled(true);
} }
psUpdateWorkmode(); workmodeUpdated(Global::WorkMode().value());
psFirstShow(); psFirstShow();
updateTrayMenu(); updateTrayMenu();
@ -241,7 +228,7 @@ void MainWindow::clearPasscode() {
} else { } else {
_main->showAnimated(bg, true); _main->showAnimated(bg, true);
} }
notifyUpdateAll(); AuthSession::Current().notifications()->updateAll();
updateGlobalMenu(); updateGlobalMenu();
if (_main) { if (_main) {
@ -265,7 +252,9 @@ void MainWindow::setupPasscode() {
setInnerFocus(); setInnerFocus();
} }
_shouldLockAt = 0; _shouldLockAt = 0;
notifyUpdateAll(); if (AuthSession::Exists()) {
AuthSession::Current().notifications()->updateAll();
}
updateGlobalMenu(); updateGlobalMenu();
} }
@ -360,6 +349,9 @@ void MainWindow::setupMain(const MTPUser *self) {
auto bg = animated ? grabInner() : QPixmap(); auto bg = animated ? grabInner() : QPixmap();
clearWidgets(); clearWidgets();
t_assert(AuthSession::Exists());
_main.create(bodyWidget()); _main.create(bodyWidget());
_main->show(); _main->show();
updateControlsGeometry(); updateControlsGeometry();
@ -369,11 +361,7 @@ void MainWindow::setupMain(const MTPUser *self) {
} else { } else {
_main->activate(); _main->activate();
} }
if (self) { _main->start(self);
_main->start(*self);
} else {
MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())), _main->rpcDone(&MainWidget::startFull));
}
fixOrder(); fixOrder();
@ -573,7 +561,7 @@ bool MainWindow::doWeReadServerHistory() {
} }
void MainWindow::checkHistoryActivation() { void MainWindow::checkHistoryActivation() {
if (_main && AuthSession::Current() && doWeReadServerHistory()) { if (_main && doWeReadServerHistory()) {
_main->markActiveHistoryAsRead(); _main->markActiveHistoryAsRead();
} }
} }
@ -842,9 +830,9 @@ void MainWindow::toggleDisplayNotifyFromTray() {
} }
} }
Local::writeUserSettings(); Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DesktopEnabled); AuthSession::Current().notifications()->settingsChanged().notify(Window::Notifications::ChangeType::DesktopEnabled);
if (soundNotifyChanged) { if (soundNotifyChanged) {
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::SoundEnabled); AuthSession::Current().notifications()->settingsChanged().notify(Window::Notifications::ChangeType::SoundEnabled);
} }
} }
@ -854,7 +842,7 @@ void MainWindow::closeEvent(QCloseEvent *e) {
App::quit(); App::quit();
} else { } else {
e->ignore(); e->ignore();
if (!AuthSession::Current() || !Ui::hideWindowNoQuit()) { if (!AuthSession::Exists() || !Ui::hideWindowNoQuit()) {
App::quit(); App::quit();
} }
} }
@ -919,305 +907,10 @@ void MainWindow::onClearFailed(int task, void *manager) {
emit tempDirClearFailed(task); emit tempDirClearFailed(task);
} }
void MainWindow::notifySchedule(History *history, HistoryItem *item) {
if (App::quitting() || !history->currentNotification() || !App::api()) return;
PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0;
if (item->isSilent()) {
history->popNotification(item);
return;
}
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
if (haveSetting) {
if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
if (notifyByFrom) {
haveSetting = (item->from()->notify != UnknownNotifySettings);
if (haveSetting) {
if (notifyByFrom->notify != EmptyNotifySettings && notifyByFrom->notify->mute > unixtime()) {
history->popNotification(item);
return;
}
} else {
App::api()->requestNotifySetting(notifyByFrom);
}
} else {
history->popNotification(item);
return;
}
}
} else {
if (notifyByFrom && notifyByFrom->notify == UnknownNotifySettings) {
App::api()->requestNotifySetting(notifyByFrom);
}
App::api()->requestNotifySetting(history->peer);
}
if (!item->notificationReady()) {
haveSetting = false;
}
int delay = item->Has<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
auto ms = getms(true);
bool isOnline = _main->lastWasOnline(), otherNotOld = ((cOtherOnline() * 1000LL) + Global::OnlineCloudTimeout() > t * 1000LL);
bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - _main->lastSetOnline()) > t * 1000LL);
if (!isOnline && otherNotOld && otherLaterThanMe) {
delay = Global::NotifyCloudDelay();
} else if (cOtherOnline() >= t) {
delay = Global::NotifyDefaultDelay();
}
auto when = ms + delay;
_notifyWhenAlerts[history].insert(when, notifyByFrom);
if (Global::DesktopNotify() && !Platform::Notifications::SkipToast()) {
NotifyWhenMaps::iterator i = _notifyWhenMaps.find(history);
if (i == _notifyWhenMaps.end()) {
i = _notifyWhenMaps.insert(history, NotifyWhenMap());
}
if (i.value().constFind(item->id) == i.value().cend()) {
i.value().insert(item->id, when);
}
NotifyWaiters *addTo = haveSetting ? &_notifyWaiters : &_notifySettingWaiters;
NotifyWaiters::const_iterator it = addTo->constFind(history);
if (it == addTo->cend() || it->when > when) {
addTo->insert(history, NotifyWaiter(item->id, when, notifyByFrom));
}
}
if (haveSetting) {
if (!_notifyWaitTimer.isActive() || _notifyWaitTimer.remainingTime() > delay) {
_notifyWaitTimer.start(delay);
}
}
}
void MainWindow::notifyClear(History *history) {
if (!history) {
Window::Notifications::GetManager()->clearAll();
for (auto i = _notifyWhenMaps.cbegin(), e = _notifyWhenMaps.cend(); i != e; ++i) {
i.key()->clearNotifications();
}
_notifyWhenMaps.clear();
_notifyWhenAlerts.clear();
_notifyWaiters.clear();
_notifySettingWaiters.clear();
return;
}
Window::Notifications::GetManager()->clearFromHistory(history);
history->clearNotifications();
_notifyWhenMaps.remove(history);
_notifyWhenAlerts.remove(history);
_notifyWaiters.remove(history);
_notifySettingWaiters.remove(history);
_notifyWaitTimer.stop();
notifyShowNext();
}
void MainWindow::notifyClearFast() {
Window::Notifications::GetManager()->clearAllFast();
_notifyWhenMaps.clear();
_notifyWhenAlerts.clear();
_notifyWaiters.clear();
_notifySettingWaiters.clear();
}
void MainWindow::notifySettingGot() {
int32 t = unixtime();
for (NotifyWaiters::iterator i = _notifySettingWaiters.begin(); i != _notifySettingWaiters.end();) {
History *history = i.key();
bool loaded = false, muted = false;
if (history->peer->notify != UnknownNotifySettings) {
if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) {
loaded = true;
} else if (PeerData *from = i.value().notifyByFrom) {
if (from->notify != UnknownNotifySettings) {
if (from->notify == EmptyNotifySettings || from->notify->mute <= t) {
loaded = true;
} else {
loaded = muted = true;
}
}
} else {
loaded = muted = true;
}
}
if (loaded) {
if (HistoryItem *item = App::histItemById(history->channelId(), i.value().msg)) {
if (!item->notificationReady()) {
loaded = false;
}
} else {
muted = true;
}
}
if (loaded) {
if (!muted) {
_notifyWaiters.insert(i.key(), i.value());
}
i = _notifySettingWaiters.erase(i);
} else {
++i;
}
}
_notifyWaitTimer.stop();
notifyShowNext();
}
void MainWindow::notifyShowNext() {
if (App::quitting()) return;
auto ms = getms(true), nextAlert = 0LL;
bool alert = false;
int32 now = unixtime();
for (NotifyWhenAlerts::iterator i = _notifyWhenAlerts.begin(); i != _notifyWhenAlerts.end();) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
i.value().erase(i.value().begin());
}
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= now)) {
alert = true;
} else if (f == EmptyNotifySettings || (f != UnknownNotifySettings && f->mute <= now)) { // notify by from()
alert = true;
}
}
if (i.value().isEmpty()) {
i = _notifyWhenAlerts.erase(i);
} else {
if (!nextAlert || nextAlert > i.value().begin().key()) {
nextAlert = i.value().begin().key();
}
++i;
}
}
if (alert) {
psFlash();
App::playSound();
}
if (_notifyWaiters.isEmpty() || !Global::DesktopNotify() || Platform::Notifications::SkipToast()) {
if (nextAlert) {
_notifyWaitTimer.start(nextAlert - ms);
}
return;
}
while (true) {
auto next = 0LL;
HistoryItem *notifyItem = 0;
History *notifyHistory = 0;
for (NotifyWaiters::iterator i = _notifyWaiters.begin(); i != _notifyWaiters.end();) {
History *history = i.key();
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == _notifyWhenMaps.end()) {
history->clearNotifications();
i = _notifyWaiters.erase(i);
continue;
}
do {
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
i.value().msg = k.key();
i.value().when = k.value();
break;
}
history->skipNotification();
} while (history->currentNotification());
}
if (!history->currentNotification()) {
_notifyWhenMaps.remove(history);
i = _notifyWaiters.erase(i);
continue;
}
auto when = i.value().when;
if (!notifyItem || next > when) {
next = when;
notifyItem = history->currentNotification();
notifyHistory = history;
}
++i;
}
if (notifyItem) {
if (next > ms) {
if (nextAlert && nextAlert < next) {
next = nextAlert;
nextAlert = 0;
}
_notifyWaitTimer.start(next - ms);
break;
} else {
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
int32 fwdCount = 1;
auto ms = getms(true);
History *history = notifyItem->history();
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == _notifyWhenMaps.cend()) {
history->clearNotifications();
} else {
HistoryItem *nextNotify = 0;
do {
history->skipNotification();
if (!history->hasNotification()) {
break;
}
j.value().remove((fwd ? fwd : notifyItem)->id);
do {
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
nextNotify = history->currentNotification();
_notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0));
break;
}
history->skipNotification();
} while (history->hasNotification());
if (nextNotify) {
if (fwd) {
HistoryItem *nextFwd = nextNotify->Has<HistoryMessageForwarded>() ? nextNotify : nullptr;
if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) {
fwd = nextFwd;
++fwdCount;
} else {
nextNotify = 0;
}
} else {
nextNotify = 0;
}
}
} while (nextNotify);
}
Window::Notifications::GetManager()->showNotification(notifyItem, fwdCount);
if (!history->hasNotification()) {
_notifyWaiters.remove(history);
_notifyWhenMaps.remove(history);
continue;
}
}
} else {
break;
}
}
if (nextAlert) {
_notifyWaitTimer.start(nextAlert - ms);
}
}
void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
handler->onClick(button); handler->onClick(button);
} }
void MainWindow::notifyUpdateAll() {
Window::Notifications::GetManager()->updateAll();
}
QImage MainWindow::iconLarge() const { QImage MainWindow::iconLarge() const {
return iconbig256; return iconbig256;
} }
@ -1346,7 +1039,6 @@ void MainWindow::updateIsActiveHook() {
} }
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
notifyClearFast();
if (_clearManager) { if (_clearManager) {
_clearManager->stop(); _clearManager->stop();
_clearManager = nullptr; _clearManager = nullptr;

View file

@ -87,7 +87,7 @@ public:
void clearPasscode(); void clearPasscode();
void checkAutoLockIn(int msec); void checkAutoLockIn(int msec);
void setupIntro(); void setupIntro();
void setupMain(const MTPUser *user = 0); void setupMain(const MTPUser *user = nullptr);
void serviceNotification(const TextWithEntities &message, const MTPMessageMedia &media = MTP_messageMediaEmpty(), int32 date = 0, bool force = false); void serviceNotification(const TextWithEntities &message, const MTPMessageMedia &media = MTP_messageMediaEmpty(), int32 date = 0, bool force = false);
void serviceNotificationLocal(QString text); void serviceNotificationLocal(QString text);
void sendServiceHistoryRequest(); void sendServiceHistoryRequest();
@ -120,12 +120,6 @@ public:
TempDirState localStorageState(); TempDirState localStorageState();
void tempDirDelete(int task); void tempDirDelete(int task);
void notifySettingGot();
void notifySchedule(History *history, HistoryItem *item);
void notifyClear(History *history = 0);
void notifyClearFast();
void notifyUpdateAll();
QImage iconLarge() const; QImage iconLarge() const;
void sendPaths(); void sendPaths();
@ -183,8 +177,6 @@ public slots:
void onClearFinished(int task, void *manager); void onClearFinished(int task, void *manager);
void onClearFailed(int task, void *manager); void onClearFailed(int task, void *manager);
void notifyShowNext();
void onShowAddContact(); void onShowAddContact();
void onShowNewGroup(); void onShowNewGroup();
void onShowNewChannel(); void onShowNewChannel();
@ -240,28 +232,6 @@ private:
SingleTimer _autoLockTimer; SingleTimer _autoLockTimer;
TimeMs _shouldLockAt = 0; TimeMs _shouldLockAt = 0;
using NotifyWhenMap = QMap<MsgId, TimeMs>;
using NotifyWhenMaps = QMap<History*, NotifyWhenMap>;
NotifyWhenMaps _notifyWhenMaps;
struct NotifyWaiter {
NotifyWaiter(MsgId msg, TimeMs when, PeerData *notifyByFrom)
: msg(msg)
, when(when)
, notifyByFrom(notifyByFrom) {
}
MsgId msg;
TimeMs when;
PeerData *notifyByFrom;
};
using NotifyWaiters = QMap<History*, NotifyWaiter>;
NotifyWaiters _notifyWaiters;
NotifyWaiters _notifySettingWaiters;
SingleTimer _notifyWaitTimer;
using NotifyWhenAlert = QMap<TimeMs, PeerData*>;
using NotifyWhenAlerts = QMap<History*, NotifyWhenAlert>;
NotifyWhenAlerts _notifyWhenAlerts;
}; };
class PreLaunchWindow : public TWidget { class PreLaunchWindow : public TWidget {

View file

@ -36,6 +36,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/themes/window_theme_preview.h" #include "window/themes/window_theme_preview.h"
#include "core/task_queue.h" #include "core/task_queue.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "auth_session.h"
#include "messenger.h"
#include "storage/file_download.h"
namespace { namespace {
@ -86,10 +89,15 @@ MediaView::MediaView(QWidget*) : TWidget(nullptr)
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int))); connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
subscribe(FileDownload::ImageLoaded(), [this] { // While we have one mediaview for all authsessions we have to do this.
if (!isHidden()) { subscribe(Messenger::Instance().authSessionChanged(), [this] {
updateControls(); if (!AuthSession::Exists()) return;
}
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
if (!isHidden()) {
updateControls();
}
});
}); });
auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged; auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
@ -1155,7 +1163,7 @@ void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
} }
_zoomToScreen = 0; _zoomToScreen = 0;
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
_full = -1; _full = -1;
_current = QPixmap(); _current = QPixmap();
_down = OverNone; _down = OverNone;

View file

@ -86,7 +86,6 @@ Messenger::Messenger() : QObject()
anim::startManager(); anim::startManager();
historyInit(); historyInit();
Media::Player::start(); Media::Player::start();
Window::Notifications::Start();
DEBUG_LOG(("Application Info: inited...")); DEBUG_LOG(("Application Info: inited..."));
@ -130,7 +129,7 @@ Messenger::Messenger() : QObject()
if (state == Local::ReadMapPassNeeded) { if (state == Local::ReadMapPassNeeded) {
_window->setupPasscode(); _window->setupPasscode();
} else { } else {
if (AuthSession::Current()) { if (AuthSession::Exists()) {
_window->setupMain(); _window->setupMain();
} else { } else {
_window->setupIntro(); _window->setupIntro();
@ -196,7 +195,7 @@ QByteArray Messenger::serializeMtpAuthorization() const {
QDataStream stream(&buffer); QDataStream stream(&buffer);
stream.setVersion(QDataStream::Qt_5_1); stream.setVersion(QDataStream::Qt_5_1);
stream << qint32(AuthSession::CurrentUserId()) << qint32(mainDcId); stream << qint32(AuthSession::Exists() ? AuthSession::CurrentUserId() : 0) << qint32(mainDcId);
writeKeys(stream, keys); writeKeys(stream, keys);
writeKeys(stream, keysToDestroy); writeKeys(stream, keysToDestroy);
} }
@ -433,7 +432,7 @@ bool Messenger::peerPhotoFail(PeerId peer, const RPCError &error) {
} }
void Messenger::peerClearPhoto(PeerId id) { void Messenger::peerClearPhoto(PeerId id) {
if (!AuthSession::Current()) return; if (!AuthSession::Exists()) return;
if (id == AuthSession::CurrentUserPeerId()) { if (id == AuthSession::CurrentUserPeerId()) {
MTP::send(MTPphotos_UpdateProfilePhoto(MTP_inputPhotoEmpty()), rpcDone(&Messenger::selfPhotoCleared), rpcFail(&Messenger::peerPhotoFail, id)); MTP::send(MTPphotos_UpdateProfilePhoto(MTP_inputPhotoEmpty()), rpcDone(&Messenger::selfPhotoCleared), rpcFail(&Messenger::peerPhotoFail, id));
@ -525,7 +524,7 @@ void Messenger::killDownloadSessions() {
} }
void Messenger::photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file) { void Messenger::photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file) {
if (!AuthSession::Current()) return; if (!AuthSession::Exists()) return;
auto i = photoUpdates.find(msgId); auto i = photoUpdates.find(msgId);
if (i != photoUpdates.end()) { if (i != photoUpdates.end()) {
@ -583,10 +582,12 @@ void Messenger::onSwitchTestMode() {
void Messenger::authSessionCreate(UserId userId) { void Messenger::authSessionCreate(UserId userId) {
_authSession = std::make_unique<AuthSession>(userId); _authSession = std::make_unique<AuthSession>(userId);
authSessionChanged().notify();
} }
void Messenger::authSessionDestroy() { void Messenger::authSessionDestroy() {
_authSession.reset(); _authSession.reset();
authSessionChanged().notify();
} }
FileUploader *Messenger::uploader() { FileUploader *Messenger::uploader() {
@ -656,6 +657,7 @@ void Messenger::prepareToDestroy() {
// Some MTP requests can be cancelled from data clearing. // Some MTP requests can be cancelled from data clearing.
App::clearHistories(); App::clearHistories();
authSessionDestroy();
_delayedDestroyedLoaders.clear(); _delayedDestroyedLoaders.clear();
_mtproto.reset(); _mtproto.reset();
@ -668,8 +670,6 @@ Messenger::~Messenger() {
Shortcuts::finish(); Shortcuts::finish();
Window::Notifications::Finish();
anim::stopManager(); anim::stopManager();
stopWebLoadManager(); stopWebLoadManager();

View file

@ -32,7 +32,7 @@ class MainWidget;
class FileUploader; class FileUploader;
class Translator; class Translator;
class Messenger : public QObject, public RPCSender, private base::Subscriber { class Messenger final : public QObject, public RPCSender, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
@ -73,6 +73,9 @@ public:
} }
void authSessionCreate(UserId userId); void authSessionCreate(UserId userId);
void authSessionDestroy(); void authSessionDestroy();
base::Observable<void> &authSessionChanged() {
return _authSessionChanged;
}
FileUploader *uploader(); FileUploader *uploader();
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId); void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
@ -145,6 +148,7 @@ private:
std::unique_ptr<MTP::Instance> _mtproto; std::unique_ptr<MTP::Instance> _mtproto;
std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy; std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy;
std::unique_ptr<AuthSession> _authSession; std::unique_ptr<AuthSession> _authSession;
base::Observable<void> _authSessionChanged;
SingleDelayedCall _delayedLoadersDestroyer; SingleDelayedCall _delayedLoadersDestroyer;
std::vector<std::unique_ptr<FileLoader>> _delayedDestroyedLoaders; std::vector<std::unique_ptr<FileLoader>> _delayedDestroyedLoaders;

View file

@ -796,7 +796,7 @@ bool Instance::Private::rpcErrorOccured(mtpRequestId requestId, const RPCFailHan
} }
bool Instance::Private::hasAuthorization() { bool Instance::Private::hasAuthorization() {
return (AuthSession::Current() != nullptr); return AuthSession::Exists();
} }
void Instance::Private::importDone(const MTPauth_Authorization &result, mtpRequestId requestId) { void Instance::Private::importDone(const MTPauth_Authorization &result, mtpRequestId requestId) {

View file

@ -42,6 +42,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "history/history_service_layout.h" #include "history/history_service_layout.h"
#include "media/media_audio.h" #include "media/media_audio.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "auth_session.h"
#include "storage/file_download.h"
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -59,7 +61,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, Ui::ScrollArea *scroll, P
, _cancelSearch(this, st::dialogsCancelSearch) , _cancelSearch(this, st::dialogsCancelSearch)
, _itemsToBeLoaded(LinksOverviewPerPage * 2) , _itemsToBeLoaded(LinksOverviewPerPage * 2)
, _width(st::windowMinWidth) { , _width(st::windowMinWidth) {
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::Current().downloader()->taskFinished(), [this] { update(); });
subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) { subscribe(Global::RefItemRemoved(), [this](HistoryItem *item) {
itemRemoved(item); itemRemoved(item);
}); });
@ -1917,7 +1919,7 @@ void OverviewWidget::clear() {
} }
void OverviewWidget::onScroll() { void OverviewWidget::onScroll() {
MTP::clearLoaderPriorities(); AuthSession::Current().downloader()->clearPriorities();
int32 preloadThreshold = _scroll->height() * 5; int32 preloadThreshold = _scroll->height() * 5;
bool needToPreload = false; bool needToPreload = false;
do { do {

View file

@ -72,7 +72,7 @@ void PasscodeWidget::onSubmit() {
cSetPasscodeBadTries(0); cSetPasscodeBadTries(0);
Messenger::Instance().startMtp(); Messenger::Instance().startMtp();
if (AuthSession::Current()) { if (AuthSession::Exists()) {
App::wnd()->setupMain(); App::wnd()->setupMain();
} else { } else {
App::wnd()->setupIntro(); App::wnd()->setupIntro();

View file

@ -164,8 +164,10 @@ static gboolean _trayIconCheck(gpointer/* pIn*/) {
if (Libs::gtk_status_icon_is_embedded(_trayIcon)) { if (Libs::gtk_status_icon_is_embedded(_trayIcon)) {
trayIconChecked = true; trayIconChecked = true;
cSetSupportTray(true); cSetSupportTray(true);
if (Global::started()) {
Global::RefWorkMode().setForced(Global::WorkMode().value(), true);
}
if (App::wnd()) { if (App::wnd()) {
App::wnd()->psUpdateWorkmode();
Notify::unreadCounterUpdated(); Notify::unreadCounterUpdated();
App::wnd()->updateTrayMenu(); App::wnd()->updateTrayMenu();
} }
@ -196,7 +198,7 @@ void MainWindow::initHook() {
} }
bool MainWindow::hasTrayIcon() const { bool MainWindow::hasTrayIcon() const {
return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (cWorkMode() != dbiwmWindowOnly)); return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (Global::WorkMode().value() != dbiwmWindowOnly));
} }
void MainWindow::psStatusIconCheck() { void MainWindow::psStatusIconCheck() {
@ -272,10 +274,10 @@ void MainWindow::psSetupTrayIcon() {
} }
} }
void MainWindow::psUpdateWorkmode() { void MainWindow::workmodeUpdated(DBIWorkMode mode) {
if (!cSupportTray()) return; if (!cSupportTray()) return;
if (cWorkMode() == dbiwmWindowOnly) { if (mode == dbiwmWindowOnly) {
if (noQtTrayIcon) { if (noQtTrayIcon) {
if (useAppIndicator) { if (useAppIndicator) {
Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_PASSIVE); Libs::app_indicator_set_status(_trayIndicator, APP_INDICATOR_STATUS_PASSIVE);
@ -372,10 +374,6 @@ void MainWindow::updateIconCounters() {
} }
} }
bool MainWindow::psHasNativeNotifications() {
return Notifications::Supported();
}
void MainWindow::LibsLoaded() { void MainWindow::LibsLoaded() {
noQtTrayIcon = !DesktopEnvironment::TryQtTrayIcon(); noQtTrayIcon = !DesktopEnvironment::TryQtTrayIcon();
tryAppIndicator = !DesktopEnvironment::PreferAppIndicatorTrayIcon(); tryAppIndicator = !DesktopEnvironment::PreferAppIndicatorTrayIcon();
@ -518,7 +516,7 @@ void MainWindow::psCreateTrayIcon() {
Libs::g_idle_add((GSourceFunc)_trayIconCheck, 0); Libs::g_idle_add((GSourceFunc)_trayIconCheck, 0);
_psCheckStatusIconTimer.start(100); _psCheckStatusIconTimer.start(100);
} else { } else {
psUpdateWorkmode(); workmodeUpdated(Global::WorkMode().value());
} }
} }
@ -555,7 +553,7 @@ void MainWindow::psFirstShow() {
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) { if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
setWindowState(Qt::WindowMinimized); setWindowState(Qt::WindowMinimized);
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
hide(); hide();
} else { } else {
show(); show();
@ -577,9 +575,6 @@ void MainWindow::psUpdateSysMenu(Qt::WindowState state) {
void MainWindow::psUpdateMargins() { void MainWindow::psUpdateMargins() {
} }
void MainWindow::psFlash() {
}
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
if (_trayIcon) { if (_trayIcon) {
Libs::g_object_unref(_trayIcon); Libs::g_object_unref(_trayIcon);

View file

@ -35,16 +35,9 @@ public:
void psUpdateSysMenu(Qt::WindowState state); void psUpdateSysMenu(Qt::WindowState state);
void psUpdateMargins(); void psUpdateMargins();
void psFlash();
void psNotifySettingGot();
void psUpdateWorkmode();
void psRefreshTaskbarIcon() { void psRefreshTaskbarIcon() {
} }
bool psHasNativeNotifications();
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
static void LibsLoaded(); static void LibsLoaded();
@ -63,6 +56,8 @@ protected:
bool hasTrayIcon() const override; bool hasTrayIcon() const override;
void workmodeUpdated(DBIWorkMode mode) override;
QSystemTrayIcon *trayIcon = nullptr; QSystemTrayIcon *trayIcon = nullptr;
QMenu *trayIconMenu = nullptr; QMenu *trayIconMenu = nullptr;
QImage icon256, iconbig256; QImage icon256, iconbig256;

View file

@ -24,13 +24,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "platform/linux/linux_libnotify.h" #include "platform/linux/linux_libnotify.h"
#include "platform/linux/linux_libs.h" #include "platform/linux/linux_libs.h"
#include "lang.h" #include "lang.h"
#include "core/task_queue.h"
namespace Platform { namespace Platform {
namespace Notifications { namespace Notifications {
namespace { namespace {
NeverFreedPointer<Manager> ManagerInstance;
bool LibNotifyLoaded() { bool LibNotifyLoaded() {
return (Libs::notify_init != nullptr) return (Libs::notify_init != nullptr)
&& (Libs::notify_uninit != nullptr) && (Libs::notify_uninit != nullptr)
@ -100,10 +99,10 @@ QString escapeHtml(const QString &text) {
class NotificationData { class NotificationData {
public: public:
NotificationData(const QString &title, const QString &body, const QStringList &capabilities, PeerId peerId, MsgId msgId) NotificationData(const std::shared_ptr<Manager*> &guarded, const QString &title, const QString &body, const QStringList &capabilities, PeerId peerId, MsgId msgId)
: _data(Libs::notify_notification_new(title.toUtf8().constData(), body.toUtf8().constData(), nullptr)) { : _data(Libs::notify_notification_new(title.toUtf8().constData(), body.toUtf8().constData(), nullptr)) {
if (valid()) { if (valid()) {
init(capabilities, peerId, msgId); init(guarded, capabilities, peerId, msgId);
} }
} }
bool valid() const { bool valid() const {
@ -158,7 +157,7 @@ public:
} }
private: private:
void init(const QStringList &capabilities, PeerId peerId, MsgId msgId) { void init(const std::shared_ptr<Manager*> &guarded, const QStringList &capabilities, PeerId peerId, MsgId msgId) {
if (capabilities.contains(qsl("append"))) { if (capabilities.contains(qsl("append"))) {
Libs::notify_notification_set_hint_string(_data, "append", "true"); Libs::notify_notification_set_hint_string(_data, "append", "true");
} else if (capabilities.contains(qsl("x-canonical-append"))) { } else if (capabilities.contains(qsl("x-canonical-append"))) {
@ -169,22 +168,20 @@ private:
auto signalHandler = G_CALLBACK(NotificationData::notificationClosed); auto signalHandler = G_CALLBACK(NotificationData::notificationClosed);
auto signalName = "closed"; auto signalName = "closed";
auto signalDataFreeMethod = &NotificationData::notificationDataFreeClosure; auto signalDataFreeMethod = &NotificationData::notificationDataFreeClosure;
auto signalData = new NotificationDataStruct(peerId, msgId); auto signalData = new NotificationDataStruct(guarded, peerId, msgId);
_handlerId = Libs::g_signal_connect_helper(signalReceiver, signalName, signalHandler, signalData, signalDataFreeMethod); _handlerId = Libs::g_signal_connect_helper(signalReceiver, signalName, signalHandler, signalData, signalDataFreeMethod);
Libs::notify_notification_set_timeout(_data, Libs::NOTIFY_EXPIRES_DEFAULT); Libs::notify_notification_set_timeout(_data, Libs::NOTIFY_EXPIRES_DEFAULT);
if (auto manager = ManagerInstance.data()) { if ((*guarded)->hasActionsSupport()) {
if (manager->hasActionsSupport()) { auto label = lang(lng_notification_reply).toUtf8();
auto label = lang(lng_notification_reply).toUtf8(); auto actionReceiver = _data;
auto actionReceiver = _data; auto actionHandler = &NotificationData::notificationClicked;
auto actionHandler = &NotificationData::notificationClicked; auto actionLabel = label.constData();
auto actionLabel = label.constData(); auto actionName = "default";
auto actionName = "default"; auto actionDataFreeMethod = &NotificationData::notificationDataFree;
auto actionDataFreeMethod = &NotificationData::notificationDataFree; auto actionData = new NotificationDataStruct(guarded, peerId, msgId);
auto actionData = new NotificationDataStruct(peerId, msgId); Libs::notify_notification_add_action(actionReceiver, actionName, actionLabel, actionHandler, actionData, actionDataFreeMethod);
Libs::notify_notification_add_action(actionReceiver, actionName, actionLabel, actionHandler, actionData, actionDataFreeMethod);
}
} }
} }
@ -194,12 +191,23 @@ private:
} }
struct NotificationDataStruct { struct NotificationDataStruct {
NotificationDataStruct(PeerId peerId, MsgId msgId) : peerId(peerId), msgId(msgId) { NotificationDataStruct(const std::shared_ptr<Manager*> &guarded, PeerId peerId, MsgId msgId)
: weak(guarded)
, peerId(peerId)
, msgId(msgId) {
} }
std::weak_ptr<Manager*> weak;
PeerId peerId = 0; PeerId peerId = 0;
MsgId msgId = 0; MsgId msgId = 0;
}; };
static void performOnMainQueue(NotificationDataStruct *data, base::lambda_once<void(Manager *manager)> task) {
base::TaskQueue::Main().Put([weak = data->weak, task = std::move(task)]() mutable {
if (auto strong = weak.lock()) {
task(*strong);
}
});
}
static void notificationDataFree(gpointer data) { static void notificationDataFree(gpointer data) {
auto notificationData = static_cast<NotificationDataStruct*>(data); auto notificationData = static_cast<NotificationDataStruct*>(data);
delete notificationData; delete notificationData;
@ -211,15 +219,15 @@ private:
static void notificationClosed(Libs::NotifyNotification *notification, gpointer data) { static void notificationClosed(Libs::NotifyNotification *notification, gpointer data) {
auto closedReason = Libs::notify_notification_get_closed_reason(notification); auto closedReason = Libs::notify_notification_get_closed_reason(notification);
auto notificationData = static_cast<NotificationDataStruct*>(data); auto notificationData = static_cast<NotificationDataStruct*>(data);
if (auto manager = ManagerInstance.data()) { performOnMainQueue(notificationData, [peerId = notificationData->peerId, msgId = notificationData->msgId](Manager *manager) {
manager->clearNotification(notificationData->peerId, notificationData->msgId); manager->clearNotification(peerId, msgId);
} });
} }
static void notificationClicked(Libs::NotifyNotification *notification, char *action, gpointer data) { static void notificationClicked(Libs::NotifyNotification *notification, char *action, gpointer data) {
auto notificationData = static_cast<NotificationDataStruct*>(data); auto notificationData = static_cast<NotificationDataStruct*>(data);
if (auto manager = ManagerInstance.data()) { performOnMainQueue(notificationData, [peerId = notificationData->peerId, msgId = notificationData->msgId](Manager *manager) {
manager->notificationActivated(notificationData->peerId, notificationData->msgId); manager->notificationActivated(peerId, msgId);
} });
} }
Libs::NotifyNotification *_data = nullptr; Libs::NotifyNotification *_data = nullptr;
@ -229,47 +237,72 @@ private:
using Notification = QSharedPointer<NotificationData>; using Notification = QSharedPointer<NotificationData>;
} // namespace QString GetServerName() {
if (!LibNotifyLoaded()) {
void Start() { return QString();
if (LibNotifyLoaded()) {
if (Libs::notify_is_initted() || Libs::notify_init("Telegram Desktop")) {
ManagerInstance.createIfNull();
if (!ManagerInstance->init()) {
ManagerInstance.clear();
LOG(("LibNotify Error: manager failed to init!"));
}
} else {
LOG(("LibNotify Error: failed to init!"));
}
} }
if (!Libs::notify_is_initted() && !Libs::notify_init("Telegram Desktop")) {
LOG(("LibNotify Error: failed to init!"));
return QString();
}
gchar *name = nullptr;
auto guard = base::scope_guard([&name] {
if (name) Libs::g_free(name);
});
if (!Libs::notify_get_server_info(&name, nullptr, nullptr, nullptr)) {
LOG(("LibNotify Error: could not get server name!"));
return QString();
}
if (!name) {
LOG(("LibNotify Error: successfully got empty server name!"));
return QString();
}
auto result = QString::fromUtf8(static_cast<const char*>(name));
LOG(("Notifications Server: %1").arg(result));
return result;
} }
Window::Notifications::Manager *GetManager() { auto LibNotifyServerName = QString();
if (Global::started() && Global::NativeNotifications()) {
return ManagerInstance.data(); } // namespace
bool Supported() {
static auto Checked = false;
if (!Checked) {
Checked = true;
LibNotifyServerName = GetServerName();
}
return !LibNotifyServerName.isEmpty();
}
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
if (Global::NativeNotifications() && Supported()) {
return std::make_unique<Manager>(system);
} }
return nullptr; return nullptr;
} }
bool Supported() {
return ManagerInstance.data() != nullptr;
}
void Finish() { void Finish() {
if (GetManager()) { if (Libs::notify_is_initted && Libs::notify_uninit) {
ManagerInstance.reset(); if (Libs::notify_is_initted()) {
Libs::notify_uninit(); Libs::notify_uninit();
}
} }
} }
class Manager::Impl { class Manager::Private {
public: public:
using Type = Window::Notifications::CachedUserpics::Type; using Type = Window::Notifications::CachedUserpics::Type;
Impl(Type type) : _cachedUserpics(type) { explicit Private(Type type)
: _cachedUserpics(type) {
} }
bool init(); void init(Manager *manager);
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton); void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
void clearAll(); void clearAll();
@ -283,6 +316,8 @@ public:
return _actionsSupported; return _actionsSupported;
} }
~Private();
private: private:
QString escapeNotificationText(const QString &text) const; QString escapeNotificationText(const QString &text) const;
void showNextNotification(); void showNextNotification();
@ -309,9 +344,13 @@ private:
bool _markupSupported = false; bool _markupSupported = false;
bool _poorSupported = false; bool _poorSupported = false;
std::shared_ptr<Manager*> _guarded;
}; };
bool Manager::Impl::init() { void Manager::Private::init(Manager *manager) {
_guarded = std::make_shared<Manager*>(manager);
if (auto capabilities = Libs::notify_get_server_caps()) { if (auto capabilities = Libs::notify_get_server_caps()) {
for (auto capability = capabilities; capability; capability = capability->next) { for (auto capability = capabilities; capability; capability = capability->next) {
auto capabilityText = QString::fromUtf8(static_cast<const char*>(capability->data)); auto capabilityText = QString::fromUtf8(static_cast<const char*>(capability->data));
@ -331,32 +370,19 @@ bool Manager::Impl::init() {
// Unity and other Notify OSD users handle desktop notifications // Unity and other Notify OSD users handle desktop notifications
// extremely poor, even without the ability to close() them. // extremely poor, even without the ability to close() them.
gchar *name = nullptr; _serverName = LibNotifyServerName;
if (Libs::notify_get_server_info(&name, nullptr, nullptr, nullptr)) { t_assert(!_serverName.isEmpty());
if (name) { if (_serverName == qstr("notify-osd")) {
_serverName = QString::fromUtf8(static_cast<const char*>(name)); // _poorSupported = true;
Libs::g_free(name); _actionsSupported = false;
LOG(("Notifications Server: %1").arg(_serverName));
if (_serverName == qstr("notify-osd")) {
// _poorSupported = true;
_actionsSupported = false;
}
} else {
LOG(("LibNotify Error: successfully got empty server name!"));
}
} else {
LOG(("LibNotify Error: could not get server name!"));
} }
return !_serverName.isEmpty();
} }
QString Manager::Impl::escapeNotificationText(const QString &text) const { QString Manager::Private::escapeNotificationText(const QString &text) const {
return _markupSupported ? escapeHtml(text) : text; return _markupSupported ? escapeHtml(text) : text;
} }
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { void Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
auto titleText = escapeNotificationText(title); auto titleText = escapeNotificationText(title);
auto subtitleText = escapeNotificationText(subtitle); auto subtitleText = escapeNotificationText(subtitle);
auto msgText = escapeNotificationText(msg); auto msgText = escapeNotificationText(msg);
@ -376,7 +402,7 @@ void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
showNextNotification(); showNextNotification();
} }
void Manager::Impl::showNextNotification() { void Manager::Private::showNextNotification() {
// Show only one notification at a time in Unity / Notify OSD. // Show only one notification at a time in Unity / Notify OSD.
if (_poorSupported) { if (_poorSupported) {
for (auto b = _notifications.begin(); !_notifications.isEmpty() && b->isEmpty();) { for (auto b = _notifications.begin(); !_notifications.isEmpty() && b->isEmpty();) {
@ -401,7 +427,7 @@ void Manager::Impl::showNextNotification() {
auto peerId = data.peer->id; auto peerId = data.peer->id;
auto msgId = data.msgId; auto msgId = data.msgId;
auto notification = MakeShared<NotificationData>(data.title, data.body, _capabilities, peerId, msgId); auto notification = MakeShared<NotificationData>(_guarded, data.title, data.body, _capabilities, peerId, msgId);
if (!notification->valid()) { if (!notification->valid()) {
return; return;
} }
@ -438,7 +464,7 @@ void Manager::Impl::showNextNotification() {
} }
} }
void Manager::Impl::clearAll() { void Manager::Private::clearAll() {
_queuedNotifications.clear(); _queuedNotifications.clear();
auto temp = base::take(_notifications); auto temp = base::take(_notifications);
@ -449,7 +475,7 @@ void Manager::Impl::clearAll() {
} }
} }
void Manager::Impl::clearFromHistory(History *history) { void Manager::Private::clearFromHistory(History *history) {
for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.end();) { for (auto i = _queuedNotifications.begin(); i != _queuedNotifications.end();) {
if (i->peer == history->peer) { if (i->peer == history->peer) {
i = _queuedNotifications.erase(i); i = _queuedNotifications.erase(i);
@ -471,7 +497,7 @@ void Manager::Impl::clearFromHistory(History *history) {
showNextNotification(); showNextNotification();
} }
void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) { void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
auto i = _notifications.find(peerId); auto i = _notifications.find(peerId);
if (i != _notifications.cend()) { if (i != _notifications.cend()) {
i.value().remove(msgId); i.value().remove(msgId);
@ -483,37 +509,39 @@ void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
showNextNotification(); showNextNotification();
} }
Manager::Manager() : _impl(std::make_unique<Impl>(Impl::Type::Rounded)) { Manager::Private::~Private() {
clearAll();
} }
bool Manager::init() { Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
return _impl->init(); , _private(std::make_unique<Private>(Private::Type::Rounded)) {
_private->init(this);
} }
void Manager::clearNotification(PeerId peerId, MsgId msgId) { void Manager::clearNotification(PeerId peerId, MsgId msgId) {
_impl->clearNotification(peerId, msgId); _private->clearNotification(peerId, msgId);
} }
bool Manager::hasPoorSupport() const { bool Manager::hasPoorSupport() const {
return _impl->hasPoorSupport(); return _private->hasPoorSupport();
} }
bool Manager::hasActionsSupport() const { bool Manager::hasActionsSupport() const {
return _impl->hasActionsSupport(); return _private->hasActionsSupport();
} }
Manager::~Manager() = default; Manager::~Manager() = default;
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton); _private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
} }
void Manager::doClearAllFast() { void Manager::doClearAllFast() {
_impl->clearAll(); _private->clearAll();
} }
void Manager::doClearFromHistory(History *history) { void Manager::doClearFromHistory(History *history) {
_impl->clearFromHistory(history); _private->clearFromHistory(history);
} }
} // namespace Notifications } // namespace Notifications

View file

@ -36,11 +36,14 @@ inline bool SkipToast() {
return false; return false;
} }
inline void FlashBounce() {
}
void Finish();
class Manager : public Window::Notifications::NativeManager { class Manager : public Window::Notifications::NativeManager {
public: public:
Manager(); Manager(Window::Notifications::System *system);
bool init();
void clearNotification(PeerId peerId, MsgId msgId); void clearNotification(PeerId peerId, MsgId msgId);
bool hasPoorSupport() const; bool hasPoorSupport() const;
@ -54,9 +57,8 @@ protected:
void doClearFromHistory(History *history) override; void doClearFromHistory(History *history) override;
private: private:
class Impl; class Private;
friend class Impl; const std::unique_ptr<Private> _private;
std::unique_ptr<Impl> _impl;
}; };

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwidget.h" #include "mainwidget.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "platform/linux/file_utilities_linux.h" #include "platform/linux/file_utilities_linux.h"
#include "platform/platform_notifications_manager.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include <sys/stat.h> #include <sys/stat.h>
@ -370,6 +371,8 @@ void start() {
} }
void finish() { void finish() {
Notifications::Finish();
delete _psEventFilter; delete _psEventFilter;
_psEventFilter = nullptr; _psEventFilter = nullptr;
} }

View file

@ -36,25 +36,20 @@ public:
void psUpdateSysMenu(Qt::WindowState state); void psUpdateSysMenu(Qt::WindowState state);
void psUpdateMargins(); void psUpdateMargins();
void psFlash();
void psUpdateWorkmode();
void psRefreshTaskbarIcon() { void psRefreshTaskbarIcon() {
} }
bool psFilterNativeEvent(void *event); bool psFilterNativeEvent(void *event);
bool psHasNativeNotifications() {
return !(QSysInfo::macVersion() < QSysInfo::MV_10_8);
}
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
int getCustomTitleHeight() const { int getCustomTitleHeight() const {
return _customTitleHeight; return _customTitleHeight;
} }
// It is placed here while the window handles activeSpaceDidChange event.
void customNotificationCreated(QWidget *notification);
~MainWindow(); ~MainWindow();
class Private; class Private;
@ -88,6 +83,8 @@ protected:
void updateGlobalMenuHook() override; void updateGlobalMenuHook() override;
void workmodeUpdated(DBIWorkMode mode) override;
QSystemTrayIcon *trayIcon = nullptr; QSystemTrayIcon *trayIcon = nullptr;
QMenu *trayIconMenu = nullptr; QMenu *trayIconMenu = nullptr;
QImage icon256, iconbig256; QImage icon256, iconbig256;
@ -109,9 +106,16 @@ private:
void updateTitleCounter(); void updateTitleCounter();
void updateIconCounters(); void updateIconCounters();
class CustomNotificationHandle;
friend class CustomNotificationHandle;
void customNotificationDestroyed(CustomNotificationHandle *handle);
void activateCustomNotifications();
friend class Private; friend class Private;
std::unique_ptr<Private> _private; std::unique_ptr<Private> _private;
std::set<CustomNotificationHandle*> _customNotifications;
mutable bool psIdle; mutable bool psIdle;
mutable QTimer psIdleTimer; mutable QTimer psIdleTimer;

View file

@ -56,7 +56,6 @@ public:
Private(MainWindow *window); Private(MainWindow *window);
void setWindowBadge(const QString &str); void setWindowBadge(const QString &str);
void startBounce();
void enableShadow(WId winId); void enableShadow(WId winId);
@ -64,6 +63,7 @@ public:
void willEnterFullScreen(); void willEnterFullScreen();
void willExitFullScreen(); void willExitFullScreen();
void activateCustomNotifications();
void initCustomTitle(NSWindow *window, NSView *view); void initCustomTitle(NSWindow *window, NSView *view);
@ -82,6 +82,25 @@ private:
}; };
class MainWindow::CustomNotificationHandle : public QObject {
public:
CustomNotificationHandle(QWidget *parent) : QObject(parent) {
}
void activate() {
auto widget = static_cast<QWidget*>(parent());
NSWindow *wnd = [reinterpret_cast<NSView *>(widget->winId()) window];
[wnd orderFront:wnd];
}
~CustomNotificationHandle() {
if (auto window = App::wnd()) {
window->customNotificationDestroyed(this);
}
}
};
} // namespace Platform } // namespace Platform
@implementation MainWindowObserver { @implementation MainWindowObserver {
@ -98,11 +117,7 @@ MainWindow::Private *_private;
} }
- (void) activeSpaceDidChange:(NSNotification *)aNotification { - (void) activeSpaceDidChange:(NSNotification *)aNotification {
if (auto manager = Window::Notifications::Default::GetManager()) { _private->activateCustomNotifications();
manager->enumerateNotifications([](QWidget *widget) {
objc_activateWnd(widget->winId());
});
}
} }
- (void) darkModeChanged:(NSNotification *)aNotification { - (void) darkModeChanged:(NSNotification *)aNotification {
@ -157,10 +172,6 @@ void MainWindow::Private::setWindowBadge(const QString &str) {
} }
} }
void MainWindow::Private::startBounce() {
[NSApp requestUserAttention:NSInformationalRequest];
}
void MainWindow::Private::initCustomTitle(NSWindow *window, NSView *view) { void MainWindow::Private::initCustomTitle(NSWindow *window, NSView *view) {
[window setStyleMask:[window styleMask] | NSFullSizeContentViewWindowMask]; [window setStyleMask:[window styleMask] | NSFullSizeContentViewWindowMask];
[window setTitlebarAppearsTransparent:YES]; [window setTitlebarAppearsTransparent:YES];
@ -191,6 +202,10 @@ void MainWindow::Private::willExitFullScreen() {
_public->setTitleVisible(true); _public->setTitleVisible(true);
} }
void MainWindow::Private::activateCustomNotifications() {
_public->activateCustomNotifications();
}
void MainWindow::Private::enableShadow(WId winId) { void MainWindow::Private::enableShadow(WId winId) {
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask]; // [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
// [[(NSView*)winId window] setHasShadow:YES]; // [[(NSView*)winId window] setHasShadow:YES];
@ -299,18 +314,15 @@ void MainWindow::psSetupTrayIcon() {
trayIcon->show(); trayIcon->show();
} }
void MainWindow::psUpdateWorkmode() { void MainWindow::workmodeUpdated(DBIWorkMode mode) {
psSetupTrayIcon(); psSetupTrayIcon();
if (cWorkMode() == dbiwmWindowOnly) { if (mode == dbiwmWindowOnly) {
if (trayIcon) { if (trayIcon) {
trayIcon->setContextMenu(0); trayIcon->setContextMenu(0);
delete trayIcon; delete trayIcon;
trayIcon = nullptr; trayIcon = nullptr;
} }
} }
if (auto manager = Platform::Notifications::GetNativeManager()) {
manager->updateDelegate();
}
} }
void _placeCounter(QImage &img, int size, int count, style::color bg, style::color color) { void _placeCounter(QImage &img, int size, int count, style::color bg, style::color color) {
@ -400,7 +412,7 @@ void MainWindow::psFirstShow() {
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) { if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
setWindowState(Qt::WindowMinimized); setWindowState(Qt::WindowMinimized);
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
hide(); hide();
} else { } else {
show(); show();
@ -514,6 +526,20 @@ void MainWindow::psUpdateSysMenu(Qt::WindowState state) {
void MainWindow::psUpdateMargins() { void MainWindow::psUpdateMargins() {
} }
void MainWindow::customNotificationCreated(QWidget *notification) {
_customNotifications.insert(object_ptr<CustomNotificationHandle>(notification));
}
void MainWindow::customNotificationDestroyed(CustomNotificationHandle *handle) {
_customNotifications.erase(handle);
}
void MainWindow::activateCustomNotifications() {
for (auto handle : _customNotifications) {
handle->activate();
}
}
void MainWindow::updateGlobalMenuHook() { void MainWindow::updateGlobalMenuHook() {
if (!App::wnd() || !positionInited()) return; if (!App::wnd() || !positionInited()) return;
@ -552,10 +578,6 @@ void MainWindow::updateGlobalMenuHook() {
_forceDisabled(psShowTelegram, App::wnd()->isActive()); _forceDisabled(psShowTelegram, App::wnd()->isActive());
} }
void MainWindow::psFlash() {
return _private->startBounce();
}
bool MainWindow::psFilterNativeEvent(void *event) { bool MainWindow::psFilterNativeEvent(void *event) {
return _private->filterNativeEvent(event); return _private->filterNativeEvent(event);
} }

View file

@ -25,9 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace Platform { namespace Platform {
namespace Notifications { namespace Notifications {
class Manager;
Manager *GetNativeManager();
inline bool SkipAudio() { inline bool SkipAudio() {
return false; return false;
} }
@ -38,10 +35,7 @@ inline bool SkipToast() {
class Manager : public Window::Notifications::NativeManager { class Manager : public Window::Notifications::NativeManager {
public: public:
Manager(); Manager(Window::Notifications::System *system);
void updateDelegate();
~Manager(); ~Manager();
protected: protected:
@ -50,14 +44,10 @@ protected:
void doClearFromHistory(History *history) override; void doClearFromHistory(History *history) override;
private: private:
class Impl; class Private;
std::unique_ptr<Impl> _impl; const std::unique_ptr<Private> _private;
}; };
inline Window::Notifications::Manager *GetManager() {
return GetNativeManager();
}
} // namespace Notifications } // namespace Notifications
} // namespace Platform } // namespace Platform

View file

@ -23,6 +23,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "platform/platform_specific.h" #include "platform/platform_specific.h"
#include "platform/mac/mac_utilities.h" #include "platform/mac/mac_utilities.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include "mainwindow.h"
#include "core/task_queue.h"
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
@ -93,22 +95,19 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm);
namespace Platform { namespace Platform {
namespace Notifications { namespace Notifications {
void Start() {
if (cPlatform() != dbipMacOld) {
ManagerInstance.createIfNull();
}
}
Manager *GetNativeManager() {
return ManagerInstance.data();
}
bool Supported() { bool Supported() {
return ManagerInstance.data() != nullptr; return (cPlatform() != dbipMacOld);
} }
void Finish() { std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
ManagerInstance.clear(); if (Supported()) {
return std::make_unique<Manager>(system);
}
return nullptr;
}
void FlashBounce() {
[NSApp requestUserAttention:NSInformationalRequest];
} }
void CustomNotificationShownHook(QWidget *widget) { void CustomNotificationShownHook(QWidget *widget) {
@ -116,27 +115,38 @@ void CustomNotificationShownHook(QWidget *widget) {
objc_holdOnTop(widget->winId()); objc_holdOnTop(widget->winId());
widget->show(); widget->show();
psShowOverAll(widget, false); psShowOverAll(widget, false);
if (auto window = App::wnd()) {
window->customNotificationCreated(widget);
}
} }
class Manager::Impl { class Manager::Private : public QObject, private base::Subscriber {
public: public:
Impl(); Private();
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton); void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
void clearAll(); void clearAll();
void clearFromHistory(History *history); void clearFromHistory(History *history);
void updateDelegate(); void updateDelegate();
~Impl(); ~Private();
private: private:
NotificationDelegate *_delegate; NotificationDelegate *_delegate;
}; };
Manager::Impl::Impl() : _delegate([[NotificationDelegate alloc] init]) { Manager::Private::Private() : _delegate([[NotificationDelegate alloc] init]) {
updateDelegate();
subscribe(Global::RefWorkMode(), [this](DBIWorkMode mode) {
// We need to update the delegate _after_ the tray icon change was done in Qt.
// Because Qt resets the delegate.
base::TaskQueue::Main().Put(base::lambda_guarded(this, [this] {
updateDelegate();
}));
});
} }
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { void Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
@autoreleasepool { @autoreleasepool {
NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease]; NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease];
@ -168,7 +178,7 @@ void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
} }
} }
void Manager::Impl::clearAll() { void Manager::Private::clearAll() {
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
NSArray *notificationsList = [center deliveredNotifications]; NSArray *notificationsList = [center deliveredNotifications];
for (id notification in notificationsList) { for (id notification in notificationsList) {
@ -182,7 +192,7 @@ void Manager::Impl::clearAll() {
[center removeAllDeliveredNotifications]; [center removeAllDeliveredNotifications];
} }
void Manager::Impl::clearFromHistory(History *history) { void Manager::Private::clearFromHistory(History *history) {
unsigned long long peerId = history->peer->id; unsigned long long peerId = history->peer->id;
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
@ -199,34 +209,32 @@ void Manager::Impl::clearFromHistory(History *history) {
} }
} }
void Manager::Impl::updateDelegate() { void Manager::Private::updateDelegate() {
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center setDelegate:_delegate]; [center setDelegate:_delegate];
} }
Manager::Impl::~Impl() { Manager::Private::~Private() {
clearAll();
[_delegate release]; [_delegate release];
} }
Manager::Manager() : _impl(std::make_unique<Impl>()) { Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
} , _private(std::make_unique<Private>()) {
void Manager::updateDelegate() {
_impl->updateDelegate();
} }
Manager::~Manager() = default; Manager::~Manager() = default;
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton); _private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
} }
void Manager::doClearAllFast() { void Manager::doClearAllFast() {
_impl->clearAll(); _private->clearAll();
} }
void Manager::doClearFromHistory(History *history) { void Manager::doClearFromHistory(History *history) {
_impl->clearFromHistory(history); _private->clearFromHistory(history);
} }
} // namespace Notifications } // namespace Notifications

View file

@ -24,7 +24,6 @@ void objc_holdOnTop(WId winId);
bool objc_darkMode(); bool objc_darkMode();
void objc_showOverAll(WId winId, bool canFocus = true); void objc_showOverAll(WId winId, bool canFocus = true);
void objc_bringToBack(WId winId); void objc_bringToBack(WId winId);
void objc_activateWnd(WId winId);
void objc_debugShowAlert(const QString &str); void objc_debugShowAlert(const QString &str);
void objc_outputDebugString(const QString &str); void objc_outputDebugString(const QString &str);

View file

@ -208,11 +208,6 @@ void objc_bringToBack(WId winId) {
[wnd setLevel:NSModalPanelWindowLevel]; [wnd setLevel:NSModalPanelWindowLevel];
} }
void objc_activateWnd(WId winId) {
NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
[wnd orderFront:wnd];
}
bool objc_handleMediaKeyEvent(void *ev) { bool objc_handleMediaKeyEvent(void *ev) {
auto e = reinterpret_cast<NSEvent*>(ev); auto e = reinterpret_cast<NSEvent*>(ev);

View file

@ -29,10 +29,9 @@ void CustomNotificationShownHook(QWidget *widget);
bool SkipAudio(); bool SkipAudio();
bool SkipToast(); bool SkipToast();
void Start();
Window::Notifications::Manager *GetManager();
bool Supported(); bool Supported();
void Finish(); std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system);
void FlashBounce();
} // namespace Notifications } // namespace Notifications
} // namespace Platform } // namespace Platform

View file

@ -703,8 +703,8 @@ void MainWindow::showTrayTooltip() {
} }
} }
void MainWindow::psUpdateWorkmode() { void MainWindow::workmodeUpdated(DBIWorkMode mode) {
switch (cWorkMode()) { switch (mode) {
case dbiwmWindowAndTray: { case dbiwmWindowAndTray: {
psSetupTrayIcon(); psSetupTrayIcon();
HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT); HWND psOwner = (HWND)GetWindowLong(ps_hWnd, GWL_HWNDPARENT);
@ -800,10 +800,6 @@ void MainWindow::initHook() {
setWindowIcon(wndIcon); setWindowIcon(wndIcon);
} }
bool MainWindow::psHasNativeNotifications() {
return Notifications::Supported();
}
Q_DECLARE_METATYPE(QMargins); Q_DECLARE_METATYPE(QMargins);
void MainWindow::psFirstShow() { void MainWindow::psFirstShow() {
_psShadowWindows.init(st::windowShadowFg->c); _psShadowWindows.init(st::windowShadowFg->c);
@ -821,7 +817,7 @@ void MainWindow::psFirstShow() {
if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized() && !App::passcoded()) || cStartInTray()) { if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized() && !App::passcoded()) || cStartInTray()) {
setWindowState(Qt::WindowMinimized); setWindowState(Qt::WindowMinimized);
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
hide(); hide();
} else { } else {
show(); show();
@ -934,18 +930,6 @@ void MainWindow::psUpdateMargins() {
} }
} }
void MainWindow::psFlash() {
if (GetForegroundWindow() == ps_hWnd) return;
FLASHWINFO info;
info.cbSize = sizeof(info);
info.hwnd = ps_hWnd;
info.dwFlags = FLASHW_ALL;
info.dwTimeout = 0;
info.uCount = 1;
FlashWindowEx(&info);
}
HWND MainWindow::psHwnd() const { HWND MainWindow::psHwnd() const {
return ps_hWnd; return ps_hWnd;
} }

View file

@ -43,15 +43,8 @@ public:
void psUpdateSysMenu(Qt::WindowState state); void psUpdateSysMenu(Qt::WindowState state);
void psUpdateMargins(); void psUpdateMargins();
void psFlash();
void psNotifySettingGot();
void psUpdateWorkmode();
void psRefreshTaskbarIcon(); void psRefreshTaskbarIcon();
bool psHasNativeNotifications();
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
static UINT TaskbarCreatedMsgId() { static UINT TaskbarCreatedMsgId() {
@ -108,6 +101,8 @@ protected:
void showTrayTooltip() override; void showTrayTooltip() override;
void workmodeUpdated(DBIWorkMode mode) override;
QTimer psUpdatedPositionTimer; QTimer psUpdatedPositionTimer;
private: private:

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "platform/win/windows_event_filter.h" #include "platform/win/windows_event_filter.h"
#include "platform/win/windows_dlls.h" #include "platform/win/windows_dlls.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "core/task_queue.h"
#include <Shobjidl.h> #include <Shobjidl.h>
#include <shellapi.h> #include <shellapi.h>
@ -48,22 +49,6 @@ namespace Platform {
namespace Notifications { namespace Notifications {
namespace { namespace {
NeverFreedPointer<Manager> ManagerInstance;
ComPtr<IToastNotificationManagerStatics> _notificationManager;
ComPtr<IToastNotifier> _notifier;
ComPtr<IToastNotificationFactory> _notificationFactory;
struct NotificationPtr {
NotificationPtr() {
}
NotificationPtr(const ComPtr<IToastNotification> &ptr) : p(ptr) {
}
ComPtr<IToastNotification> p;
};
using Notifications = QMap<PeerId, QMap<MsgId, NotificationPtr>>;
Notifications _notifications;
class StringReferenceWrapper { class StringReferenceWrapper {
public: public:
StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() { StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() {
@ -137,15 +122,6 @@ bool init() {
if (!SUCCEEDED(Dlls::SetCurrentProcessExplicitAppUserModelID(appUserModelId))) { if (!SUCCEEDED(Dlls::SetCurrentProcessExplicitAppUserModelID(appUserModelId))) {
return false; return false;
} }
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager))) {
return false;
}
if (!SUCCEEDED(_notificationManager->CreateToastNotifierWithId(StringReferenceWrapper(appUserModelId, wcslen(appUserModelId)).Get(), &_notifier))) {
return false;
}
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
return false;
}
return true; return true;
} }
@ -235,16 +211,27 @@ typedef ABI::Windows::Foundation::ITypedEventHandler<ToastNotification*, ToastFa
class ToastEventHandler : public Implements<DesktopToastActivatedEventHandler, DesktopToastDismissedEventHandler, DesktopToastFailedEventHandler> { class ToastEventHandler : public Implements<DesktopToastActivatedEventHandler, DesktopToastDismissedEventHandler, DesktopToastFailedEventHandler> {
public: public:
ToastEventHandler::ToastEventHandler(const PeerId &peer, MsgId msg) : _ref(1), _peerId(peer), _msgId(msg) { // We keep a weak pointer to a member field of native notifications manager.
ToastEventHandler::ToastEventHandler(const std::shared_ptr<Manager*> &guarded, const PeerId &peer, MsgId msg)
: _peerId(peer)
, _msgId(msg)
, _weak(guarded) {
} }
~ToastEventHandler() { ~ToastEventHandler() = default;
void performOnMainQueue(base::lambda_once<void(Manager *manager)> task) {
base::TaskQueue::Main().Put([weak = _weak, task = std::move(task)]() mutable {
if (auto strong = weak.lock()) {
task(*strong);
}
});
} }
// DesktopToastActivatedEventHandler // DesktopToastActivatedEventHandler
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IInspectable* args) { IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IInspectable* args) {
if (auto manager = ManagerInstance.data()) { performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
manager->notificationActivated(_peerId, _msgId); manager->notificationActivated(peerId, msgId);
} });
return S_OK; return S_OK;
} }
@ -258,9 +245,9 @@ public:
case ToastDismissalReason_UserCanceled: case ToastDismissalReason_UserCanceled:
case ToastDismissalReason_TimedOut: case ToastDismissalReason_TimedOut:
default: default:
if (auto manager = ManagerInstance.data()) { performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
manager->clearNotification(_peerId, _msgId); manager->clearNotification(peerId, msgId);
} });
break; break;
} }
} }
@ -269,21 +256,23 @@ public:
// DesktopToastFailedEventHandler // DesktopToastFailedEventHandler
IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IToastFailedEventArgs *e) { IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IToastFailedEventArgs *e) {
if (auto manager = ManagerInstance.data()) { performOnMainQueue([peerId = _peerId, msgId = _msgId](Manager *manager) {
manager->clearNotification(_peerId, _msgId); manager->clearNotification(peerId, msgId);
} });
return S_OK; return S_OK;
} }
// IUnknown // IUnknown
IFACEMETHODIMP_(ULONG) AddRef() { IFACEMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement(&_ref); return InterlockedIncrement(&_refCount);
} }
IFACEMETHODIMP_(ULONG) Release() { IFACEMETHODIMP_(ULONG) Release() {
ULONG l = InterlockedDecrement(&_ref); auto refCount = InterlockedDecrement(&_refCount);
if (l == 0) delete this; if (refCount == 0) {
return l; delete this;
}
return refCount;
} }
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) { IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) {
@ -306,41 +295,61 @@ public:
} }
private: private:
ULONG _ref; ULONG _refCount = 0;
PeerId _peerId; PeerId _peerId = 0;
MsgId _msgId; MsgId _msgId = 0;
std::weak_ptr<Manager*> _weak;
}; };
} // namespace auto Checked = false;
auto InitSucceeded = false;
void Start() { void Check() {
if (init()) { InitSucceeded = init();
ManagerInstance.createIfNull();
}
} }
Window::Notifications::Manager *GetManager() { } // namespace
if (Global::started() && Global::NativeNotifications()) {
return ManagerInstance.data(); bool Supported() {
if (!Checked) {
Checked = true;
Check();
}
return InitSucceeded;
}
std::unique_ptr<Window::Notifications::Manager> Create(Window::Notifications::System *system) {
if (Global::NativeNotifications() && Supported()) {
auto result = std::make_unique<Manager>(system);
if (result->init()) {
return std::move(result);
}
} }
return nullptr; return nullptr;
} }
bool Supported() { void FlashBounce() {
return ManagerInstance.data() != nullptr; auto window = App::wnd();
if (!window || GetForegroundWindow() == window->psHwnd()) {
return;
}
FLASHWINFO info;
info.cbSize = sizeof(info);
info.hwnd = window->psHwnd();
info.dwFlags = FLASHW_ALL;
info.dwTimeout = 0;
info.uCount = 1;
FlashWindowEx(&info);
} }
void Finish() { class Manager::Private {
ManagerInstance.clear();
}
class Manager::Impl {
public: public:
using Type = Window::Notifications::CachedUserpics::Type; using Type = Window::Notifications::CachedUserpics::Type;
Impl(Type type) : _cachedUserpics(type) { explicit Private(Manager *instance, Type type);
} bool init();
bool showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton); bool showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
void clearAll(); void clearAll();
@ -349,21 +358,60 @@ public:
void afterNotificationActivated(PeerId peerId, MsgId msgId); void afterNotificationActivated(PeerId peerId, MsgId msgId);
void clearNotification(PeerId peerId, MsgId msgId); void clearNotification(PeerId peerId, MsgId msgId);
~Impl(); ~Private();
private: private:
Window::Notifications::CachedUserpics _cachedUserpics; Window::Notifications::CachedUserpics _cachedUserpics;
std::shared_ptr<Manager*> _guarded;
ComPtr<IToastNotificationManagerStatics> _notificationManager;
ComPtr<IToastNotifier> _notifier;
ComPtr<IToastNotificationFactory> _notificationFactory;
struct NotificationPtr {
NotificationPtr() {
}
NotificationPtr(const ComPtr<IToastNotification> &ptr) : p(ptr) {
}
ComPtr<IToastNotification> p;
};
QMap<PeerId, QMap<MsgId, NotificationPtr>> _notifications;
}; };
Manager::Impl::~Impl() { Manager::Private::Private(Manager *instance, Type type)
: _guarded(std::make_shared<Manager*>(instance))
, _cachedUserpics(type) {
}
bool Manager::Private::init() {
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager))) {
return false;
}
auto appUserModelId = AppUserModelId::getId();
if (!SUCCEEDED(_notificationManager->CreateToastNotifierWithId(StringReferenceWrapper(appUserModelId, wcslen(appUserModelId)).Get(), &_notifier))) {
return false;
}
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
return false;
}
return true;
}
Manager::Private::~Private() {
clearAll();
_notifications.clear(); _notifications.clear();
if (_notificationManager) _notificationManager.Reset(); if (_notificationManager) _notificationManager.Reset();
if (_notifier) _notifier.Reset(); if (_notifier) _notifier.Reset();
if (_notificationFactory) _notificationFactory.Reset(); if (_notificationFactory) _notificationFactory.Reset();
} }
void Manager::Impl::clearAll() { void Manager::Private::clearAll() {
if (!_notifier) return; if (!_notifier) return;
auto temp = base::take(_notifications); auto temp = base::take(_notifications);
@ -374,7 +422,7 @@ void Manager::Impl::clearAll() {
} }
} }
void Manager::Impl::clearFromHistory(History *history) { void Manager::Private::clearFromHistory(History *history) {
if (!_notifier) return; if (!_notifier) return;
auto i = _notifications.find(history->peer->id); auto i = _notifications.find(history->peer->id);
@ -388,17 +436,17 @@ void Manager::Impl::clearFromHistory(History *history) {
} }
} }
void Manager::Impl::beforeNotificationActivated(PeerId peerId, MsgId msgId) { void Manager::Private::beforeNotificationActivated(PeerId peerId, MsgId msgId) {
clearNotification(peerId, msgId); clearNotification(peerId, msgId);
} }
void Manager::Impl::afterNotificationActivated(PeerId peerId, MsgId msgId) { void Manager::Private::afterNotificationActivated(PeerId peerId, MsgId msgId) {
if (auto window = App::wnd()) { if (auto window = App::wnd()) {
SetForegroundWindow(window->psHwnd()); SetForegroundWindow(window->psHwnd());
} }
} }
void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) { void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
auto i = _notifications.find(peerId); auto i = _notifications.find(peerId);
if (i != _notifications.cend()) { if (i != _notifications.cend()) {
i.value().remove(msgId); i.value().remove(msgId);
@ -408,7 +456,7 @@ void Manager::Impl::clearNotification(PeerId peerId, MsgId msgId) {
} }
} }
bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { bool Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
if (!_notificationManager || !_notifier || !_notificationFactory) return false; if (!_notificationManager || !_notifier || !_notificationFactory) return false;
ComPtr<IXmlDocument> toastXml; ComPtr<IXmlDocument> toastXml;
@ -475,7 +523,7 @@ bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
if (!SUCCEEDED(hr)) return false; if (!SUCCEEDED(hr)) return false;
EventRegistrationToken activatedToken, dismissedToken, failedToken; EventRegistrationToken activatedToken, dismissedToken, failedToken;
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(peer->id, msgId)); ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(_guarded, peer->id, msgId));
hr = toast->add_Activated(eventHandler.Get(), &activatedToken); hr = toast->add_Activated(eventHandler.Get(), &activatedToken);
if (!SUCCEEDED(hr)) return false; if (!SUCCEEDED(hr)) return false;
@ -510,33 +558,38 @@ bool Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
return true; return true;
} }
Manager::Manager() : _impl(std::make_unique<Impl>(Impl::Type::Rounded)) { Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
}
bool Manager::init() {
return _private->init();
} }
void Manager::clearNotification(PeerId peerId, MsgId msgId) { void Manager::clearNotification(PeerId peerId, MsgId msgId) {
_impl->clearNotification(peerId, msgId); _private->clearNotification(peerId, msgId);
} }
Manager::~Manager() = default; Manager::~Manager() = default;
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) { void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton); _private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
} }
void Manager::doClearAllFast() { void Manager::doClearAllFast() {
_impl->clearAll(); _private->clearAll();
} }
void Manager::doClearFromHistory(History *history) { void Manager::doClearFromHistory(History *history) {
_impl->clearFromHistory(history); _private->clearFromHistory(history);
} }
void Manager::onBeforeNotificationActivated(PeerId peerId, MsgId msgId) { void Manager::onBeforeNotificationActivated(PeerId peerId, MsgId msgId) {
_impl->beforeNotificationActivated(peerId, msgId); _private->beforeNotificationActivated(peerId, msgId);
} }
void Manager::onAfterNotificationActivated(PeerId peerId, MsgId msgId) { void Manager::onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
_impl->afterNotificationActivated(peerId, msgId); _private->afterNotificationActivated(peerId, msgId);
} }
namespace { namespace {

View file

@ -30,7 +30,9 @@ inline void CustomNotificationShownHook(QWidget *widget) {
class Manager : public Window::Notifications::NativeManager { class Manager : public Window::Notifications::NativeManager {
public: public:
Manager(); Manager(Window::Notifications::System *system);
bool init();
void clearNotification(PeerId peerId, MsgId msgId); void clearNotification(PeerId peerId, MsgId msgId);
@ -44,8 +46,8 @@ protected:
void onAfterNotificationActivated(PeerId peerId, MsgId msgId) override; void onAfterNotificationActivated(PeerId peerId, MsgId msgId) override;
private: private:
class Impl; class Private;
std::unique_ptr<Impl> _impl; const std::unique_ptr<Private> _private;
}; };

View file

@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "styles/style_profile.h" #include "styles/style_profile.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "auth_session.h"
namespace Profile { namespace Profile {
@ -38,7 +39,7 @@ PeerListWidget::PeerListWidget(QWidget *parent, PeerData *peer, const QString &t
, _removeText(removeText) , _removeText(removeText)
, _removeWidth(st::normalFont->width(_removeText)) { , _removeWidth(st::normalFont->width(_removeText)) {
setMouseTracking(true); setMouseTracking(true);
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
} }
int PeerListWidget::resizeGetHeight(int newWidth) { int PeerListWidget::resizeGetHeight(int newWidth) {

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_profile.h" #include "styles/style_profile.h"
#include "observer_peer.h" #include "observer_peer.h"
#include "storage/file_download.h" #include "auth_session.h"
namespace Profile { namespace Profile {
@ -41,7 +41,7 @@ UserpicButton::UserpicButton(QWidget *parent, PeerData *peer, int size) : Abstra
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update); notifyPeerUpdated(update);
})); }));
subscribe(FileDownload::ImageLoaded(), [this] { subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
if (_waiting && _peer->userpicLoaded()) { if (_waiting && _peer->userpicLoaded()) {
_waiting = false; _waiting = false;
startNewPhotoShowing(); startNewPhotoShowing();

View file

@ -55,7 +55,6 @@ bool gAutoUpdate = true;
TWindowPos gWindowPos; TWindowPos gWindowPos;
LaunchMode gLaunchMode = LaunchModeNormal; LaunchMode gLaunchMode = LaunchModeNormal;
bool gSupportTray = true; bool gSupportTray = true;
DBIWorkMode gWorkMode = dbiwmWindowAndTray;
bool gSeenTrayTooltip = false; bool gSeenTrayTooltip = false;
bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false; bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false;
int32 gLastUpdateCheck = 0; int32 gLastUpdateCheck = 0;

View file

@ -101,7 +101,6 @@ struct TWindowPos {
}; };
DeclareSetting(TWindowPos, WindowPos); DeclareSetting(TWindowPos, WindowPos);
DeclareSetting(bool, SupportTray); DeclareSetting(bool, SupportTray);
DeclareSetting(DBIWorkMode, WorkMode);
DeclareSetting(bool, SeenTrayTooltip); DeclareSetting(bool, SeenTrayTooltip);
DeclareSetting(bool, RestartingUpdate); DeclareSetting(bool, RestartingUpdate);
DeclareSetting(bool, Restarting); DeclareSetting(bool, Restarting);

View file

@ -184,9 +184,10 @@ void GeneralWidget::refreshControls() {
#endif // !TDESKTOP_DISABLE_AUTOUPDATE #endif // !TDESKTOP_DISABLE_AUTOUPDATE
if (cPlatform() == dbipWindows || cSupportTray()) { if (cPlatform() == dbipWindows || cSupportTray()) {
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), SLOT(onEnableTrayIcon()), (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray)); auto workMode = Global::WorkMode().value();
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), SLOT(onEnableTrayIcon()), (workMode == dbiwmTrayOnly || workMode == dbiwmWindowAndTray));
if (cPlatform() == dbipWindows) { if (cPlatform() == dbipWindows) {
addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onEnableTaskbarIcon()), (cWorkMode() == dbiwmWindowOnly || cWorkMode() == dbiwmWindowAndTray)); addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onEnableTaskbarIcon()), (workMode == dbiwmWindowOnly || workMode == dbiwmWindowAndTray));
#ifndef OS_WIN_STORE #ifndef OS_WIN_STORE
addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), SLOT(onAutoStart()), cAutoStart()); addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), SLOT(onAutoStart()), cAutoStart());
@ -276,12 +277,11 @@ void GeneralWidget::onEnableTaskbarIcon() {
} }
void GeneralWidget::updateWorkmode() { void GeneralWidget::updateWorkmode() {
DBIWorkMode newMode = (_enableTrayIcon->checked() && (!_enableTaskbarIcon || _enableTaskbarIcon->checked())) ? dbiwmWindowAndTray : (_enableTrayIcon->checked() ? dbiwmTrayOnly : dbiwmWindowOnly); auto newMode = (_enableTrayIcon->checked() && (!_enableTaskbarIcon || _enableTaskbarIcon->checked())) ? dbiwmWindowAndTray : (_enableTrayIcon->checked() ? dbiwmTrayOnly : dbiwmWindowOnly);
if (cWorkMode() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) { if (Global::WorkMode().value() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) {
cSetSeenTrayTooltip(false); cSetSeenTrayTooltip(false);
} }
cSetWorkMode(newMode); Global::RefWorkMode().set(newMode);
App::wnd()->psUpdateWorkmode();
Local::writeSettings(); Local::writeSettings();
} }

View file

@ -30,18 +30,24 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/notifications_manager.h" #include "window/notifications_manager.h"
#include "boxes/notifications_box.h" #include "boxes/notifications_box.h"
#include "platform/platform_notifications_manager.h" #include "platform/platform_notifications_manager.h"
#include "auth_session.h"
namespace Settings { namespace Settings {
namespace {
using ChangeType = Window::Notifications::ChangeType;
} // namespace
NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_notify)) { NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_notify)) {
createControls(); createControls();
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType type) { subscribe(AuthSession::Current().notifications()->settingsChanged(), [this](ChangeType type) {
if (type == Notify::ChangeType::DesktopEnabled) { if (type == ChangeType::DesktopEnabled) {
desktopEnabledUpdated(); desktopEnabledUpdated();
} else if (type == Notify::ChangeType::ViewParams) { } else if (type == ChangeType::ViewParams) {
viewParamUpdated(); viewParamUpdated();
} else if (type == Notify::ChangeType::SoundEnabled) { } else if (type == ChangeType::SoundEnabled) {
_playSound->setChecked(Global::SoundNotify()); _playSound->setChecked(Global::SoundNotify());
} }
}); });
@ -95,7 +101,7 @@ void NotificationsWidget::onDesktopNotifications() {
} }
Global::SetDesktopNotify(_desktopNotifications->checked()); Global::SetDesktopNotify(_desktopNotifications->checked());
Local::writeUserSettings(); Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DesktopEnabled); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::DesktopEnabled);
} }
void NotificationsWidget::desktopEnabledUpdated() { void NotificationsWidget::desktopEnabledUpdated() {
@ -125,7 +131,7 @@ void NotificationsWidget::onShowSenderName() {
} }
Global::SetNotifyView(viewParam); Global::SetNotifyView(viewParam);
Local::writeUserSettings(); Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::ViewParams); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::ViewParams);
} }
void NotificationsWidget::onShowMessagePreview() { void NotificationsWidget::onShowMessagePreview() {
@ -143,7 +149,7 @@ void NotificationsWidget::onShowMessagePreview() {
Global::SetNotifyView(viewParam); Global::SetNotifyView(viewParam);
Local::writeUserSettings(); Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::ViewParams); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::ViewParams);
} }
void NotificationsWidget::viewParamUpdated() { void NotificationsWidget::viewParamUpdated() {
@ -159,10 +165,11 @@ void NotificationsWidget::onNativeNotifications() {
return; return;
} }
Window::Notifications::GetManager()->clearAllFast();
Global::SetNativeNotifications(_nativeNotifications->checked()); Global::SetNativeNotifications(_nativeNotifications->checked());
Local::writeUserSettings(); Local::writeUserSettings();
AuthSession::Current().notifications()->createManager();
if (Global::NativeNotifications()) { if (Global::NativeNotifications()) {
_advanced->slideUp(); _advanced->slideUp();
} else { } else {
@ -181,13 +188,13 @@ void NotificationsWidget::onPlaySound() {
Global::SetSoundNotify(_playSound->checked()); Global::SetSoundNotify(_playSound->checked());
Local::writeUserSettings(); Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::SoundEnabled); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::SoundEnabled);
} }
void NotificationsWidget::onIncludeMuted() { void NotificationsWidget::onIncludeMuted() {
Global::SetIncludeMuted(_includeMuted->checked()); Global::SetIncludeMuted(_includeMuted->checked());
Local::writeUserSettings(); Local::writeUserSettings();
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::IncludeMuted); AuthSession::Current().notifications()->settingsChanged().notify(ChangeType::IncludeMuted);
} }
} // namespace Settings } // namespace Settings

View file

@ -46,7 +46,7 @@ bool lock_telegram() {
bool minimize_telegram() { bool minimize_telegram() {
if (auto w = App::wnd()) { if (auto w = App::wnd()) {
if (cWorkMode() == dbiwmTrayOnly) { if (Global::WorkMode().value() == dbiwmTrayOnly) {
w->minimizeToTray(); w->minimizeToTray();
} else { } else {
w->setWindowState(Qt::WindowMinimized); w->setWindowState(Qt::WindowMinimized);

View file

@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "auth_session.h"
namespace internal { namespace internal {
namespace { namespace {
@ -719,7 +720,7 @@ StickerPanInner::StickerPanInner(QWidget *parent) : TWidget(parent)
_updateInlineItems.setSingleShot(true); _updateInlineItems.setSingleShot(true);
connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems())); connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems()));
subscribe(FileDownload::ImageLoaded(), [this] { subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] {
update(); update();
readVisibleSets(); readVisibleSets();
}); });

View file

@ -25,10 +25,18 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "messenger.h" #include "messenger.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include "platform/platform_file_utilities.h" #include "platform/platform_file_utilities.h"
#include "auth_session.h"
namespace Storage {
void Downloader::clearPriorities() {
++_priority;
}
} // namespace Storage
namespace { namespace {
int32 GlobalPriority = 1;
struct DataRequested { struct DataRequested {
DataRequested() { DataRequested() {
memset(v, 0, sizeof(v)); memset(v, 0, sizeof(v));
@ -37,16 +45,15 @@ struct DataRequested {
}; };
QMap<int32, DataRequested> DataRequestedMap; QMap<int32, DataRequested> DataRequestedMap;
// Debug flag to find out how we end up crashing. } // namespace
std::set<FileLoader*> MustNotDestroy;
}
struct FileLoaderQueue { struct FileLoaderQueue {
FileLoaderQueue(int32 limit) : queries(0), limit(limit), start(0), end(0) { FileLoaderQueue(int32 limit) : limit(limit) {
} }
int32 queries, limit; int queries = 0;
FileLoader *start, *end; int limit = 0;
FileLoader *start = nullptr;
FileLoader *end = nullptr;
}; };
namespace { namespace {
@ -64,7 +71,8 @@ namespace {
} }
FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading) FileLoader::FileLoader(const QString &toFile, int32 size, LocationType locationType, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading)
: _autoLoading(autoLoading) : _downloader(AuthSession::Current().downloader())
, _autoLoading(autoLoading)
, _file(toFile) , _file(toFile)
, _fname(toFile) , _fname(toFile)
, _toCache(toCache) , _toCache(toCache)
@ -158,8 +166,6 @@ void FileLoader::pause() {
} }
FileLoader::~FileLoader() { FileLoader::~FileLoader() {
t_assert(MustNotDestroy.find(this) == MustNotDestroy.cend());
if (_localTaskId) { if (_localTaskId) {
Local::cancelTask(_localTaskId); Local::cancelTask(_localTaskId);
} }
@ -197,11 +203,9 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &
_fileIsOpen = false; _fileIsOpen = false;
Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath()); Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath());
} }
FileDownload::ImageLoaded().notify(); _downloader->taskFinished().notify();
MustNotDestroy.insert(this);
emit progress(this); emit progress(this);
MustNotDestroy.erase(this);
loadNext(); loadNext();
} }
@ -224,45 +228,46 @@ void FileLoader::start(bool loadFirst, bool prior) {
} }
} }
auto currentPriority = _downloader->currentPriority();
FileLoader *before = 0, *after = 0; FileLoader *before = 0, *after = 0;
if (prior) { if (prior) {
if (_inQueue && _priority == GlobalPriority) { if (_inQueue && _priority == currentPriority) {
if (loadFirst) { if (loadFirst) {
if (!_prev) return startLoading(loadFirst, prior); if (!_prev) return startLoading(loadFirst, prior);
before = _queue->start; before = _queue->start;
} else { } else {
if (!_next || _next->_priority < GlobalPriority) return startLoading(loadFirst, prior); if (!_next || _next->_priority < currentPriority) return startLoading(loadFirst, prior);
after = _next; after = _next;
while (after->_next && after->_next->_priority == GlobalPriority) { while (after->_next && after->_next->_priority == currentPriority) {
after = after->_next; after = after->_next;
} }
} }
} else { } else {
_priority = GlobalPriority; _priority = currentPriority;
if (loadFirst) { if (loadFirst) {
if (_inQueue && !_prev) return startLoading(loadFirst, prior); if (_inQueue && !_prev) return startLoading(loadFirst, prior);
before = _queue->start; before = _queue->start;
} else { } else {
if (_inQueue) { if (_inQueue) {
if (_next && _next->_priority == GlobalPriority) { if (_next && _next->_priority == currentPriority) {
after = _next; after = _next;
} else if (_prev && _prev->_priority < GlobalPriority) { } else if (_prev && _prev->_priority < currentPriority) {
before = _prev; before = _prev;
while (before->_prev && before->_prev->_priority < GlobalPriority) { while (before->_prev && before->_prev->_priority < currentPriority) {
before = before->_prev; before = before->_prev;
} }
} else { } else {
return startLoading(loadFirst, prior); return startLoading(loadFirst, prior);
} }
} else { } else {
if (_queue->start && _queue->start->_priority == GlobalPriority) { if (_queue->start && _queue->start->_priority == currentPriority) {
after = _queue->start; after = _queue->start;
} else { } else {
before = _queue->start; before = _queue->start;
} }
} }
if (after) { if (after) {
while (after->_next && after->_next->_priority == GlobalPriority) { while (after->_next && after->_next->_priority == currentPriority) {
after = after->_next; after = after->_next;
} }
} }
@ -270,9 +275,9 @@ void FileLoader::start(bool loadFirst, bool prior) {
} }
} else { } else {
if (loadFirst) { if (loadFirst) {
if (_inQueue && (!_prev || _prev->_priority == GlobalPriority)) return startLoading(loadFirst, prior); if (_inQueue && (!_prev || _prev->_priority == currentPriority)) return startLoading(loadFirst, prior);
before = _prev; before = _prev;
while (before->_prev && before->_prev->_priority != GlobalPriority) { while (before->_prev && before->_prev->_priority != currentPriority) {
before = before->_prev; before = before->_prev;
} }
} else { } else {
@ -330,13 +335,11 @@ void FileLoader::cancel(bool fail) {
_fname = QString(); _fname = QString();
_file.setFileName(_fname); _file.setFileName(_fname);
MustNotDestroy.insert(this);
if (fail) { if (fail) {
emit failed(this, started); emit failed(this, started);
} else { } else {
emit progress(this); emit progress(this);
} }
MustNotDestroy.erase(this);
loadNext(); loadNext();
} }
@ -553,12 +556,10 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
} }
} }
if (_finished) { if (_finished) {
FileDownload::ImageLoaded().notify(); _downloader->taskFinished().notify();
} }
MustNotDestroy.insert(this);
emit progress(this); emit progress(this);
MustNotDestroy.erase(this);
loadNext(); loadNext();
} }
@ -609,9 +610,7 @@ bool mtpFileLoader::tryLoadLocal() {
} }
} }
MustNotDestroy.insert(this);
emit progress(this); emit progress(this);
MustNotDestroy.erase(this);
if (_localStatus != LocalNotTried) { if (_localStatus != LocalNotTried) {
return _finished; return _finished;
@ -690,11 +689,9 @@ void webFileLoader::onFinished(const QByteArray &data) {
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) { if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
Local::writeWebFile(_url, _data); Local::writeWebFile(_url, _data);
} }
FileDownload::ImageLoaded().notify(); _downloader->taskFinished().notify();
MustNotDestroy.insert(this);
emit progress(this); emit progress(this);
MustNotDestroy.erase(this);
loadNext(); loadNext();
} }
@ -1103,22 +1100,3 @@ void WebLoadMainManager::error(webFileLoader *loader) {
loader->onError(); loader->onError();
} }
} }
namespace MTP {
void clearLoaderPriorities() {
++GlobalPriority;
}
}
namespace FileDownload {
namespace {
base::Observable<void> ImageLoadedObservable;
} // namespace
base::Observable<void> &ImageLoaded() {
return ImageLoadedObservable;
}
} // namespace FileDownload

View file

@ -21,20 +21,29 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "core/observer.h" #include "core/observer.h"
#include "storage/localimageloader.h" // for TaskId
namespace MTP { namespace Storage {
void clearLoaderPriorities();
}
enum LocationType { class Downloader final {
UnknownFileLocation = 0, public:
// 1, 2, etc are used as "version" value in mediaKey() method. int currentPriority() const {
return _priority;
}
void clearPriorities();
base::Observable<void> &taskFinished() {
return _taskFinishedObservable;
}
private:
base::Observable<void> _taskFinishedObservable;
int _priority = 1;
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
}; };
} // namespace Storage
struct StorageImageSaved { struct StorageImageSaved {
StorageImageSaved() = default; StorageImageSaved() = default;
explicit StorageImageSaved(const QByteArray &data) : data(data) { explicit StorageImageSaved(const QByteArray &data) : data(data) {
@ -52,17 +61,6 @@ enum LocalLoadStatus {
LocalFailed, LocalFailed,
}; };
using TaskId = void*; // no interface, just id
enum LoadFromCloudSetting {
LoadFromCloudOrLocal,
LoadFromLocalOnly,
};
enum LoadToCacheSetting {
LoadToFileOnly,
LoadToCacheAsWell,
};
class mtpFileLoader; class mtpFileLoader;
class webFileLoader; class webFileLoader;
@ -129,6 +127,7 @@ signals:
protected: protected:
void readImage(const QSize &shrinkBox) const; void readImage(const QSize &shrinkBox) const;
Storage::Downloader *_downloader = nullptr;
FileLoader *_prev = nullptr; FileLoader *_prev = nullptr;
FileLoader *_next = nullptr; FileLoader *_next = nullptr;
int _priority = 0; int _priority = 0;
@ -338,9 +337,3 @@ static WebLoadManager * const FinishedWebLoadManager = SharedMemoryLocation<WebL
void reinitWebLoadManager(); void reinitWebLoadManager();
void stopWebLoadManager(); void stopWebLoadManager();
namespace FileDownload {
base::Observable<void> &ImageLoaded();
} // namespace FileDownload

View file

@ -99,6 +99,8 @@ struct SendMediaReady {
}; };
using TaskId = void*; // no interface, just id
class Task { class Task {
public: public:
virtual void process() = 0; // is executed in a separate thread virtual void process() = 0; // is executed in a separate thread

View file

@ -1088,11 +1088,14 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
stream >> v; stream >> v;
if (!_checkStreamStatus(stream)) return false; if (!_checkStreamStatus(stream)) return false;
switch (v) { auto newMode = [v] {
case dbiwmTrayOnly: cSetWorkMode(dbiwmTrayOnly); break; switch (v) {
case dbiwmWindowOnly: cSetWorkMode(dbiwmWindowOnly); break; case dbiwmTrayOnly: return dbiwmTrayOnly;
default: cSetWorkMode(dbiwmWindowAndTray); break; case dbiwmWindowOnly: return dbiwmWindowOnly;
};
return dbiwmWindowAndTray;
}; };
Global::RefWorkMode().set(newMode());
} break; } break;
case dbiConnectionType: { case dbiConnectionType: {
@ -2269,7 +2272,7 @@ void writeSettings() {
data.stream << quint32(dbiAutoStart) << qint32(cAutoStart()); data.stream << quint32(dbiAutoStart) << qint32(cAutoStart());
data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized()); data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized());
data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu()); data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu());
data.stream << quint32(dbiWorkMode) << qint32(cWorkMode()); data.stream << quint32(dbiWorkMode) << qint32(Global::WorkMode().value());
data.stream << quint32(dbiSeenTrayTooltip) << qint32(cSeenTrayTooltip()); data.stream << quint32(dbiSeenTrayTooltip) << qint32(cSeenTrayTooltip());
data.stream << quint32(dbiAutoUpdate) << qint32(cAutoUpdate()); data.stream << quint32(dbiAutoUpdate) << qint32(cAutoUpdate());
data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck()); data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck());
@ -2731,7 +2734,7 @@ public:
qint32 legacyTypeField = 0; qint32 legacyTypeField = 0;
stream >> first >> second >> legacyTypeField >> data; stream >> first >> second >> legacyTypeField >> data;
} }
void clearInMap() { void clearInMap() override {
StorageMap::iterator j = _imagesMap.find(_location); StorageMap::iterator j = _imagesMap.find(_location);
if (j != _imagesMap.cend() && j->first == _key) { if (j != _imagesMap.cend() && j->first == _key) {
clearKey(_key, FileOption::User); clearKey(_key, FileOption::User);

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "core/basic_types.h" #include "core/basic_types.h"
#include "storage/file_download.h"
namespace Window { namespace Window {
namespace Theme { namespace Theme {

View file

@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "auth_session.h" #include "auth_session.h"
#include "messenger.h" #include "messenger.h"
#include "storage/file_download.h"
namespace { namespace {

View file

@ -20,6 +20,34 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
using MediaKey = QPair<uint64, uint64>;
inline uint64 mediaMix32To64(int32 a, int32 b) {
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
}
enum LocationType {
UnknownFileLocation = 0,
// 1, 2, etc are used as "version" value in mediaKey() method.
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
};
// Old method, should not be used anymore.
//inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
// return MediaKey(mediaMix32To64(type, dc), id);
//}
// New method when version was introduced, type is not relevant anymore (all files are Documents).
inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id, int32 version) {
return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id);
}
inline StorageKey mediaKey(const MTPDfileLocation &location) {
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
}
typedef int32 UserId; typedef int32 UserId;
typedef int32 ChatId; typedef int32 ChatId;
typedef int32 ChannelId; typedef int32 ChannelId;

View file

@ -883,6 +883,10 @@ void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
_forgot = false; _forgot = false;
} }
bool RemoteImage::amLoading() const {
return _loader && _loader != CancelledFileLoader;
}
void RemoteImage::automaticLoad(const HistoryItem *item) { void RemoteImage::automaticLoad(const HistoryItem *item) {
if (loaded()) return; if (loaded()) return;

View file

@ -20,7 +20,18 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "storage/file_download.h" class FileLoader;
class mtpFileLoader;
enum LoadFromCloudSetting {
LoadFromCloudOrLocal,
LoadFromLocalOnly,
};
enum LoadToCacheSetting {
LoadToFileOnly,
LoadToCacheAsWell,
};
enum class ImageRoundRadius { enum class ImageRoundRadius {
None, None,
@ -317,9 +328,7 @@ protected:
private: private:
mutable FileLoader *_loader = nullptr; mutable FileLoader *_loader = nullptr;
bool amLoading() const { bool amLoading() const;
return _loader && _loader != CancelledFileLoader;
}
void doCheckload() const; void doCheckload() const;
void destroyLoaderDelayed(FileLoader *newValue = nullptr) const; void destroyLoaderDelayed(FileLoader *newValue = nullptr) const;
@ -328,7 +337,6 @@ private:
class StorageImage : public RemoteImage { class StorageImage : public RemoteImage {
public: public:
StorageImage(const StorageImageLocation &location, int32 size = 0); StorageImage(const StorageImageLocation &location, int32 size = 0);
StorageImage(const StorageImageLocation &location, QByteArray &bytes); StorageImage(const StorageImageLocation &location, QByteArray &bytes);
@ -511,19 +519,3 @@ inline bool operator==(const FileLocation &a, const FileLocation &b) {
inline bool operator!=(const FileLocation &a, const FileLocation &b) { inline bool operator!=(const FileLocation &a, const FileLocation &b) {
return !(a == b); return !(a == b);
} }
typedef QPair<uint64, uint64> MediaKey;
inline uint64 mediaMix32To64(int32 a, int32 b) {
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
}
// Old method, should not be used anymore.
//inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
// return MediaKey(mediaMix32To64(type, dc), id);
//}
// New method when version was introduced, type is not relevant anymore (all files are Documents).
inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id, int32 version) {
return (version > 0) ? MediaKey(mediaMix32To64(version, dc), id) : MediaKey(mediaMix32To64(type, dc), id);
}
inline StorageKey mediaKey(const MTPDfileLocation &location) {
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
}

View file

@ -43,6 +43,7 @@ MainWindow::MainWindow() : QWidget()
} }
}); });
subscribe(Global::RefUnreadCounterUpdate(), [this] { updateUnreadCounter(); }); subscribe(Global::RefUnreadCounterUpdate(), [this] { updateUnreadCounter(); });
subscribe(Global::RefWorkMode(), [this](DBIWorkMode mode) { workmodeUpdated(mode); });
_isActiveTimer->setSingleShot(true); _isActiveTimer->setSingleShot(true);
connect(_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActiveByTimer())); connect(_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActiveByTimer()));
@ -53,7 +54,7 @@ bool MainWindow::hideNoQuit() {
hideMediaview(); hideMediaview();
return true; return true;
} }
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) {
if (minimizeToTray()) { if (minimizeToTray()) {
Ui::showChatsList(); Ui::showChatsList();
return true; return true;

View file

@ -127,6 +127,9 @@ protected:
virtual void showTrayTooltip() { virtual void showTrayTooltip() {
} }
virtual void workmodeUpdated(DBIWorkMode mode) {
}
virtual void updateControlsGeometry(); virtual void updateControlsGeometry();
// This one is overriden in Windows for historical reasons. // This one is overriden in Windows for historical reasons.

View file

@ -25,25 +25,332 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "lang.h" #include "lang.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "apiwrap.h"
#include "auth_session.h"
namespace Window { namespace Window {
namespace Notifications { namespace Notifications {
void Start() { System::System(AuthSession *session) : _authSession(session) {
Default::Start(); createManager();
Platform::Notifications::Start();
_waitTimer.setTimeoutHandler([this] {
showNext();
});
subscribe(settingsChanged(), [this](ChangeType type) {
if (type == ChangeType::DesktopEnabled) {
App::wnd()->updateTrayMenu();
clearAll();
} else if (type == ChangeType::ViewParams) {
updateAll();
} else if (type == ChangeType::IncludeMuted) {
Notify::unreadCounterUpdated();
}
});
} }
Manager *GetManager() { void System::createManager() {
if (auto result = Platform::Notifications::GetManager()) { _manager = Platform::Notifications::Create(this);
return result; if (!_manager) {
_manager = std::make_unique<Default::Manager>(this);
} }
return Default::GetManager();
} }
void Finish() { void System::schedule(History *history, HistoryItem *item) {
Platform::Notifications::Finish(); if (App::quitting() || !history->currentNotification() || !App::api()) return;
Default::Finish();
PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0;
if (item->isSilent()) {
history->popNotification(item);
return;
}
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
if (haveSetting) {
if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
if (notifyByFrom) {
haveSetting = (item->from()->notify != UnknownNotifySettings);
if (haveSetting) {
if (notifyByFrom->notify != EmptyNotifySettings && notifyByFrom->notify->mute > unixtime()) {
history->popNotification(item);
return;
}
} else {
App::api()->requestNotifySetting(notifyByFrom);
}
} else {
history->popNotification(item);
return;
}
}
} else {
if (notifyByFrom && notifyByFrom->notify == UnknownNotifySettings) {
App::api()->requestNotifySetting(notifyByFrom);
}
App::api()->requestNotifySetting(history->peer);
}
if (!item->notificationReady()) {
haveSetting = false;
}
int delay = item->Has<HistoryMessageForwarded>() ? 500 : 100, t = unixtime();
auto ms = getms(true);
bool isOnline = App::main()->lastWasOnline(), otherNotOld = ((cOtherOnline() * 1000LL) + Global::OnlineCloudTimeout() > t * 1000LL);
bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - App::main()->lastSetOnline()) > t * 1000LL);
if (!isOnline && otherNotOld && otherLaterThanMe) {
delay = Global::NotifyCloudDelay();
} else if (cOtherOnline() >= t) {
delay = Global::NotifyDefaultDelay();
}
auto when = ms + delay;
_whenAlerts[history].insert(when, notifyByFrom);
if (Global::DesktopNotify() && !Platform::Notifications::SkipToast()) {
auto &whenMap = _whenMaps[history];
if (whenMap.constFind(item->id) == whenMap.cend()) {
whenMap.insert(item->id, when);
}
auto &addTo = haveSetting ? _waiters : _settingWaiters;
auto it = addTo.constFind(history);
if (it == addTo.cend() || it->when > when) {
addTo.insert(history, Waiter(item->id, when, notifyByFrom));
}
}
if (haveSetting) {
if (!_waitTimer.isActive() || _waitTimer.remainingTime() > delay) {
_waitTimer.start(delay);
}
}
}
void System::clearAll() {
_manager->clearAll();
for (auto i = _whenMaps.cbegin(), e = _whenMaps.cend(); i != e; ++i) {
i.key()->clearNotifications();
}
_whenMaps.clear();
_whenAlerts.clear();
_waiters.clear();
_settingWaiters.clear();
}
void System::clearFromHistory(History *history) {
_manager->clearFromHistory(history);
history->clearNotifications();
_whenMaps.remove(history);
_whenAlerts.remove(history);
_waiters.remove(history);
_settingWaiters.remove(history);
_waitTimer.stop();
showNext();
}
void System::clearFromItem(HistoryItem *item) {
_manager->clearFromItem(item);
}
void System::clearAllFast() {
_manager->clearAllFast();
_whenMaps.clear();
_whenAlerts.clear();
_waiters.clear();
_settingWaiters.clear();
}
void System::checkDelayed() {
int32 t = unixtime();
for (auto i = _settingWaiters.begin(); i != _settingWaiters.end();) {
auto history = i.key();
bool loaded = false, muted = false;
if (history->peer->notify != UnknownNotifySettings) {
if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) {
loaded = true;
} else if (PeerData *from = i.value().notifyByFrom) {
if (from->notify != UnknownNotifySettings) {
if (from->notify == EmptyNotifySettings || from->notify->mute <= t) {
loaded = true;
} else {
loaded = muted = true;
}
}
} else {
loaded = muted = true;
}
}
if (loaded) {
if (HistoryItem *item = App::histItemById(history->channelId(), i.value().msg)) {
if (!item->notificationReady()) {
loaded = false;
}
} else {
muted = true;
}
}
if (loaded) {
if (!muted) {
_waiters.insert(i.key(), i.value());
}
i = _settingWaiters.erase(i);
} else {
++i;
}
}
_waitTimer.stop();
showNext();
}
void System::showNext() {
if (App::quitting()) return;
auto ms = getms(true), nextAlert = 0LL;
bool alert = false;
int32 now = unixtime();
for (auto i = _whenAlerts.begin(); i != _whenAlerts.end();) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
i.value().erase(i.value().begin());
}
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= now)) {
alert = true;
} else if (f == EmptyNotifySettings || (f != UnknownNotifySettings && f->mute <= now)) { // notify by from()
alert = true;
}
}
if (i.value().isEmpty()) {
i = _whenAlerts.erase(i);
} else {
if (!nextAlert || nextAlert > i.value().begin().key()) {
nextAlert = i.value().begin().key();
}
++i;
}
}
if (alert) {
Platform::Notifications::FlashBounce();
App::playSound();
}
if (_waiters.isEmpty() || !Global::DesktopNotify() || Platform::Notifications::SkipToast()) {
if (nextAlert) {
_waitTimer.start(nextAlert - ms);
}
return;
}
while (true) {
auto next = 0LL;
HistoryItem *notifyItem = nullptr;
History *notifyHistory = nullptr;
for (auto i = _waiters.begin(); i != _waiters.end();) {
History *history = i.key();
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
auto j = _whenMaps.find(history);
if (j == _whenMaps.end()) {
history->clearNotifications();
i = _waiters.erase(i);
continue;
}
do {
auto k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
i.value().msg = k.key();
i.value().when = k.value();
break;
}
history->skipNotification();
} while (history->currentNotification());
}
if (!history->currentNotification()) {
_whenMaps.remove(history);
i = _waiters.erase(i);
continue;
}
auto when = i.value().when;
if (!notifyItem || next > when) {
next = when;
notifyItem = history->currentNotification();
notifyHistory = history;
}
++i;
}
if (notifyItem) {
if (next > ms) {
if (nextAlert && nextAlert < next) {
next = nextAlert;
nextAlert = 0;
}
_waitTimer.start(next - ms);
break;
} else {
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
int32 fwdCount = 1;
auto ms = getms(true);
History *history = notifyItem->history();
auto j = _whenMaps.find(history);
if (j == _whenMaps.cend()) {
history->clearNotifications();
} else {
HistoryItem *nextNotify = 0;
do {
history->skipNotification();
if (!history->hasNotification()) {
break;
}
j.value().remove((fwd ? fwd : notifyItem)->id);
do {
auto k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
nextNotify = history->currentNotification();
_waiters.insert(notifyHistory, Waiter(k.key(), k.value(), 0));
break;
}
history->skipNotification();
} while (history->hasNotification());
if (nextNotify) {
if (fwd) {
HistoryItem *nextFwd = nextNotify->Has<HistoryMessageForwarded>() ? nextNotify : nullptr;
if (nextFwd && fwd->author() == nextFwd->author() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) {
fwd = nextFwd;
++fwdCount;
} else {
nextNotify = nullptr;
}
} else {
nextNotify = nullptr;
}
}
} while (nextNotify);
}
_manager->showNotification(notifyItem, fwdCount);
if (!history->hasNotification()) {
_waiters.remove(history);
_whenMaps.remove(history);
continue;
}
}
} else {
break;
}
}
if (nextAlert) {
_waitTimer.start(nextAlert - ms);
}
}
void System::updateAll() {
_manager->updateAll();
} }
Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) { Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) {
@ -66,7 +373,7 @@ void Manager::notificationActivated(PeerId peerId, MsgId msgId) {
#endif #endif
if (App::passcoded()) { if (App::passcoded()) {
window->setInnerFocus(); window->setInnerFocus();
window->notifyClear(); system()->clearAll();
} else { } else {
auto tomsg = !history->peer->isUser() && (msgId > 0); auto tomsg = !history->peer->isUser() && (msgId > 0);
if (tomsg) { if (tomsg) {
@ -76,7 +383,7 @@ void Manager::notificationActivated(PeerId peerId, MsgId msgId) {
} }
} }
Ui::showPeerHistory(history, tomsg ? msgId : ShowAtUnreadMsgId); Ui::showPeerHistory(history, tomsg ? msgId : ShowAtUnreadMsgId);
window->notifyClear(history); system()->clearFromHistory(history);
} }
} }
onAfterNotificationActivated(peerId, msgId); onAfterNotificationActivated(peerId, msgId);

View file

@ -20,17 +20,100 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
class AuthSession;
namespace Platform {
namespace Notifications {
class Manager;
} // namespace Notifications
} // namespace Platform
namespace Window {
namespace Notifications {
enum class ChangeType {
SoundEnabled,
IncludeMuted,
DesktopEnabled,
ViewParams,
MaxCount,
Corner,
DemoIsShown,
};
} // namespace Notifications
} // namespace Window
namespace base {
template <>
struct custom_is_fast_copy_type<Window::Notifications::ChangeType> : public std::true_type {
};
} // namespace base
namespace Window { namespace Window {
namespace Notifications { namespace Notifications {
class Manager; class Manager;
void Start(); class System final : private base::Subscriber {
Manager *GetManager(); public:
void Finish(); System(AuthSession *session);
void createManager();
void checkDelayed();
void schedule(History *history, HistoryItem *item);
void clearFromHistory(History *history);
void clearFromItem(HistoryItem *item);
void clearAll();
void clearAllFast();
void updateAll();
base::Observable<ChangeType> &settingsChanged() {
return _settingsChanged;
}
AuthSession *authSession() {
return _authSession;
}
private:
void showNext();
AuthSession *_authSession = nullptr;
QMap<History*, QMap<MsgId, TimeMs>> _whenMaps;
struct Waiter {
Waiter(MsgId msg, TimeMs when, PeerData *notifyByFrom)
: msg(msg)
, when(when)
, notifyByFrom(notifyByFrom) {
}
MsgId msg;
TimeMs when;
PeerData *notifyByFrom;
};
using Waiters = QMap<History*, Waiter>;
Waiters _waiters;
Waiters _settingWaiters;
SingleTimer _waitTimer;
QMap<History*, QMap<TimeMs, PeerData*>> _whenAlerts;
std::unique_ptr<Manager> _manager;
base::Observable<ChangeType> _settingsChanged;
};
class Manager { class Manager {
public: public:
Manager(System *system) : _system(system) {
}
void showNotification(HistoryItem *item, int forwardedCount) { void showNotification(HistoryItem *item, int forwardedCount) {
doShowNotification(item, forwardedCount); doShowNotification(item, forwardedCount);
} }
@ -63,6 +146,10 @@ public:
virtual ~Manager() = default; virtual ~Manager() = default;
protected: protected:
System *system() const {
return _system;
}
virtual void doUpdateAll() = 0; virtual void doUpdateAll() = 0;
virtual void doShowNotification(HistoryItem *item, int forwardedCount) = 0; virtual void doShowNotification(HistoryItem *item, int forwardedCount) = 0;
virtual void doClearAll() = 0; virtual void doClearAll() = 0;
@ -74,10 +161,15 @@ protected:
virtual void onAfterNotificationActivated(PeerId peerId, MsgId msgId) { virtual void onAfterNotificationActivated(PeerId peerId, MsgId msgId) {
} }
private:
System *_system = nullptr;
}; };
class NativeManager : public Manager { class NativeManager : public Manager {
protected: protected:
using Manager::Manager;
void doUpdateAll() override { void doUpdateAll() override {
doClearAllFast(); doClearAllFast();
} }

View file

@ -31,14 +31,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include "storage/file_download.h"
#include "auth_session.h"
namespace Window { namespace Window {
namespace Notifications { namespace Notifications {
namespace Default { namespace Default {
namespace { namespace {
NeverFreedPointer<Manager> ManagerInstance;
int notificationMaxHeight() { int notificationMaxHeight() {
return st::notifyMinHeight + st::notifyReplyArea.heightMax + st::notifyBorderWidth; return st::notifyMinHeight + st::notifyReplyArea.heightMax + st::notifyBorderWidth;
} }
@ -59,32 +59,24 @@ internal::Widget::Direction notificationShiftDirection() {
} // namespace } // namespace
void Start() { std::unique_ptr<Manager> Create(System *system) {
ManagerInstance.createIfNull(); return std::make_unique<Manager>(system);
} }
Manager *GetManager() { Manager::Manager(System *system) : Notifications::Manager(system) {
return ManagerInstance.data(); subscribe(system->authSession()->downloader()->taskFinished(), [this] {
} for_const (auto &notification, _notifications) {
void Finish() {
ManagerInstance.clear();
}
Manager::Manager() {
subscribe(FileDownload::ImageLoaded(), [this] {
for_const (auto notification, _notifications) {
notification->updatePeerPhoto(); notification->updatePeerPhoto();
} }
}); });
subscribe(Global::RefNotifySettingsChanged(), [this](Notify::ChangeType change) { subscribe(system->settingsChanged(), [this](ChangeType change) {
settingsChanged(change); settingsChanged(change);
}); });
_inputCheckTimer.setTimeoutHandler([this] { checkLastInput(); }); _inputCheckTimer.setTimeoutHandler([this] { checkLastInput(); });
} }
bool Manager::hasReplyingNotification() const { bool Manager::hasReplyingNotification() const {
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
if (notification->isReplying()) { if (notification->isReplying()) {
return true; return true;
} }
@ -92,20 +84,20 @@ bool Manager::hasReplyingNotification() const {
return false; return false;
} }
void Manager::settingsChanged(Notify::ChangeType change) { void Manager::settingsChanged(ChangeType change) {
if (change == Notify::ChangeType::Corner) { if (change == ChangeType::Corner) {
auto startPosition = notificationStartPosition(); auto startPosition = notificationStartPosition();
auto shiftDirection = notificationShiftDirection(); auto shiftDirection = notificationShiftDirection();
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
notification->updatePosition(startPosition, shiftDirection); notification->updatePosition(startPosition, shiftDirection);
} }
if (_hideAll) { if (_hideAll) {
_hideAll->updatePosition(startPosition, shiftDirection); _hideAll->updatePosition(startPosition, shiftDirection);
} }
} else if (change == Notify::ChangeType::MaxCount) { } else if (change == ChangeType::MaxCount) {
int allow = Global::NotificationsCount(); int allow = Global::NotificationsCount();
for (int i = _notifications.size(); i != 0;) { for (int i = _notifications.size(); i != 0;) {
auto notification = _notifications[--i]; auto &notification = _notifications[--i];
if (notification->isUnlinked()) continue; if (notification->isUnlinked()) continue;
if (--allow < 0) { if (--allow < 0) {
notification->unlinkHistory(); notification->unlinkHistory();
@ -116,14 +108,14 @@ void Manager::settingsChanged(Notify::ChangeType change) {
showNextFromQueue(); showNextFromQueue();
} }
} }
} else if (change == Notify::ChangeType::DemoIsShown) { } else if (change == ChangeType::DemoIsShown) {
auto demoIsShown = Global::NotificationsDemoIsShown(); auto demoIsShown = Global::NotificationsDemoIsShown();
_demoMasterOpacity.start([this] { demoMasterOpacityCallback(); }, demoIsShown ? 1. : 0., demoIsShown ? 0. : 1., st::notifyFastAnim); _demoMasterOpacity.start([this] { demoMasterOpacityCallback(); }, demoIsShown ? 1. : 0., demoIsShown ? 0. : 1., st::notifyFastAnim);
} }
} }
void Manager::demoMasterOpacityCallback() { void Manager::demoMasterOpacityCallback() {
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
notification->updateOpacity(); notification->updateOpacity();
} }
if (_hideAll) { if (_hideAll) {
@ -138,7 +130,7 @@ float64 Manager::demoMasterOpacity() const {
void Manager::checkLastInput() { void Manager::checkLastInput() {
auto replying = hasReplyingNotification(); auto replying = hasReplyingNotification();
auto waiting = false; auto waiting = false;
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
if (!notification->checkLastInput(replying)) { if (!notification->checkLastInput(replying)) {
waiting = true; waiting = true;
} }
@ -151,7 +143,7 @@ void Manager::checkLastInput() {
void Manager::startAllHiding() { void Manager::startAllHiding() {
if (!hasReplyingNotification()) { if (!hasReplyingNotification()) {
int notHidingCount = 0; int notHidingCount = 0;
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
if (notification->isShowing()) { if (notification->isShowing()) {
++notHidingCount; ++notHidingCount;
} else { } else {
@ -166,7 +158,7 @@ void Manager::startAllHiding() {
} }
void Manager::stopAllHiding() { void Manager::stopAllHiding() {
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
notification->stopHiding(); notification->stopHiding();
} }
if (_hideAll) { if (_hideAll) {
@ -175,46 +167,52 @@ void Manager::stopAllHiding() {
} }
void Manager::showNextFromQueue() { void Manager::showNextFromQueue() {
if (!_queuedNotifications.isEmpty()) { auto guard = base::scope_guard([this] {
int count = Global::NotificationsCount(); if (_positionsOutdated) {
for_const (auto notification, _notifications) { moveWidgets();
if (notification->isUnlinked()) continue;
--count;
}
if (count > 0) {
auto startPosition = notificationStartPosition();
auto startShift = 0;
auto shiftDirection = notificationShiftDirection();
do {
auto queued = _queuedNotifications.front();
_queuedNotifications.pop_front();
auto notification = std::make_unique<Notification>(
queued.history,
queued.peer,
queued.author,
queued.item,
queued.forwardedCount,
startPosition, startShift, shiftDirection);
Platform::Notifications::CustomNotificationShownHook(notification.get());
_notifications.push_back(notification.release());
--count;
} while (count > 0 && !_queuedNotifications.isEmpty());
_positionsOutdated = true;
checkLastInput();
} }
});
if (_queuedNotifications.empty()) {
return;
} }
if (_positionsOutdated) { int count = Global::NotificationsCount();
moveWidgets(); for_const (auto &notification, _notifications) {
if (notification->isUnlinked()) continue;
--count;
} }
if (count <= 0) {
return;
}
auto startPosition = notificationStartPosition();
auto startShift = 0;
auto shiftDirection = notificationShiftDirection();
do {
auto queued = _queuedNotifications.front();
_queuedNotifications.pop_front();
auto notification = std::make_unique<Notification>(
this,
queued.history,
queued.peer,
queued.author,
queued.item,
queued.forwardedCount,
startPosition, startShift, shiftDirection);
Platform::Notifications::CustomNotificationShownHook(notification.get());
_notifications.push_back(std::move(notification));
--count;
} while (count > 0 && !_queuedNotifications.empty());
_positionsOutdated = true;
checkLastInput();
} }
void Manager::moveWidgets() { void Manager::moveWidgets() {
auto shift = st::notifyDeltaY; auto shift = st::notifyDeltaY;
int lastShift = 0, lastShiftCurrent = 0, count = 0; int lastShift = 0, lastShiftCurrent = 0, count = 0;
for (int i = _notifications.size(); i != 0;) { for (int i = _notifications.size(); i != 0;) {
auto notification = _notifications[--i]; auto &notification = _notifications[--i];
if (notification->isUnlinked()) continue; if (notification->isUnlinked()) continue;
notification->changeShift(shift); notification->changeShift(shift);
@ -226,10 +224,10 @@ void Manager::moveWidgets() {
++count; ++count;
} }
if (count > 1 || !_queuedNotifications.isEmpty()) { if (count > 1 || !_queuedNotifications.empty()) {
auto deltaY = st::notifyHideAllHeight + st::notifyDeltaY; auto deltaY = st::notifyHideAllHeight + st::notifyDeltaY;
if (!_hideAll) { if (!_hideAll) {
_hideAll = new HideAllButton(notificationStartPosition(), lastShiftCurrent, notificationShiftDirection()); _hideAll = std::make_unique<HideAllButton>(this, notificationStartPosition(), lastShiftCurrent, notificationShiftDirection());
} }
_hideAll->changeShift(lastShift); _hideAll->changeShift(lastShift);
_hideAll->stopHiding(); _hideAll->stopHiding();
@ -243,10 +241,12 @@ void Manager::changeNotificationHeight(Notification *notification, int newHeight
if (!deltaHeight) return; if (!deltaHeight) return;
notification->addToHeight(deltaHeight); notification->addToHeight(deltaHeight);
auto index = _notifications.indexOf(notification); auto it = std::find_if(_notifications.cbegin(), _notifications.cend(), [notification](auto &item) {
if (index > 0) { return (item.get() == notification);
for (int i = 0; i != index; ++i) { });
auto notification = _notifications[i]; if (it != _notifications.cend()) {
for (auto i = _notifications.cbegin(); i != it; ++i) {
auto &notification = *i;
if (notification->isUnlinked()) continue; if (notification->isUnlinked()) continue;
notification->addToShift(deltaHeight); notification->addToShift(deltaHeight);
@ -266,22 +266,21 @@ void Manager::unlinkFromShown(Notification *remove) {
showNextFromQueue(); showNextFromQueue();
} }
void Manager::removeFromShown(Notification *remove) { void Manager::removeWidget(internal::Widget *remove) {
if (remove) { if (remove == _hideAll.get()) {
auto index = _notifications.indexOf(remove); _hideAll.reset();
if (index >= 0) { } else if (remove) {
_notifications.removeAt(index); auto it = std::find_if(_notifications.cbegin(), _notifications.cend(), [remove](auto &item) {
return item.get() == remove;
});
if (it != _notifications.cend()) {
_notifications.erase(it);
_positionsOutdated = true; _positionsOutdated = true;
} }
} }
showNextFromQueue(); showNextFromQueue();
} }
void Manager::removeHideAll(HideAllButton *remove) {
if (remove == _hideAll) {
_hideAll = nullptr;
}
}
void Manager::doShowNotification(HistoryItem *item, int forwardedCount) { void Manager::doShowNotification(HistoryItem *item, int forwardedCount) {
_queuedNotifications.push_back(QueuedNotification(item, forwardedCount)); _queuedNotifications.push_back(QueuedNotification(item, forwardedCount));
showNextFromQueue(); showNextFromQueue();
@ -289,7 +288,7 @@ void Manager::doShowNotification(HistoryItem *item, int forwardedCount) {
void Manager::doClearAll() { void Manager::doClearAll() {
_queuedNotifications.clear(); _queuedNotifications.clear();
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
notification->unlinkHistory(); notification->unlinkHistory();
} }
showNextFromQueue(); showNextFromQueue();
@ -297,11 +296,8 @@ void Manager::doClearAll() {
void Manager::doClearAllFast() { void Manager::doClearAllFast() {
_queuedNotifications.clear(); _queuedNotifications.clear();
auto notifications = base::take(_notifications); base::take(_notifications);
for_const (auto notification, notifications) { base::take(_hideAll);
delete notification;
}
delete base::take(_hideAll);
} }
void Manager::doClearFromHistory(History *history) { void Manager::doClearFromHistory(History *history) {
@ -312,7 +308,7 @@ void Manager::doClearFromHistory(History *history) {
++i; ++i;
} }
} }
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
if (notification->unlinkHistory(history)) { if (notification->unlinkHistory(history)) {
_positionsOutdated = true; _positionsOutdated = true;
} }
@ -321,20 +317,18 @@ void Manager::doClearFromHistory(History *history) {
} }
void Manager::doClearFromItem(HistoryItem *item) { void Manager::doClearFromItem(HistoryItem *item) {
for (auto i = 0, queuedCount = _queuedNotifications.size(); i != queuedCount; ++i) { _queuedNotifications.erase(std::remove_if(_queuedNotifications.begin(), _queuedNotifications.end(), [item](auto &queued) {
if (_queuedNotifications[i].item == item) { return (queued.item == item);
_queuedNotifications.removeAt(i); }), _queuedNotifications.cend());
break;
} for_const (auto &notification, _notifications) {
}
for_const (auto notification, _notifications) {
// Calls unlinkFromShown() -> showNextFromQueue() // Calls unlinkFromShown() -> showNextFromQueue()
notification->itemRemoved(item); notification->itemRemoved(item);
} }
} }
void Manager::doUpdateAll() { void Manager::doUpdateAll() {
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
notification->updateNotifyDisplay(); notification->updateNotifyDisplay();
} }
} }
@ -345,7 +339,8 @@ Manager::~Manager() {
namespace internal { namespace internal {
Widget::Widget(QPoint startPosition, int shift, Direction shiftDirection) : TWidget(nullptr) Widget::Widget(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection) : TWidget(nullptr)
, _manager(manager)
, _startPosition(startPosition) , _startPosition(startPosition)
, _direction(shiftDirection) , _direction(shiftDirection)
, a_shift(shift) , a_shift(shift)
@ -364,12 +359,10 @@ void Widget::destroyDelayed() {
if (_deleted) return; if (_deleted) return;
_deleted = true; _deleted = true;
// Ubuntu has a lag if deleteLater() called immediately. // Ubuntu has a lag if a fully transparent widget is destroyed immediately.
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64 App::CallDelayed(1000, this, [this] {
QTimer::singleShot(1000, [this] { delete this; }); manager()->removeWidget(this);
#else // Q_OS_LINUX32 || Q_OS_LINUX64 });
deleteLater();
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
} }
void Widget::opacityAnimationCallback() { void Widget::opacityAnimationCallback() {
@ -411,9 +404,7 @@ void Widget::hideAnimated(float64 duration, const anim::transition &func) {
} }
void Widget::updateOpacity() { void Widget::updateOpacity() {
if (auto manager = ManagerInstance.data()) { setWindowOpacity(_a_opacity.current(_hiding ? 0. : 1.) * _manager->demoMasterOpacity());
setWindowOpacity(_a_opacity.current(_hiding ? 0. : 1.) * manager->demoMasterOpacity());
}
} }
void Widget::changeShift(int top) { void Widget::changeShift(int top) {
@ -469,7 +460,7 @@ void Background::paintEvent(QPaintEvent *e) {
p.fillRect(st::notifyBorderWidth, height() - st::notifyBorderWidth, width() - 2 * st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder); p.fillRect(st::notifyBorderWidth, height() - st::notifyBorderWidth, width() - 2 * st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder);
} }
Notification::Notification(History *history, PeerData *peer, PeerData *author, HistoryItem *msg, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection) : Widget(startPosition, shift, shiftDirection) Notification::Notification(Manager *manager, History *history, PeerData *peer, PeerData *author, HistoryItem *msg, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection) : Widget(manager, startPosition, shift, shiftDirection)
, _history(history) , _history(history)
, _peer(peer) , _peer(peer)
, _author(author) , _author(author)
@ -711,9 +702,7 @@ bool Notification::canReply() const {
} }
void Notification::unlinkHistoryInManager() { void Notification::unlinkHistoryInManager() {
if (auto manager = ManagerInstance.data()) { manager()->unlinkFromShown(this);
manager->unlinkFromShown(this);
}
} }
void Notification::toggleActionButtons(bool visible) { void Notification::toggleActionButtons(bool visible) {
@ -766,19 +755,15 @@ void Notification::showReplyField() {
void Notification::sendReply() { void Notification::sendReply() {
if (!_history) return; if (!_history) return;
if (auto manager = ManagerInstance.data()) { auto peerId = _history->peer->id;
auto peerId = _history->peer->id; auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
auto msgId = _item ? _item->id : ShowAtUnreadMsgId; manager()->notificationReplied(peerId, msgId, _replyArea->getLastText());
manager->notificationReplied(peerId, msgId, _replyArea->getLastText());
manager->startAllHiding(); manager()->startAllHiding();
}
} }
void Notification::changeHeight(int newHeight) { void Notification::changeHeight(int newHeight) {
if (auto manager = ManagerInstance.data()) { manager()->changeNotificationHeight(this, newHeight);
manager->changeNotificationHeight(this, newHeight);
}
} }
bool Notification::unlinkHistory(History *history) { bool Notification::unlinkHistory(History *history) {
@ -793,9 +778,7 @@ bool Notification::unlinkHistory(History *history) {
void Notification::enterEventHook(QEvent *e) { void Notification::enterEventHook(QEvent *e) {
if (!_history) return; if (!_history) return;
if (auto manager = ManagerInstance.data()) { manager()->stopAllHiding();
manager->stopAllHiding();
}
if (!_replyArea && canReply()) { if (!_replyArea && canReply()) {
toggleActionButtons(true); toggleActionButtons(true);
} }
@ -803,9 +786,7 @@ void Notification::enterEventHook(QEvent *e) {
void Notification::leaveEventHook(QEvent *e) { void Notification::leaveEventHook(QEvent *e) {
if (!_history) return; if (!_history) return;
if (auto manager = ManagerInstance.data()) { manager()->startAllHiding();
manager->startAllHiding();
}
toggleActionButtons(false); toggleActionButtons(false);
} }
@ -821,11 +802,9 @@ void Notification::mousePressEvent(QMouseEvent *e) {
unlinkHistoryInManager(); unlinkHistoryInManager();
} else { } else {
e->ignore(); e->ignore();
if (auto manager = ManagerInstance.data()) { auto peerId = _history->peer->id;
auto peerId = _history->peer->id; auto msgId = _item ? _item->id : ShowAtUnreadMsgId;
auto msgId = _item ? _item->id : ShowAtUnreadMsgId; manager()->notificationActivated(peerId, msgId);
manager->notificationActivated(peerId, msgId);
}
} }
} }
@ -850,13 +829,7 @@ void Notification::onHideByTimer() {
startHiding(); startHiding();
} }
Notification::~Notification() { HideAllButton::HideAllButton(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection) : Widget(manager, startPosition, shift, shiftDirection) {
if (auto manager = ManagerInstance.data()) {
manager->removeFromShown(this);
}
}
HideAllButton::HideAllButton(QPoint startPosition, int shift, Direction shiftDirection) : Widget(startPosition, shift, shiftDirection) {
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
auto position = computePosition(st::notifyHideAllHeight); auto position = computePosition(st::notifyHideAllHeight);
@ -885,12 +858,6 @@ void HideAllButton::stopHiding() {
hideStop(); hideStop();
} }
HideAllButton::~HideAllButton() {
if (auto manager = ManagerInstance.data()) {
manager->removeHideAll(this);
}
}
void HideAllButton::enterEventHook(QEvent *e) { void HideAllButton::enterEventHook(QEvent *e) {
_mouseOver = true; _mouseOver = true;
update(); update();
@ -908,9 +875,7 @@ void HideAllButton::mousePressEvent(QMouseEvent *e) {
void HideAllButton::mouseReleaseEvent(QMouseEvent *e) { void HideAllButton::mouseReleaseEvent(QMouseEvent *e) {
auto mouseDown = base::take(_mouseDown); auto mouseDown = base::take(_mouseDown);
if (mouseDown && _mouseOver) { if (mouseDown && _mouseOver) {
if (auto manager = ManagerInstance.data()) { manager()->clearAll();
manager->clearAll();
}
} }
} }

View file

@ -39,18 +39,15 @@ class HideAllButton;
} // namespace internal } // namespace internal
class Manager; class Manager;
std::unique_ptr<Manager> Create(System *system);
void Start();
Manager *GetManager();
void Finish();
class Manager : public Notifications::Manager, private base::Subscriber { class Manager : public Notifications::Manager, private base::Subscriber {
public: public:
Manager(); Manager(System *system);
template <typename Method> template <typename Method>
void enumerateNotifications(Method method) { void enumerateNotifications(Method method) {
for_const (auto notification, _notifications) { for_const (auto &notification, _notifications) {
method(notification); method(notification);
} }
} }
@ -73,25 +70,24 @@ private:
void showNextFromQueue(); void showNextFromQueue();
void unlinkFromShown(Notification *remove); void unlinkFromShown(Notification *remove);
void removeFromShown(Notification *remove);
void removeHideAll(HideAllButton *remove);
void startAllHiding(); void startAllHiding();
void stopAllHiding(); void stopAllHiding();
void checkLastInput(); void checkLastInput();
void removeWidget(internal::Widget *remove);
float64 demoMasterOpacity() const; float64 demoMasterOpacity() const;
void demoMasterOpacityCallback(); void demoMasterOpacityCallback();
void moveWidgets(); void moveWidgets();
void changeNotificationHeight(Notification *widget, int newHeight); void changeNotificationHeight(Notification *widget, int newHeight);
void settingsChanged(Notify::ChangeType change); void settingsChanged(ChangeType change);
bool hasReplyingNotification() const; bool hasReplyingNotification() const;
using Notifications = QList<Notification*>; std::vector<std::unique_ptr<Notification>> _notifications;
Notifications _notifications;
HideAllButton *_hideAll = nullptr; std::unique_ptr<HideAllButton> _hideAll;
bool _positionsOutdated = false; bool _positionsOutdated = false;
SingleTimer _inputCheckTimer; SingleTimer _inputCheckTimer;
@ -111,8 +107,7 @@ private:
HistoryItem *item; HistoryItem *item;
int forwardedCount; int forwardedCount;
}; };
using QueuedNotifications = QList<QueuedNotification>; std::deque<QueuedNotification> _queuedNotifications;
QueuedNotifications _queuedNotifications;
Animation _demoMasterOpacity; Animation _demoMasterOpacity;
@ -126,7 +121,7 @@ public:
Up, Up,
Down, Down,
}; };
Widget(QPoint startPosition, int shift, Direction shiftDirection); Widget(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection);
bool isShowing() const { bool isShowing() const {
return _a_opacity.animating() && !_hiding; return _a_opacity.animating() && !_hiding;
@ -149,6 +144,11 @@ protected:
virtual void updateGeometry(int x, int y, int width, int height); virtual void updateGeometry(int x, int y, int width, int height);
protected:
Manager *manager() const {
return _manager;
}
private: private:
void opacityAnimationCallback(); void opacityAnimationCallback();
void destroyDelayed(); void destroyDelayed();
@ -156,6 +156,8 @@ private:
void hideAnimated(float64 duration, const anim::transition &func); void hideAnimated(float64 duration, const anim::transition &func);
void step_shift(float64 ms, bool timer); void step_shift(float64 ms, bool timer);
Manager *_manager = nullptr;
bool _hiding = false; bool _hiding = false;
bool _deleted = false; bool _deleted = false;
Animation _a_opacity; Animation _a_opacity;
@ -180,7 +182,7 @@ class Notification : public Widget {
Q_OBJECT Q_OBJECT
public: public:
Notification(History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection); Notification(Manager *manager, History *history, PeerData *peer, PeerData *author, HistoryItem *item, int forwardedCount, QPoint startPosition, int shift, Direction shiftDirection);
void startHiding(); void startHiding();
void stopHiding(); void stopHiding();
@ -200,8 +202,6 @@ public:
bool unlinkHistory(History *history = nullptr); bool unlinkHistory(History *history = nullptr);
bool checkLastInput(bool hasReplyingNotifications); bool checkLastInput(bool hasReplyingNotifications);
~Notification();
protected: protected:
void enterEventHook(QEvent *e) override; void enterEventHook(QEvent *e) override;
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
@ -260,14 +260,12 @@ private:
class HideAllButton : public Widget { class HideAllButton : public Widget {
public: public:
HideAllButton(QPoint startPosition, int shift, Direction shiftDirection); HideAllButton(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection);
void startHiding(); void startHiding();
void startHidingFast(); void startHidingFast();
void stopHiding(); void stopHiding();
~HideAllButton();
protected: protected:
void enterEventHook(QEvent *e) override; void enterEventHook(QEvent *e) override;
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;

View file

@ -112,7 +112,13 @@ void CachedUserpics::onClear() {
CachedUserpics::~CachedUserpics() { CachedUserpics::~CachedUserpics() {
if (_someSavedFlag) { if (_someSavedFlag) {
psDeleteDir(cWorkingDir() + qsl("tdata/temp")); TimeMs result = 0;
for_const (auto &item, _images) {
QFile(item.path).remove();
}
// This works about 1200ms on Windows for a folder with one image O_o
// psDeleteDir(cWorkingDir() + qsl("tdata/temp"));
} }
} }

View file

@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "boxes/aboutbox.h" #include "boxes/aboutbox.h"
#include "lang.h" #include "lang.h"
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "auth_session.h"
namespace Window { namespace Window {
@ -70,7 +71,7 @@ MainMenu::MainMenu(QWidget *parent) : TWidget(parent)
_version->setLink(1, MakeShared<UrlClickHandler>(qsl("https://desktop.telegram.org/changelog"))); _version->setLink(1, MakeShared<UrlClickHandler>(qsl("https://desktop.telegram.org/changelog")));
_version->setLink(2, MakeShared<LambdaClickHandler>([] { Ui::show(Box<AboutBox>()); })); _version->setLink(2, MakeShared<LambdaClickHandler>([] { Ui::show(Box<AboutBox>()); }));
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
subscribe(Global::RefConnectionTypeChanged(), [this] { updateConnectionState(); }); subscribe(Global::RefConnectionTypeChanged(), [this] { updateConnectionState(); });
updateConnectionState(); updateConnectionState();
} }