diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 9a21f66af..9ee03eee4 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -35,6 +35,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/observer.h" #include "observer_peer.h" #include "window/chat_background.h" +#include "window/notifications_abstract_manager.h" #include "history/history_location_manager.h" namespace { @@ -728,6 +729,7 @@ AppClass::AppClass() : QObject() style::startManager(); anim::startManager(); historyInit(); + Window::Notifications::start(); DEBUG_LOG(("Application Info: inited...")); @@ -741,7 +743,8 @@ AppClass::AppClass() : QObject() DEBUG_LOG(("Application Info: starting app...")); - QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database + // Create mime database, so it won't be slow later. + QMimeDatabase().mimeTypeForName(qsl("text/plain")); _window = new MainWindow(); _window->createWinId(); @@ -1100,6 +1103,8 @@ AppClass::~AppClass() { auto window = createAndSwap(_window); delete window; + Window::Notifications::finish(); + anim::stopManager(); stopWebLoadManager(); @@ -1126,9 +1131,9 @@ AppClass *AppClass::app() { } MainWindow *AppClass::wnd() { - return AppObject ? AppObject->_window : 0; + return AppObject ? AppObject->_window : nullptr; } MainWidget *AppClass::main() { - return (AppObject && AppObject->_window) ? AppObject->_window->mainWidget() : 0; + return (AppObject && AppObject->_window) ? AppObject->_window->mainWidget() : nullptr; } diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 43c59329e..f36b74141 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -43,6 +43,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" #include "apiwrap.h" #include "settings/settings_widget.h" +#include "window/notifications_default_manager.h" ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent) , _shadow(st::boxShadow) @@ -81,289 +82,6 @@ void ConnectingWidget::onReconnect() { MTP::restart(); } -NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : TWidget(0) -, history(msg->history()) -, item(msg) -, fwdCount(fwdCount) -#if defined Q_OS_WIN && !defined Q_OS_WINRT -, started(GetTickCount()) -#endif // Q_OS_WIN && !Q_OS_WINRT -, close(this, st::notifyClose) -, alphaDuration(st::notifyFastAnim) -, posDuration(st::notifyFastAnim) -, hiding(false) -, _index(0) -, a_opacity(0) -, a_func(anim::linear) -, a_y(y + st::notifyHeight + st::notifyDeltaY) -, _a_appearance(animation(this, &NotifyWindow::step_appearance)) { - - updateNotifyDisplay(); - - hideTimer.setSingleShot(true); - connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer())); - - inputTimer.setSingleShot(true); - connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput())); - - connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistoryAndNotify())); - close.setAcceptBoth(true); - close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y()); - close.show(); - - a_y.start(y); - setGeometry(x, a_y.current(), st::notifyWidth, st::notifyHeight); - - a_opacity.start(1); - setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); - setAttribute(Qt::WA_MacAlwaysShowToolWindow); - - show(); - - setWindowOpacity(a_opacity.current()); - - alphaDuration = posDuration = st::notifyFastAnim; - _a_appearance.start(); - - checkLastInput(); -} - -void NotifyWindow::checkLastInput() { -#if defined Q_OS_WIN && !defined Q_OS_WINRT - LASTINPUTINFO lii; - lii.cbSize = sizeof(LASTINPUTINFO); - BOOL res = GetLastInputInfo(&lii); - if (!res || lii.dwTime >= started) { - hideTimer.start(st::notifyWaitLongHide); - } else { - inputTimer.start(300); - } -#else // Q_OS_WIN && !Q_OS_WINRT - // TODO - if (true) { - hideTimer.start(st::notifyWaitLongHide); - } else { - inputTimer.start(300); - } -#endif // else for Q_OS_WIN && !Q_OS_WINRT -} - -void NotifyWindow::moveTo(int32 x, int32 y, int32 index) { - if (index >= 0) { - _index = index; - } - move(x, a_y.current()); - a_y.start(y); - a_opacity.restart(); - posDuration = st::notifyFastAnim; - _a_appearance.start(); -} - -void NotifyWindow::updateNotifyDisplay() { - if (!item) return; - - int32 w = st::notifyWidth, h = st::notifyHeight; - QImage img(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); - if (cRetina()) img.setDevicePixelRatio(cRetinaFactor()); - img.fill(st::notifyBG->c); - - { - Painter p(&img); - p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); - p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); - - if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) { - history->peer->loadUserpic(true, true); - history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width()); - } else { - static QPixmap icon = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon); - } - - int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; - - QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height); - if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) { - if (auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(history->peer, false)) { - chatTypeIcon->paint(p, rectForName.topLeft(), w); - rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip); - } - } - - QDateTime now(QDateTime::currentDateTime()), lastTime(item->date); - QDate nowDate(now.date()), lastDate(lastTime.date()); - QString dt = lastTime.toString(cTimeFormat()); - int32 dtWidth = st::dialogsTextFont->width(dt); - rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip); - p.setFont(st::dialogsDateFont); - p.setPen(st::dialogsDateFg); - p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::dialogsTextFont->ascent, dt); - - if (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview) { - const HistoryItem *textCachedFor = 0; - Text itemTextCache(itemWidth); - QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height); - if (fwdCount < 2) { - bool active = false; - item->drawInDialog(p, r, active, textCachedFor, itemTextCache); - } else { - p.setFont(st::dialogsTextFont); - if (item->hasFromName() && !item->isPost()) { - itemTextCache.setText(st::dialogsTextFont, item->author()->name); - p.setPen(st::dialogsTextFgService); - itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dialogsTextFont->height); - r.setTop(r.top() + st::dialogsTextFont->height); - } - p.setPen(st::dialogsTextFg); - p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, fwdCount)); - } - } else { - static QString notifyText = st::dialogsTextFont->elided(lang(lng_notification_preview), itemWidth); - p.setPen(st::dialogsTextFgService); - p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText); - } - - p.setPen(st::dialogsNameFg); - if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) { - history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); - } else { - p.setFont(st::msgNameFont->f); - static QString notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width()); - p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle); - } - } - - pm = App::pixmapFromImageInPlace(std_::move(img)); - update(); -} - -void NotifyWindow::updatePeerPhoto() { - if (!peerPhoto->isNull() && peerPhoto->loaded()) { - QImage img(pm.toImage()); - { - QPainter p(&img); - p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); - } - peerPhoto = ImagePtr(); - pm = App::pixmapFromImageInPlace(std_::move(img)); - update(); - } -} - -void NotifyWindow::itemRemoved(HistoryItem *del) { - if (item == del) { - item = 0; - unlinkHistoryAndNotify(); - } -} - -void NotifyWindow::unlinkHistoryAndNotify() { - unlinkHistory(); - App::wnd()->notifyShowNext(); -} - -void NotifyWindow::unlinkHistory(History *hist) { - if (!hist || hist == history) { - animHide(st::notifyFastAnim, anim::linear); - history = 0; - item = 0; - } -} - -void NotifyWindow::enterEvent(QEvent *e) { - if (!history) return; - if (App::wnd()) App::wnd()->notifyStopHiding(); -} - -void NotifyWindow::leaveEvent(QEvent *e) { - if (!history) return; - App::wnd()->notifyStartHiding(); -} - -void NotifyWindow::startHiding() { - hideTimer.start(st::notifyWaitShortHide); -} - -void NotifyWindow::mousePressEvent(QMouseEvent *e) { - if (!history) return; - - PeerId peer = history->peer->id; - MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId; - - if (e->button() == Qt::RightButton) { - unlinkHistoryAndNotify(); - } else { - App::wnd()->showFromTray(); - if (App::passcoded()) { - App::wnd()->setInnerFocus(); - App::wnd()->notifyClear(); - } else { - Ui::showPeerHistory(peer, msgId); - } - e->ignore(); - } -} - -void NotifyWindow::paintEvent(QPaintEvent *e) { - QPainter p(this); - p.drawPixmap(0, 0, pm); -} - -void NotifyWindow::animHide(float64 duration, anim::transition func) { - if (!history) return; - alphaDuration = duration; - a_func = func; - a_opacity.start(0); - a_y.restart(); - hiding = true; - _a_appearance.start(); -} - -void NotifyWindow::stopHiding() { - if (!history) return; - alphaDuration = st::notifyFastAnim; - a_func = anim::linear; - a_opacity.start(1); - a_y.restart(); - hiding = false; - hideTimer.stop(); - _a_appearance.start(); -} - -void NotifyWindow::hideByTimer() { - if (!history) return; - animHide(st::notifySlowHide, st::notifySlowHideFunc); -} - -void NotifyWindow::step_appearance(float64 ms, bool timer) { - float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration; - if (dtAlpha >= 1) { - a_opacity.finish(); - if (hiding) { - _a_appearance.stop(); - deleteLater(); - } else if (dtPos >= 1) { - _a_appearance.stop(); - } - } else { - a_opacity.update(dtAlpha, a_func); - } - setWindowOpacity(a_opacity.current()); - if (dtPos >= 1) { - a_y.finish(); - } else { - a_y.update(dtPos, anim::linear); - } - move(x(), a_y.current()); - update(); -} - -NotifyWindow::~NotifyWindow() { - if (App::wnd()) App::wnd()->notifyShowNext(this); -} - MainWindow::MainWindow() { icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation); icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation); @@ -1440,8 +1158,8 @@ void MainWindow::notifyFire() { void MainWindow::notifyClear(History *history) { if (!history) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->unlinkHistory(); + for_const (auto widget, notifyWidgets) { + widget->unlinkHistory(); } psClearNotifies(); for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) { @@ -1454,10 +1172,10 @@ void MainWindow::notifyClear(History *history) { } notifyWaiters.remove(history); notifySettingWaiters.remove(history); - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->unlinkHistory(history); + for_const (auto widget, notifyWidgets) { + widget->unlinkHistory(history); } - psClearNotifies(history->peer->id); + psClearNotifies(history); notifyWhenMaps.remove(history); notifyWhenAlerts.remove(history); notifyShowNext(); @@ -1466,11 +1184,11 @@ void MainWindow::notifyClear(History *history) { void MainWindow::notifyClearFast() { notifyWaiters.clear(); notifySettingWaiters.clear(); - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->deleteLater(); + for_const (auto widget, notifyWidgets) { + widget->deleteLater(); } psClearNotifies(); - notifyWindows.clear(); + notifyWidgets.clear(); notifyWhenMaps.clear(); notifyWhenAlerts.clear(); } @@ -1517,14 +1235,14 @@ void MainWindow::notifySettingGot() { notifyShowNext(); } -void MainWindow::notifyShowNext(NotifyWindow *remove) { +void MainWindow::notifyShowNext(Window::Notifications::Widget *remove) { if (App::quitting()) return; int32 count = NotifyWindowsCount; if (remove) { - for (NotifyWindows::iterator i = notifyWindows.begin(), e = notifyWindows.end(); i != e; ++i) { + for (auto i = notifyWidgets.begin(), e = notifyWidgets.end(); i != e; ++i) { if ((*i) == remove) { - notifyWindows.erase(i); + notifyWidgets.erase(i); break; } } @@ -1560,9 +1278,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) { } if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - int32 ind = (*i)->index(); - if (ind < 0) continue; + for_const (auto widget, notifyWidgets) { + if (widget->index() < 0) continue; --count; } } @@ -1663,9 +1380,9 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) { } if (Global::CustomNotifies()) { - NotifyWindow *notify = new NotifyWindow(notifyItem, x, y, fwdCount); - notifyWindows.push_back(notify); - psNotifyShown(notify); + auto widget = new Window::Notifications::Widget(notifyItem, x, y, fwdCount); + notifyWidgets.push_back(widget); + psNotifyShown(widget); --count; } else { psPlatformNotify(notifyItem, fwdCount); @@ -1686,42 +1403,41 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) { } count = NotifyWindowsCount - count; - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - int32 ind = (*i)->index(); - if (ind < 0) continue; + for_const (auto widget, notifyWidgets) { + if (widget->index() < 0) continue; --count; - (*i)->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY)); + widget->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY)); } } void MainWindow::notifyItemRemoved(HistoryItem *item) { if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->itemRemoved(item); + for_const (auto widget, notifyWidgets) { + widget->itemRemoved(item); } } } void MainWindow::notifyStopHiding() { if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->stopHiding(); + for_const (auto widget, notifyWidgets) { + widget->stopHiding(); } } } void MainWindow::notifyStartHiding() { if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->startHiding(); + for_const (auto widget, notifyWidgets) { + widget->startHiding(); } } } void MainWindow::notifyUpdateAllPhotos() { if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->updatePeerPhoto(); + for_const (auto widget, notifyWidgets) { + widget->updatePeerPhoto(); } } if (_mediaView && !_mediaView->isHidden()) _mediaView->updateControls(); @@ -1733,8 +1449,8 @@ void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButt void MainWindow::notifyUpdateAll() { if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - (*i)->updateNotifyDisplay(); + for_const (auto widget, notifyWidgets) { + widget->updateNotifyDisplay(); } } psClearNotifies(); @@ -1742,8 +1458,8 @@ void MainWindow::notifyUpdateAll() { void MainWindow::notifyActivateAll() { if (Global::CustomNotifies()) { - for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { - psActivateNotify(*i); + for_const (auto widget, notifyWidgets) { + psActivateNotify(widget); } } } diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index c091e5e91..e35b12de1 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -32,28 +32,33 @@ class IntroWidget; class MainWidget; class LayerStackWidget; class LayerWidget; + namespace Local { class ClearManager; } // namespace Local + namespace Settings { class Widget; } // namespace Settings +namespace Window { +namespace Notifications { +class Widget; +} // namespace Notifications +} // namespace Window + class ConnectingWidget : public QWidget { Q_OBJECT public: - ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect); void set(const QString &text, const QString &reconnect); void paintEvent(QPaintEvent *e); public slots: - void onReconnect(); private: - Ui::RectShadow _shadow; QString _text; int32 _textWidth; @@ -61,69 +66,6 @@ private: }; -class NotifyWindow : public TWidget { - Q_OBJECT - -public: - - NotifyWindow(HistoryItem *item, int32 x, int32 y, int32 fwdCount); - - void enterEvent(QEvent *e); - void leaveEvent(QEvent *e); - void mousePressEvent(QMouseEvent *e); - void paintEvent(QPaintEvent *e); - - void step_appearance(float64 ms, bool timer); - void animHide(float64 duration, anim::transition func); - void startHiding(); - void stopHiding(); - void moveTo(int32 x, int32 y, int32 index = -1); - - void updateNotifyDisplay(); - void updatePeerPhoto(); - - void itemRemoved(HistoryItem *del); - - int32 index() const { - return history ? _index : -1; - } - - void unlinkHistory(History *hist = 0); - - ~NotifyWindow(); - -public slots: - - void hideByTimer(); - void checkLastInput(); - - void unlinkHistoryAndNotify(); - -private: - -#if defined Q_OS_WIN && !defined Q_OS_WINRT - DWORD started; -#endif // Q_OS_WIN && !Q_OS_WINRT - History *history; - HistoryItem *item; - int32 fwdCount; - IconedButton close; - QPixmap pm; - float64 alphaDuration, posDuration; - QTimer hideTimer, inputTimer; - bool hiding; - int32 _index; - anim::fvalue a_opacity; - anim::transition a_func; - anim::ivalue a_y; - Animation _a_appearance; - - ImagePtr peerPhoto; - -}; - -typedef QList NotifyWindows; - class MediaPreviewWidget; class MainWindow : public Platform::MainWindow, private base::Subscriber { @@ -208,7 +150,7 @@ public: void notifySchedule(History *history, HistoryItem *item); void notifyClear(History *history = 0); void notifyClearFast(); - void notifyShowNext(NotifyWindow *remove = 0); + void notifyShowNext(Window::Notifications::Widget *remove = 0); void notifyItemRemoved(HistoryItem *item); void notifyStopHiding(); void notifyStartHiding(); @@ -354,9 +296,11 @@ private: typedef QMap NotifyWhenAlerts; NotifyWhenAlerts notifyWhenAlerts; - NotifyWindows notifyWindows; + using NotifyWidgets = QList; + NotifyWidgets notifyWidgets; MediaView *_mediaView = nullptr; + }; class PreLaunchWindow : public TWidget { diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 2647ea36e..ff1fe33fc 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -663,13 +663,13 @@ void MainWindow::psUpdateMargins() { void MainWindow::psFlash() { } -void MainWindow::psActivateNotify(NotifyWindow *w) { +void MainWindow::psActivateNotify(Window::Notifications::Widget *w) { } void MainWindow::psClearNotifies(PeerId peerId) { } -void MainWindow::psNotifyShown(NotifyWindow *w) { +void MainWindow::psNotifyShown(Window::Notifications::Widget *w) { } void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) { diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index 2526a9c5f..e95acac1b 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -22,7 +22,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "window/main_window.h" -class NotifyWindow; +namespace Window { +namespace Notifications { +class Widget; +} // namespace Notifications +} // namespace Window namespace Platform { @@ -58,9 +62,9 @@ public: return posInited; } - void psActivateNotify(NotifyWindow *w); + void psActivateNotify(Window::Notifications::Widget *w); void psClearNotifies(PeerId peerId = 0); - void psNotifyShown(NotifyWindow *w); + void psNotifyShown(Window::Notifications::Widget *w); void psPlatformNotify(HistoryItem *item, int32 fwdCount); void psUpdateCounter(); diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp new file mode 100644 index 000000000..c9d8a8562 --- /dev/null +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -0,0 +1,38 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "platform/linux/notifications_manager_linux.h" + +namespace Platform { +namespace Notifications { + +void start() { +} + +Window::Notifications::AbstractManager *manager() { + return nullptr; +} + +void finish() { +} + +} // namespace Notifications +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h new file mode 100644 index 000000000..71944652c --- /dev/null +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h @@ -0,0 +1,33 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "window/notifications_abstract_manager.h" + +namespace Platform { +namespace Notifications { + +void start(); +Window::Notifications::AbstractManager *manager(); +void finish(); + +} // namespace Notifications +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h index 2bbe76dc4..e417aa187 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.h +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h @@ -23,7 +23,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "window/main_window.h" #include "pspecific_mac_p.h" -class NotifyWindow; +namespace Window { +namespace Notifications { +class Widget; +} // namespace Notifications +} // namespace Window namespace Platform { @@ -70,9 +74,9 @@ public: bool psFilterNativeEvent(void *event); - void psActivateNotify(NotifyWindow *w); + void psActivateNotify(Window::Notifications::Widget *w); void psClearNotifies(PeerId peerId = 0); - void psNotifyShown(NotifyWindow *w); + void psNotifyShown(Window::Notifications::Widget *w); void psPlatformNotify(HistoryItem *item, int32 fwdCount); bool eventFilter(QObject *obj, QEvent *evt) override; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index 149e68803..8718b9c45 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "playerwidget.h" #include "historywidget.h" #include "localstorage.h" +#include "window/notifications_default_manager.h" #include "lang.h" @@ -467,7 +468,7 @@ void MainWindow::psClearNotifies(PeerId peerId) { _private.clearNotifies(peerId); } -void MainWindow::psActivateNotify(NotifyWindow *w) { +void MainWindow::psActivateNotify(Window::Notifications::Widget *w) { objc_activateWnd(w->winId()); } @@ -475,7 +476,7 @@ bool MainWindow::psFilterNativeEvent(void *event) { return _private.filterNativeEvent(event); } -void MainWindow::psNotifyShown(NotifyWindow *w) { +void MainWindow::psNotifyShown(Window::Notifications::Widget *w) { w->hide(); objc_holdOnTop(w->winId()); w->show(); diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h new file mode 100644 index 000000000..71944652c --- /dev/null +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h @@ -0,0 +1,33 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "window/notifications_abstract_manager.h" + +namespace Platform { +namespace Notifications { + +void start(); +Window::Notifications::AbstractManager *manager(); +void finish(); + +} // namespace Notifications +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm new file mode 100644 index 000000000..45f9346db --- /dev/null +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm @@ -0,0 +1,38 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "platform/mac/notifications_manager_mac.h" + +namespace Platform { +namespace Notifications { + +void start() { +} + +Window::Notifications::AbstractManager *manager() { + return nullptr; +} + +void finish() { +} + +} // namespace Notifications +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/platform_notifications_manager.h b/Telegram/SourceFiles/platform/platform_notifications_manager.h new file mode 100644 index 000000000..596d7f456 --- /dev/null +++ b/Telegram/SourceFiles/platform/platform_notifications_manager.h @@ -0,0 +1,31 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#ifdef Q_OS_MAC +#include "platform/winrt/notifications_manager_mac.h" +#elif defined Q_OS_LINUX // Q_OS_MAC +#include "platform/linux/notifications_manager_linux.h" +#elif defined Q_OS_WINRT // Q_OS_MAC || Q_OS_LINUX +#include "platform/winrt/notifications_manager_winrt.h" +#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT +#include "platform/win/notifications_manager_win.h" +#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || Q_OS_WIN diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 343c5d4df..eb701532e 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "platform/win/windows_toasts.h" #include "platform/win/windows_dlls.h" +#include "window/notifications_abstract_manager.h" #include "mainwindow.h" #include "application.h" #include "lang.h" @@ -819,8 +820,8 @@ void MainWindow::psInitFrameless() { psUpdatedPositionTimer.setSingleShot(true); connect(&psUpdatedPositionTimer, SIGNAL(timeout()), this, SLOT(psSavePosition())); - QPlatformNativeInterface *i = QGuiApplication::platformNativeInterface(); - ps_hWnd = static_cast(i->nativeResourceForWindow(QByteArrayLiteral("handle"), windowHandle())); + auto platformInterface = QGuiApplication::platformNativeInterface(); + ps_hWnd = static_cast(platformInterface->nativeResourceForWindow(QByteArrayLiteral("handle"), windowHandle())); if (!ps_hWnd) return; @@ -1066,8 +1067,6 @@ MainWindow::~MainWindow() { if (taskbarList) taskbarList.Reset(); - Toasts::finish(); - _shadowsWorking = false; if (ps_menu) DestroyMenu(ps_menu); psDestroyIcons(); @@ -1075,23 +1074,22 @@ MainWindow::~MainWindow() { if (ps_tbHider_hWnd) DestroyWindow(ps_tbHider_hWnd); } -void MainWindow::psActivateNotify(NotifyWindow *w) { +void MainWindow::psActivateNotify(Window::Notifications::Widget *w) { } -void MainWindow::psClearNotifies(PeerId peerId) { - Toasts::clearNotifies(peerId); +void MainWindow::psClearNotifies(History *history) { + if (history) { + Window::Notifications::manager()->clearFromHistory(history); + } else { + Window::Notifications::manager()->clearAllFast(); + } } -void MainWindow::psNotifyShown(NotifyWindow *w) { +void MainWindow::psNotifyShown(Window::Notifications::Widget *w) { } void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) { - QString title = (!App::passcoded() && Global::NotifyView() <= dbinvShowName) ? item->history()->peer->name : qsl("Telegram Desktop"); - QString subtitle = (!App::passcoded() && Global::NotifyView() <= dbinvShowName) ? item->notificationHeader() : QString(); - bool showpix = (!App::passcoded() && Global::NotifyView() <= dbinvShowName); - QString msg = (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview) ? (fwdCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, fwdCount)) : lang(lng_notification_preview); - - Toasts::create(item->history()->peer, item->id, showpix, title, subtitle, msg); + Window::Notifications::manager()->showNotification(item, fwdCount); } } // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index 458788064..711d06ac4 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -23,9 +23,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "window/main_window.h" #include -class NotifyWindow; class PopupMenu; +namespace Window { +namespace Notifications { +class Widget; +} // namespace Notifications +} // namespace Window + namespace Platform { class MainWindow : public Window::MainWindow { @@ -62,9 +67,9 @@ public: return posInited; } - void psActivateNotify(NotifyWindow *w); - void psClearNotifies(PeerId peerId = 0); - void psNotifyShown(NotifyWindow *w); + void psActivateNotify(Window::Notifications::Widget *w); + void psClearNotifies(History *history = nullptr); + void psNotifyShown(Window::Notifications::Widget *w); void psPlatformNotify(HistoryItem *item, int32 fwdCount); void psUpdateCounter(); diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp new file mode 100644 index 000000000..3e5e6f281 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -0,0 +1,51 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "platform/win/notifications_manager_win.h" + +#include "platform/win/windows_toasts.h" + +namespace Platform { +namespace Notifications { +namespace { + +NeverFreedPointer ToastsManager; + +} // namespace + +void start() { + Toasts::start(); +} + +Window::Notifications::AbstractManager *manager() { + if (Toasts::supported()) { + ToastsManager.makeIfNull(); + return ToastsManager.data(); + } + return nullptr; +} + +void finish() { + ToastsManager.reset(); +} + +} // namespace Notifications +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.h b/Telegram/SourceFiles/platform/win/notifications_manager_win.h new file mode 100644 index 000000000..71944652c --- /dev/null +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.h @@ -0,0 +1,33 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "window/notifications_abstract_manager.h" + +namespace Platform { +namespace Notifications { + +void start(); +Window::Notifications::AbstractManager *manager(); +void finish(); + +} // namespace Notifications +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/windows_toasts.cpp b/Telegram/SourceFiles/platform/win/windows_toasts.cpp index 32ad7aa7e..ba952cb6f 100644 --- a/Telegram/SourceFiles/platform/win/windows_toasts.cpp +++ b/Telegram/SourceFiles/platform/win/windows_toasts.cpp @@ -156,72 +156,6 @@ bool init() { return true; } -} // namespace - -void start() { - _supported = init(); -} - -bool supported() { - return _supported; -} - -uint64 clearImages(uint64 ms) { - uint64 result = 0; - for (auto i = _images.begin(); i != _images.end();) { - if (!i->until) { - ++i; - continue; - } - if (i->until <= ms) { - QFile(i->path).remove(); - i = _images.erase(i); - } else { - if (!result) { - result = i->until; - } else { - accumulate_min(result, i->until); - } - ++i; - } - } - return result; -} - -void clearNotifies(PeerId peerId) { - if (!_notifier) return; - - if (peerId) { - auto i = _notifications.find(peerId); - if (i != _notifications.cend()) { - auto temp = createAndSwap(i.value()); - _notifications.erase(i); - - for (auto j = temp.cbegin(), e = temp.cend(); j != e; ++j) { - _notifier->Hide(j->p.Get()); - } - } - } else { - auto temp = createAndSwap(_notifications); - for_const (auto ¬ifications, temp) { - for_const (auto ¬ification, notifications) { - _notifier->Hide(notification.p.Get()); - } - } - } -} - -void finish() { - _notifications.clear(); - if (_notificationManager) _notificationManager.Reset(); - if (_notifier) _notifier.Reset(); - if (_notificationFactory) _notificationFactory.Reset(); - - if (_imageSavedFlag) { - psDeleteDir(cWorkingDir() + qsl("tdata/temp")); - } -} - HRESULT SetNodeValueString(_In_ HSTRING inputString, _In_ IXmlNode *node, _In_ IXmlDocument *xml) { ComPtr inputText; @@ -446,7 +380,87 @@ QString getImage(const StorageKey &key, PeerData *peer) { return i->path; } -bool create(PeerData *peer, int32 msgId, bool showpix, const QString &title, const QString &subtitle, const QString &msg) { +} // namespace + +void start() { + _supported = init(); +} + +void finish() { +} + +bool supported() { + return _supported; +} + +uint64 clearImages(uint64 ms) { + uint64 result = 0; + for (auto i = _images.begin(); i != _images.end();) { + if (!i->until) { + ++i; + continue; + } + if (i->until <= ms) { + QFile(i->path).remove(); + i = _images.erase(i); + } else { + if (!result) { + result = i->until; + } else { + accumulate_min(result, i->until); + } + ++i; + } + } + return result; +} + +class Manager::Impl { +public: + bool create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton); + void clear(History *history, bool fast); + + ~Impl(); + +private: + +}; + +Manager::Impl::~Impl() { + _notifications.clear(); + if (_notificationManager) _notificationManager.Reset(); + if (_notifier) _notifier.Reset(); + if (_notificationFactory) _notificationFactory.Reset(); + + if (_imageSavedFlag) { + psDeleteDir(cWorkingDir() + qsl("tdata/temp")); + } +} + +void Manager::Impl::clear(History *history, bool fast) { + if (!_notifier) return; + + if (history) { + auto i = _notifications.find(history->peer->id); + if (i != _notifications.cend()) { + auto temp = createAndSwap(i.value()); + _notifications.erase(i); + + for (auto j = temp.cbegin(), e = temp.cend(); j != e; ++j) { + _notifier->Hide(j->p.Get()); + } + } + } else { + auto temp = createAndSwap(_notifications); + for_const (auto ¬ifications, temp) { + for_const (auto ¬ification, notifications) { + _notifier->Hide(notification.p.Get()); + } + } + } +} + +bool Manager::Impl::create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) { if (!supported() || !_notificationManager || !_notifier || !_notificationFactory) return false; ComPtr toastXml; @@ -460,7 +474,7 @@ bool create(PeerData *peer, int32 msgId, bool showpix, const QString &title, con StorageKey key; QString imagePath; - if (showpix) { + if (showUserpic) { key = peer->userpicUniqueKey(); } else { key = StorageKey(0, 0); @@ -549,5 +563,18 @@ bool create(PeerData *peer, int32 msgId, bool showpix, const QString &title, con return true; } +Manager::Manager() : _impl(std_::make_unique()) { +} + +Manager::~Manager() = default; + +void Manager::create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) { + _impl->create(peer, msgId, title, subtitle, showUserpic, msg, showReplyButton); +} + +void Manager::clear(History *history, bool fast) { + return _impl->clear(history, fast); +} + } // namespace Toasts } // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/windows_toasts.h b/Telegram/SourceFiles/platform/win/windows_toasts.h index b271abc4c..a8cef3c1c 100644 --- a/Telegram/SourceFiles/platform/win/windows_toasts.h +++ b/Telegram/SourceFiles/platform/win/windows_toasts.h @@ -20,19 +20,31 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "window/notifications_abstract_manager.h" + namespace Platform { namespace Toasts { void start(); -void finish(); - bool supported(); -bool create(PeerData *peer, int32 msgId, bool showpix, const QString &title, const QString &subtitle, const QString &msg); // Returns the next ms when clearImages() should be called. uint64 clearImages(uint64 ms); -void clearNotifies(PeerId peerId); +class Manager : public Window::Notifications::AbstractManager { +public: + Manager(); + + ~Manager(); + +private: + void create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override; + void clear(History *history, bool fast) override; + + class Impl; + std_::unique_ptr _impl; + +}; } // namespace Toasts } // namespace Platform diff --git a/Telegram/SourceFiles/pspecific_winrt.h b/Telegram/SourceFiles/pspecific_winrt.h index 06722c1ab..30ab755d5 100644 --- a/Telegram/SourceFiles/pspecific_winrt.h +++ b/Telegram/SourceFiles/pspecific_winrt.h @@ -27,7 +27,11 @@ inline QString psServerPrefix() { inline void psCheckLocalSocket(const QString &) { } -class NotifyWindow; +namespace Window { +namespace Notifications { +class Widget; +} // namespace Notifications +} // namespace Window class PsMainWindow : public QMainWindow { Q_OBJECT diff --git a/Telegram/SourceFiles/settings/settings_notifications_widget.cpp b/Telegram/SourceFiles/settings/settings_notifications_widget.cpp index 86c34889c..82f175eb4 100644 --- a/Telegram/SourceFiles/settings/settings_notifications_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_notifications_widget.cpp @@ -57,13 +57,13 @@ void NotificationsWidget::createControls() { _showSenderName->hideFast(); _showMessagePreview->hideFast(); } + addChildRow(_playSound, margin, lang(lng_settings_sound_notify), SLOT(onPlaySound()), Global::SoundNotify()); + addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), SLOT(onIncludeMuted()), Global::IncludeMuted()); #ifdef Q_OS_WIN if (App::wnd()->psHasNativeNotifications()) { addChildRow(_windowsNative, margin, lang(lng_settings_use_windows), SLOT(onWindowsNative()), Global::WindowsNotifications()); } #endif // Q_OS_WIN - addChildRow(_playSound, margin, lang(lng_settings_sound_notify), SLOT(onPlaySound()), Global::SoundNotify()); - addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), SLOT(onIncludeMuted()), Global::IncludeMuted()); } void NotificationsWidget::onDesktopNotifications() { diff --git a/Telegram/SourceFiles/window/notifications_abstract_manager.cpp b/Telegram/SourceFiles/window/notifications_abstract_manager.cpp new file mode 100644 index 000000000..6ebd52d73 --- /dev/null +++ b/Telegram/SourceFiles/window/notifications_abstract_manager.cpp @@ -0,0 +1,81 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "window/notifications_abstract_manager.h" + +#include "platform/platform_notifications_manager.h" +#include "window/notifications_default_manager.h" +#include "lang.h" + +namespace Window { +namespace Notifications { +namespace { + +NeverFreedPointer FallbackManager; + +} // namespace + +void start() { + Platform::Notifications::start(); +} + +AbstractManager *manager() { + if (auto result = Platform::Notifications::manager()) { + return result; + } + FallbackManager.makeIfNull(); + return FallbackManager.data(); +} + +void finish() { + Platform::Notifications::finish(); + FallbackManager.reset(); +} + +void AbstractManager::showNotification(HistoryItem *item, int forwardedCount) { + auto hideEverything = (App::passcoded() || Global::ScreenIsLocked()); + auto hideName = hideEverything || (Global::NotifyView() > dbinvShowName); + auto hidePreview = hideEverything || (Global::NotifyView() > dbinvShowPreview); + + QString title = hideName ? qsl("Telegram Desktop") : item->history()->peer->name; + QString subtitle = hideName ? QString() : item->notificationHeader(); + bool showUserpic = hideName ? false : true; + + QString msg = hidePreview ? lang(lng_notification_preview) : (forwardedCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, forwardedCount)); + bool showReplyButton = hidePreview ? false : item->history()->peer->canWrite(); + + create(item->history()->peer, item->id, title, subtitle, showUserpic, msg, showReplyButton); +} + +void AbstractManager::clearAllFast() { + clear(nullptr, true); +} + +void AbstractManager::clearAll() { + clear(nullptr, false); +} + +void AbstractManager::clearFromHistory(History *history) { + clear(history, false); +} + +} // namespace Notifications +} // namespace Window diff --git a/Telegram/SourceFiles/window/notifications_abstract_manager.h b/Telegram/SourceFiles/window/notifications_abstract_manager.h new file mode 100644 index 000000000..af8624114 --- /dev/null +++ b/Telegram/SourceFiles/window/notifications_abstract_manager.h @@ -0,0 +1,46 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +namespace Window { +namespace Notifications { + +class AbstractManager; + +void start(); +AbstractManager *manager(); +void finish(); + +class AbstractManager { +public: + void showNotification(HistoryItem *item, int forwardedCount); + void clearAllFast(); + void clearAll(); + void clearFromHistory(History *history); + +private: + virtual void create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) = 0; + virtual void clear(History *history, bool fast) = 0; + +}; + +} // namespace Notifications +} // namespace Window diff --git a/Telegram/SourceFiles/window/notifications_default_manager.cpp b/Telegram/SourceFiles/window/notifications_default_manager.cpp new file mode 100644 index 000000000..1cedbcb7b --- /dev/null +++ b/Telegram/SourceFiles/window/notifications_default_manager.cpp @@ -0,0 +1,327 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "window/notifications_default_manager.h" + +#include "mainwindow.h" +#include "lang.h" +#include "dialogs/dialogs_layout.h" +#include "styles/style_dialogs.h" + +namespace Window { +namespace Notifications { + +void DefaultManager::create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) { +} + +void DefaultManager::clear(History *history, bool fast) { +} + + +Widget::Widget(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : TWidget(0) +, history(msg->history()) +, item(msg) +, fwdCount(fwdCount) +#if defined Q_OS_WIN && !defined Q_OS_WINRT +, started(GetTickCount()) +#endif // Q_OS_WIN && !Q_OS_WINRT +, close(this, st::notifyClose) +, alphaDuration(st::notifyFastAnim) +, posDuration(st::notifyFastAnim) +, hiding(false) +, _index(0) +, a_opacity(0) +, a_func(anim::linear) +, a_y(y + st::notifyHeight + st::notifyDeltaY) +, _a_appearance(animation(this, &Widget::step_appearance)) { + + updateNotifyDisplay(); + + hideTimer.setSingleShot(true); + connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer())); + + inputTimer.setSingleShot(true); + connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput())); + + close.setClickedCallback([this] { + unlinkHistoryAndNotify(); + }); + close.setAcceptBoth(true); + close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y()); + close.show(); + + a_y.start(y); + setGeometry(x, a_y.current(), st::notifyWidth, st::notifyHeight); + + a_opacity.start(1); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + setAttribute(Qt::WA_MacAlwaysShowToolWindow); + + show(); + + setWindowOpacity(a_opacity.current()); + + alphaDuration = posDuration = st::notifyFastAnim; + _a_appearance.start(); + + checkLastInput(); +} + +void Widget::checkLastInput() { +#if defined Q_OS_WIN && !defined Q_OS_WINRT + LASTINPUTINFO lii; + lii.cbSize = sizeof(LASTINPUTINFO); + BOOL res = GetLastInputInfo(&lii); + if (!res || lii.dwTime >= started) { + hideTimer.start(st::notifyWaitLongHide); + } else { + inputTimer.start(300); + } +#else // Q_OS_WIN && !Q_OS_WINRT + // TODO + if (true) { + hideTimer.start(st::notifyWaitLongHide); + } else { + inputTimer.start(300); + } +#endif // else for Q_OS_WIN && !Q_OS_WINRT +} + +void Widget::moveTo(int32 x, int32 y, int32 index) { + if (index >= 0) { + _index = index; + } + move(x, a_y.current()); + a_y.start(y); + a_opacity.restart(); + posDuration = st::notifyFastAnim; + _a_appearance.start(); +} + +void Widget::updateNotifyDisplay() { + if (!item) return; + + int32 w = st::notifyWidth, h = st::notifyHeight; + QImage img(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + if (cRetina()) img.setDevicePixelRatio(cRetinaFactor()); + img.fill(st::notifyBG->c); + + { + Painter p(&img); + p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b); + p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); + + if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) { + history->peer->loadUserpic(true, true); + history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width()); + } else { + static QPixmap icon = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon); + } + + int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width; + + QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height); + if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) { + if (auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(history->peer, false)) { + chatTypeIcon->paint(p, rectForName.topLeft(), w); + rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip); + } + } + + QDateTime now(QDateTime::currentDateTime()), lastTime(item->date); + QDate nowDate(now.date()), lastDate(lastTime.date()); + QString dt = lastTime.toString(cTimeFormat()); + int32 dtWidth = st::dialogsTextFont->width(dt); + rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip); + p.setFont(st::dialogsDateFont); + p.setPen(st::dialogsDateFg); + p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::dialogsTextFont->ascent, dt); + + if (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview) { + const HistoryItem *textCachedFor = 0; + Text itemTextCache(itemWidth); + QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height); + if (fwdCount < 2) { + bool active = false; + item->drawInDialog(p, r, active, textCachedFor, itemTextCache); + } else { + p.setFont(st::dialogsTextFont); + if (item->hasFromName() && !item->isPost()) { + itemTextCache.setText(st::dialogsTextFont, item->author()->name); + p.setPen(st::dialogsTextFgService); + itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dialogsTextFont->height); + r.setTop(r.top() + st::dialogsTextFont->height); + } + p.setPen(st::dialogsTextFg); + p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, fwdCount)); + } + } else { + static QString notifyText = st::dialogsTextFont->elided(lang(lng_notification_preview), itemWidth); + p.setPen(st::dialogsTextFgService); + p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText); + } + + p.setPen(st::dialogsNameFg); + if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) { + history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } else { + p.setFont(st::msgNameFont->f); + static QString notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width()); + p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle); + } + } + + pm = App::pixmapFromImageInPlace(std_::move(img)); + update(); +} + +void Widget::updatePeerPhoto() { + if (!peerPhoto->isNull() && peerPhoto->loaded()) { + QImage img(pm.toImage()); + { + QPainter p(&img); + p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize)); + } + peerPhoto = ImagePtr(); + pm = App::pixmapFromImageInPlace(std_::move(img)); + update(); + } +} + +void Widget::itemRemoved(HistoryItem *del) { + if (item == del) { + item = 0; + unlinkHistoryAndNotify(); + } +} + +void Widget::unlinkHistoryAndNotify() { + unlinkHistory(); + if (auto window = App::wnd()) { + window->notifyShowNext(); + } +} + +void Widget::unlinkHistory(History *hist) { + if (!hist || hist == history) { + animHide(st::notifyFastAnim, anim::linear); + history = 0; + item = 0; + } +} + +void Widget::enterEvent(QEvent *e) { + if (!history) return; + if (App::wnd()) App::wnd()->notifyStopHiding(); +} + +void Widget::leaveEvent(QEvent *e) { + if (!history) return; + App::wnd()->notifyStartHiding(); +} + +void Widget::startHiding() { + hideTimer.start(st::notifyWaitShortHide); +} + +void Widget::mousePressEvent(QMouseEvent *e) { + if (!history) return; + + PeerId peer = history->peer->id; + MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId; + + if (e->button() == Qt::RightButton) { + unlinkHistoryAndNotify(); + } else { + App::wnd()->showFromTray(); + if (App::passcoded()) { + App::wnd()->setInnerFocus(); + App::wnd()->notifyClear(); + } else { + Ui::showPeerHistory(peer, msgId); + } + e->ignore(); + } +} + +void Widget::paintEvent(QPaintEvent *e) { + QPainter p(this); + p.drawPixmap(0, 0, pm); +} + +void Widget::animHide(float64 duration, anim::transition func) { + if (!history) return; + alphaDuration = duration; + a_func = func; + a_opacity.start(0); + a_y.restart(); + hiding = true; + _a_appearance.start(); +} + +void Widget::stopHiding() { + if (!history) return; + alphaDuration = st::notifyFastAnim; + a_func = anim::linear; + a_opacity.start(1); + a_y.restart(); + hiding = false; + hideTimer.stop(); + _a_appearance.start(); +} + +void Widget::hideByTimer() { + if (!history) return; + animHide(st::notifySlowHide, st::notifySlowHideFunc); +} + +void Widget::step_appearance(float64 ms, bool timer) { + float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration; + if (dtAlpha >= 1) { + a_opacity.finish(); + if (hiding) { + _a_appearance.stop(); + deleteLater(); + } else if (dtPos >= 1) { + _a_appearance.stop(); + } + } else { + a_opacity.update(dtAlpha, a_func); + } + setWindowOpacity(a_opacity.current()); + if (dtPos >= 1) { + a_y.finish(); + } else { + a_y.update(dtPos, anim::linear); + } + move(x(), a_y.current()); + update(); +} + +Widget::~Widget() { + if (App::wnd()) App::wnd()->notifyShowNext(this); +} + +} // namespace Notifications +} // namespace Window diff --git a/Telegram/SourceFiles/window/notifications_default_manager.h b/Telegram/SourceFiles/window/notifications_default_manager.h new file mode 100644 index 000000000..19076d875 --- /dev/null +++ b/Telegram/SourceFiles/window/notifications_default_manager.h @@ -0,0 +1,98 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "window/notifications_abstract_manager.h" + +namespace Window { +namespace Notifications { + +class DefaultManager : public AbstractManager { +public: + +private: + void create(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) override; + void clear(History *history, bool fast) override; + +}; + +class Widget : public TWidget { + Q_OBJECT + +public: + Widget(HistoryItem *item, int32 x, int32 y, int32 fwdCount); + + void step_appearance(float64 ms, bool timer); + void animHide(float64 duration, anim::transition func); + void startHiding(); + void stopHiding(); + void moveTo(int32 x, int32 y, int32 index = -1); + + void updateNotifyDisplay(); + void updatePeerPhoto(); + + void itemRemoved(HistoryItem *del); + + int32 index() const { + return history ? _index : -1; + } + + void unlinkHistory(History *hist = 0); + + ~Widget(); + +protected: + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void paintEvent(QPaintEvent *e) override; + +private slots: + void hideByTimer(); + void checkLastInput(); + +private: + void unlinkHistoryAndNotify(); + +#if defined Q_OS_WIN && !defined Q_OS_WINRT + uint64 started; +#endif // Q_OS_WIN && !Q_OS_WINRT + + History *history; + HistoryItem *item; + int32 fwdCount; + IconedButton close; + QPixmap pm; + float64 alphaDuration, posDuration; + QTimer hideTimer, inputTimer; + bool hiding; + int32 _index; + anim::fvalue a_opacity; + anim::transition a_func; + anim::ivalue a_y; + Animation _a_appearance; + + ImagePtr peerPhoto; + +}; + +} // namespace Notifications +} // namespace Window diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp index 69abfe22a..09e1e0aa9 100644 --- a/Telegram/gyp/Telegram.gyp +++ b/Telegram/gyp/Telegram.gyp @@ -324,10 +324,16 @@ '<(src_loc)/platform/linux/file_dialog_linux.h', '<(src_loc)/platform/linux/main_window_linux.cpp', '<(src_loc)/platform/linux/main_window_linux.h', + '<(src_loc)/platform/linux/notifications_manager_linux.cpp', + '<(src_loc)/platform/linux/notifications_manager_linux.h', '<(src_loc)/platform/mac/main_window_mac.mm', '<(src_loc)/platform/mac/main_window_mac.h', + '<(src_loc)/platform/mac/notifications_manager_mac.mm', + '<(src_loc)/platform/mac/notifications_manager_mac.h', '<(src_loc)/platform/win/main_window_win.cpp', '<(src_loc)/platform/win/main_window_win.h', + '<(src_loc)/platform/win/notifications_manager_win.cpp', + '<(src_loc)/platform/win/notifications_manager_win.h', '<(src_loc)/platform/win/windows_app_user_model_id.cpp', '<(src_loc)/platform/win/windows_app_user_model_id.h', '<(src_loc)/platform/win/windows_dlls.cpp', @@ -336,6 +342,9 @@ '<(src_loc)/platform/win/windows_event_filter.h', '<(src_loc)/platform/win/windows_toasts.cpp', '<(src_loc)/platform/win/windows_toasts.h', + '<(src_loc)/platform/platform_file_dialog.h', + '<(src_loc)/platform/platform_main_window.h', + '<(src_loc)/platform/platform_notifications_manager.h', '<(src_loc)/profile/profile_actions_widget.cpp', '<(src_loc)/profile/profile_actions_widget.h', '<(src_loc)/profile/profile_block_widget.cpp', @@ -473,6 +482,10 @@ '<(src_loc)/window/chat_background.h', '<(src_loc)/window/main_window.cpp', '<(src_loc)/window/main_window.h', + '<(src_loc)/window/notifications_abstract_manager.cpp', + '<(src_loc)/window/notifications_abstract_manager.h', + '<(src_loc)/window/notifications_default_manager.cpp', + '<(src_loc)/window/notifications_default_manager.h', '<(src_loc)/window/section_widget.cpp', '<(src_loc)/window/section_widget.h', '<(src_loc)/window/slide_animation.cpp', @@ -501,6 +514,8 @@ '<(src_loc)/platform/linux/file_dialog_linux.h', '<(src_loc)/platform/linux/main_window_linux.cpp', '<(src_loc)/platform/linux/main_window_linux.h', + '<(src_loc)/platform/linux/notifications_manager_linux.cpp', + '<(src_loc)/platform/linux/notifications_manager_linux.h', ], }], [ '"<(build_mac)" != "1"', { @@ -511,6 +526,8 @@ '<(src_loc)/pspecific_mac_p.h', '<(src_loc)/platform/mac/main_window_mac.mm', '<(src_loc)/platform/mac/main_window_mac.h', + '<(src_loc)/platform/mac/notifications_manager_mac.mm', + '<(src_loc)/platform/mac/notifications_manager_mac.h', ], }], [ '"<(build_win)" != "1"', { @@ -526,6 +543,8 @@ '<(src_loc)/pspecific_win.h', '<(src_loc)/platform/win/main_window_win.cpp', '<(src_loc)/platform/win/main_window_win.h', + '<(src_loc)/platform/win/notifications_manager_win.cpp', + '<(src_loc)/platform/win/notifications_manager_win.h', '<(src_loc)/platform/win/windows_app_user_model_id.cpp', '<(src_loc)/platform/win/windows_app_user_model_id.h', '<(src_loc)/platform/win/windows_dlls.cpp', diff --git a/Telegram/gyp/settings_win.gypi b/Telegram/gyp/settings_win.gypi index b97a3d5fa..1d9f7b3b4 100644 --- a/Telegram/gyp/settings_win.gypi +++ b/Telegram/gyp/settings_win.gypi @@ -46,6 +46,13 @@ 'ImageHasSafeExceptionHandlers': 'false', # Disable /SAFESEH }, }, + 'msvs_external_builder_build_cmd': [ + 'ninja.exe', + '-C', + '$(OutDir)', + '-k0', + '$(ProjectName)', + ], 'libraries': [ 'winmm', 'imm32',