mirror of https://github.com/procxx/kepka.git
				
				
				
			NB Broken! Started notification manager abstraction.
This commit is contained in:
		
							parent
							
								
									1d6aba86ba
								
							
						
					
					
						commit
						a41e0c4aa7
					
				|  | @ -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; | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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<NotifyWindow*> 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<History*, NotifyWhenAlert> NotifyWhenAlerts; | ||||
| 	NotifyWhenAlerts notifyWhenAlerts; | ||||
| 
 | ||||
| 	NotifyWindows notifyWindows; | ||||
| 	using NotifyWidgets = QList<Window::Notifications::Widget*>; | ||||
| 	NotifyWidgets notifyWidgets; | ||||
| 
 | ||||
| 	MediaView *_mediaView = nullptr; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class PreLaunchWindow : public TWidget { | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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
 | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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 | ||||
|  | @ -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
 | ||||
|  | @ -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<HWND>(i->nativeResourceForWindow(QByteArrayLiteral("handle"), windowHandle())); | ||||
| 	auto platformInterface = QGuiApplication::platformNativeInterface(); | ||||
| 	ps_hWnd = static_cast<HWND>(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
 | ||||
|  |  | |||
|  | @ -23,9 +23,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org | |||
| #include "window/main_window.h" | ||||
| #include <windows.h> | ||||
| 
 | ||||
| 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(); | ||||
|  |  | |||
|  | @ -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<Toasts::Manager> 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
 | ||||
|  | @ -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
 | ||||
|  | @ -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<IXmlText> 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<IXmlDocument> 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<Impl>()) { | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|  |  | |||
|  | @ -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> _impl; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace Toasts
 | ||||
| } // namespace Platform
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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() { | ||||
|  |  | |||
|  | @ -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<DefaultManager> 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
 | ||||
|  | @ -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
 | ||||
|  | @ -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
 | ||||
|  | @ -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
 | ||||
|  | @ -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', | ||||
|  |  | |||
|  | @ -46,6 +46,13 @@ | |||
|           'ImageHasSafeExceptionHandlers': 'false',   # Disable /SAFESEH | ||||
|         }, | ||||
|       }, | ||||
|       'msvs_external_builder_build_cmd': [ | ||||
|         'ninja.exe', | ||||
|         '-C', | ||||
|         '$(OutDir)', | ||||
|         '-k0', | ||||
|         '$(ProjectName)', | ||||
|       ], | ||||
|       'libraries': [ | ||||
|         'winmm', | ||||
|         'imm32', | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue