From da0f087404d1d0b8b3ba2a5a71fb6d7aef442913 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Tue, 8 Jul 2014 14:24:21 +0400
Subject: [PATCH] first version ubuntu qt creator build

---
 .gitignore                                    |    4 +
 Telegram/MetaEmoji.pro                        |    8 +-
 Telegram/MetaLang.pro                         |    8 +-
 Telegram/MetaStyle.pro                        |    8 +-
 Telegram/Packer.pro                           |    8 +-
 Telegram/SourceFiles/app.cpp                  |    2 +-
 Telegram/SourceFiles/boxes/aboutbox.cpp       |    6 +-
 Telegram/SourceFiles/gui/style_core.cpp       |    2 +-
 Telegram/SourceFiles/gui/text.cpp             |    4 +-
 Telegram/SourceFiles/logs.cpp                 |    3 +
 Telegram/SourceFiles/mtproto/mtp.cpp          |    2 +-
 .../SourceFiles/mtproto/mtpConnection.cpp     |    8 +-
 Telegram/SourceFiles/pspecific.h              |    2 +-
 Telegram/SourceFiles/pspecific_linux.cpp      | 1332 +++++++++++++++++
 Telegram/SourceFiles/pspecific_linux.h        |  257 ++++
 Telegram/SourceFiles/settings.cpp             |    5 +-
 Telegram/SourceFiles/stdafx.cpp               |    3 +
 Telegram/SourceFiles/title.cpp                |    4 +-
 Telegram/SourceFiles/types.cpp                |   25 +-
 Telegram/Telegram.pro                         |   33 +-
 .../basic/qbasicfontdatabase.cpp              |  490 ++++++
 Telegram/telegram_plugin_import.cpp           |    7 +-
 22 files changed, 2160 insertions(+), 61 deletions(-)
 create mode 100644 Telegram/SourceFiles/pspecific_linux.cpp
 create mode 100644 Telegram/SourceFiles/pspecific_linux.h
 create mode 100644 Telegram/_qt_5_3_1_patch/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp

diff --git a/.gitignore b/.gitignore
index d1c2f1f14..9289e37d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,7 @@ ipch/
 /Mac/
 /Telegram/*.xcodeproj/xcuserdata/
 /Telegram/*.xcodeproj/project.xcworkspace/
+
+/Telegram/*.user.*
+/Linux/
+/Telegram/Makefile
diff --git a/Telegram/MetaEmoji.pro b/Telegram/MetaEmoji.pro
index 77927fb41..8bc1723dd 100644
--- a/Telegram/MetaEmoji.pro
+++ b/Telegram/MetaEmoji.pro
@@ -2,14 +2,14 @@ QT += core
 
 CONFIG(debug, debug|release) {
     DEFINES += _DEBUG
-    OBJECTS_DIR = ./../Mac/DebugIntermediateEmoji
+    OBJECTS_DIR = ./../Linux/DebugIntermediateEmoji
     MOC_DIR = ./GeneratedFiles/Debug
-    DESTDIR = ./../Mac/DebugEmoji
+    DESTDIR = ./../Linux/DebugEmoji
 }
 CONFIG(release, debug|release) {
-    OBJECTS_DIR = ./../Mac/ReleaseIntermediateEmoji
+    OBJECTS_DIR = ./../Linux/ReleaseIntermediateEmoji
     MOC_DIR = ./GeneratedFiles/Release
-    DESTDIR = ./../Mac/ReleaseEmoji
+    DESTDIR = ./../Linux/ReleaseEmoji
 }
 
 macx {
diff --git a/Telegram/MetaLang.pro b/Telegram/MetaLang.pro
index cee803ce7..abe460d42 100644
--- a/Telegram/MetaLang.pro
+++ b/Telegram/MetaLang.pro
@@ -2,14 +2,14 @@ T += core
 
 CONFIG(debug, debug|release) {
     DEFINES += _DEBUG
-    OBJECTS_DIR = ./../Mac/DebugIntermediateLang
+    OBJECTS_DIR = ./../Linux/DebugIntermediateLang
     MOC_DIR = ./GeneratedFiles/Debug
-    DESTDIR = ./../Mac/DebugLang
+    DESTDIR = ./../Linux/DebugLang
 }
 CONFIG(release, debug|release) {
-    OBJECTS_DIR = ./../Mac/ReleaseIntermediateLang
+    OBJECTS_DIR = ./../Linux/ReleaseIntermediateLang
     MOC_DIR = ./GeneratedFiles/Release
-    DESTDIR = ./../Mac/ReleaseLang
+    DESTDIR = ./../Linux/ReleaseLang
 }
 
 macx {
diff --git a/Telegram/MetaStyle.pro b/Telegram/MetaStyle.pro
index f5ff0f7e5..f26242a0c 100644
--- a/Telegram/MetaStyle.pro
+++ b/Telegram/MetaStyle.pro
@@ -2,14 +2,14 @@ QT += core
 
 CONFIG(debug, debug|release) {
     DEFINES += _DEBUG
-    OBJECTS_DIR = ./../Mac/DebugIntermediateStyle
+    OBJECTS_DIR = ./../Linux/DebugIntermediateStyle
     MOC_DIR = ./GeneratedFiles/Debug
-    DESTDIR = ./../Mac/DebugStyle
+    DESTDIR = ./../Linux/DebugStyle
 }
 CONFIG(release, debug|release) {
-    OBJECTS_DIR = ./../Mac/ReleaseIntermediateStyle
+    OBJECTS_DIR = ./../Linux/ReleaseIntermediateStyle
     MOC_DIR = ./GeneratedFiles/Release
-    DESTDIR = ./../Mac/ReleaseStyle
+    DESTDIR = ./../Linux/ReleaseStyle
 }
 
 macx {
diff --git a/Telegram/Packer.pro b/Telegram/Packer.pro
index 4fb98d457..16082158f 100644
--- a/Telegram/Packer.pro
+++ b/Telegram/Packer.pro
@@ -2,14 +2,14 @@ QT += core
 
 CONFIG(debug, debug|release) {
     DEFINES += _DEBUG
-    OBJECTS_DIR = ./../Mac/DebugIntermediatePacker
+    OBJECTS_DIR = ./../Linux/DebugIntermediatePacker
     MOC_DIR = ./GeneratedFiles/Debug
-    DESTDIR = ./../Mac/DebugPacker
+    DESTDIR = ./../Linux/DebugPacker
 }
 CONFIG(release, debug|release) {
-    OBJECTS_DIR = ./../Mac/ReleaseIntermediatePacker
+    OBJECTS_DIR = ./../Linux/ReleaseIntermediatePacker
     MOC_DIR = ./GeneratedFiles/Release
-    DESTDIR = ./../Mac/ReleasePacker
+    DESTDIR = ./../Linux/ReleasePacker
 }
 
 macx {
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 7f0f2c03c..0a508deeb 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -321,7 +321,7 @@ namespace App {
 			case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
 			}
 
-			if (data->contact < 0 && !data->phone.isEmpty() && (data->id & 0xFFFFFFFF) != MTP::authedId()) {
+            if (data->contact < 0 && !data->phone.isEmpty() && int32(data->id & 0xFFFFFFFF) != MTP::authedId()) {
 				data->contact = 0;
 			}
 			if (data->contact > 0 && !wasContact) {
diff --git a/Telegram/SourceFiles/boxes/aboutbox.cpp b/Telegram/SourceFiles/boxes/aboutbox.cpp
index 188e8bf15..462ce32b3 100644
--- a/Telegram/SourceFiles/boxes/aboutbox.cpp
+++ b/Telegram/SourceFiles/boxes/aboutbox.cpp
@@ -84,14 +84,14 @@ void AboutBox::paintEvent(QPaintEvent *e) {
 
 			p.setPen(st::black->p);
 			p.setFont(st::aboutHeaderFont->f);
-			p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2, st::aboutHeaderTop + st::aboutHeaderFont->ascent, qsl("Telegram"));
+            p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2, st::aboutHeaderTop + st::aboutHeaderFont->ascent, qsl("Telegram"));
 
 			p.setFont(st::aboutSubheaderFont->f);
-			p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2 + _headerWidth, st::aboutHeaderTop + st::aboutSubheaderFont->ascent, qsl("Desktop"));
+            p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2 + _headerWidth, st::aboutHeaderTop + st::aboutSubheaderFont->ascent, qsl("Desktop"));
 
 			p.setFont(st::aboutVersionFont->f);
 			p.setPen(st::aboutVersionColor->p);
-			p.drawText((_width - _versionWidth) / 2, st::aboutVersionTop + st::aboutVersionFont->ascent, _versionText);
+            p.drawText((_width - _versionWidth) / 2, st::aboutVersionTop + st::aboutVersionFont->ascent, _versionText);
 		}
 	} else {
 		p.setOpacity(a_opacity.current());
diff --git a/Telegram/SourceFiles/gui/style_core.cpp b/Telegram/SourceFiles/gui/style_core.cpp
index 561953587..1addc9ece 100644
--- a/Telegram/SourceFiles/gui/style_core.cpp
+++ b/Telegram/SourceFiles/gui/style_core.cpp
@@ -32,7 +32,7 @@ namespace style {
 		modified[_flags] = Font(this);
 
 		f.setPixelSize(size);
-		f.setBold(_flags & FontBold);
+        f.setBold(_flags & FontBold);
 		f.setItalic(_flags & FontItalic);
 		f.setUnderline(_flags & FontUnderline);
 		f.setStyleStrategy(QFont::PreferQuality);
diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp
index f7522142b..32f4e0a5e 100644
--- a/Telegram/SourceFiles/gui/text.cpp
+++ b/Telegram/SourceFiles/gui/text.cpp
@@ -1245,9 +1245,9 @@ public:
 				break;
 			}
 		}/**/
-		for (; _lineEnd > _lineStart + 1; --_lineEnd) {
+        for (; _lineEnd > _lineStart; --_lineEnd) {
 			QChar ch = _t->_text.at(_lineEnd - 1);
-			if (ch != QChar::Space && ch != QChar::LineFeed) {
+            if ((ch != QChar::Space || _lineEnd == _lineStart + 1) && ch != QChar::LineFeed) {
 				break;
 			}
 		}/**/
diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp
index 8b6c30e41..2e9fbd345 100644
--- a/Telegram/SourceFiles/logs.cpp
+++ b/Telegram/SourceFiles/logs.cpp
@@ -16,6 +16,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
 Copyright (c) 2014 John Preston, https://tdesktop.com
 */
 #include "stdafx.h"
+#include <iostream>
 #include "pspecific.h"
 
 namespace {
@@ -71,6 +72,8 @@ void debugLogWrite(const char *file, int32 line, const QString &v) {
 		OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
 #elif defined Q_OS_MAC
         objc_outputDebugString(msg);
+#elif defined Q_OS_LINUX && defined _DEBUG
+        std::cout << msg.toUtf8().constData();
 #endif
 	}
 }
diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp
index f3d5f0052..1ce00a08b 100644
--- a/Telegram/SourceFiles/mtproto/mtp.cpp
+++ b/Telegram/SourceFiles/mtproto/mtp.cpp
@@ -130,7 +130,7 @@ namespace {
 
 	bool onErrorDefault(mtpRequestId requestId, const RPCError &error) {
 		const QString &err(error.type());
-		QRegularExpressionMatch m;;
+        QRegularExpressionMatch m;
 		if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) {
 			if (!requestId) return false;
 
diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp
index a114c0f57..a1cdd63d1 100644
--- a/Telegram/SourceFiles/mtproto/mtpConnection.cpp
+++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp
@@ -2756,12 +2756,12 @@ void MTProtoConnectionPrivate::authKeyCreated() {
 
 void MTProtoConnectionPrivate::clearAuthKeyData() {
 	if (authKeyData) {
-#ifdef Q_OS_WIN
-		SecureZeroMemory(authKeyData, sizeof(AuthKeyCreateData));
+#ifdef Q_OS_WIN // TODO
+//		SecureZeroMemory(authKeyData, sizeof(AuthKeyCreateData));
 #else
-        memset(authKeyData, 0, sizeof(AuthKeyCreateData));
+//        memset(authKeyData, 0, sizeof(AuthKeyCreateData));
 #endif
-		delete authKeyData;
+        delete authKeyData;
 		authKeyData = 0;
 	}
 }
diff --git a/Telegram/SourceFiles/pspecific.h b/Telegram/SourceFiles/pspecific.h
index a20715723..529960ede 100644
--- a/Telegram/SourceFiles/pspecific.h
+++ b/Telegram/SourceFiles/pspecific.h
@@ -26,7 +26,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
 #endif
 
 #ifdef Q_OS_LINUX
-
+#include "pspecific_linux.h"
 #endif
 
 #ifdef Q_OS_WIN
diff --git a/Telegram/SourceFiles/pspecific_linux.cpp b/Telegram/SourceFiles/pspecific_linux.cpp
new file mode 100644
index 000000000..0efa13350
--- /dev/null
+++ b/Telegram/SourceFiles/pspecific_linux.cpp
@@ -0,0 +1,1332 @@
+/*
+This file is part of Telegram Desktop,
+an unofficial desktop 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.
+ 
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014 John Preston, https://tdesktop.com
+*/
+#include "stdafx.h"
+#include "pspecific.h"
+
+#include "lang.h"
+#include "application.h"
+#include "mainwidget.h"
+
+namespace {
+	bool frameless = true;
+	bool finished = true;
+
+    class _PsEventFilter : public QAbstractNativeEventFilter {
+	public:
+		_PsEventFilter() {
+		}
+
+		bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
+			Window *wnd = Application::wnd();
+			if (!wnd) return false;
+
+			return false;
+		}
+	};
+    _PsEventFilter *_psEventFilter = 0;
+
+};
+
+PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
+posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/iconround256.png")) {
+    connect(&psIdleTimer, SIGNAL(timeout()), this, SLOT(psIdleTimeout()));
+    psIdleTimer.setSingleShot(false);
+	connect(&notifyWaitTimer, SIGNAL(timeout()), this, SLOT(psNotifyFire()));
+	notifyWaitTimer.setSingleShot(true);
+}
+
+void PsMainWindow::psNotIdle() const {
+	psIdleTimer.stop();
+	if (psIdle) {
+		psIdle = false;
+		if (App::main()) App::main()->setOnline();
+		if (App::wnd()) App::wnd()->checkHistoryActivation();
+	}
+}
+
+void PsMainWindow::psIdleTimeout() {
+    int64 idleTime = 0;//objc_idleTime();
+    if (idleTime >= 0) {
+        if (idleTime <= IdleMsecs) {
+			psNotIdle();
+		}
+    } else { // error
+		psNotIdle();
+	}
+}
+
+bool PsMainWindow::psIsOnline(int state) const {
+	if (state < 0) state = this->windowState();
+	if (state & Qt::WindowMinimized) {
+		return false;
+	} else if (!isVisible()) {
+		return false;
+	}
+    int64 idleTime = 0;//objc_idleTime();
+    LOG(("App Info: idle time %1").arg(idleTime));
+    if (idleTime >= 0) {
+        if (idleTime > IdleMsecs) {
+			if (!psIdle) {
+				psIdle = true;
+				psIdleTimer.start(900);
+			}
+			return false;
+		} else {
+			psNotIdle();
+		}
+    } else { // error
+		psNotIdle();
+	}
+	return true;
+}
+
+bool PsMainWindow::psIsActive(int state) const {
+	if (state < 0) state = this->windowState();
+    return isActiveWindow() && isVisible() && !(state & Qt::WindowMinimized) && !psIdle;
+}
+
+void PsMainWindow::psRefreshTaskbarIcon() {
+}
+
+void PsMainWindow::psUpdateWorkmode() {
+}
+
+void PsMainWindow::psUpdateCounter() {
+	int32 counter = App::histories().unreadFull;
+
+    setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
+
+    QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0'));
+    //_private.setWindowBadge(counter ? cnt : QString());
+}
+
+void PsMainWindow::psInitSize() {
+	setMinimumWidth(st::wndMinWidth);
+	setMinimumHeight(st::wndMinHeight);
+
+	TWindowPos pos(cWindowPos());
+	QRect avail(QDesktopWidget().availableGeometry());
+	bool maximized = false;
+	QRect geom(avail.x() + (avail.width() - st::wndDefWidth) / 2, avail.y() + (avail.height() - st::wndDefHeight) / 2, st::wndDefWidth, st::wndDefHeight);
+	if (pos.w && pos.h) {
+		QList<QScreen*> screens = App::app()->screens();
+		for (QList<QScreen*>::const_iterator i = screens.cbegin(), e = screens.cend(); i != e; ++i) {
+			QByteArray name = (*i)->name().toUtf8();
+			if (pos.moncrc == hashCrc32(name.constData(), name.size())) {
+				QRect screen((*i)->geometry());
+				int32 w = screen.width(), h = screen.height();
+				if (w >= st::wndMinWidth && h >= st::wndMinHeight) {
+					if (pos.w > w) pos.w = w;
+					if (pos.h > h) pos.h = h;
+					pos.x += screen.x();
+					pos.y += screen.y();
+					if (pos.x < screen.x() + screen.width() - 10 && pos.y < screen.y() + screen.height() - 10) {
+						geom = QRect(pos.x, pos.y, pos.w, pos.h);
+					}
+				}
+				break;
+			}
+		}
+
+		if (pos.y < 0) pos.y = 0;
+		maximized = pos.maximized;
+	}
+	setGeometry(geom);
+}
+
+void PsMainWindow::psInitFrameless() {
+    psUpdatedPositionTimer.setSingleShot(true);
+	connect(&psUpdatedPositionTimer, SIGNAL(timeout()), this, SLOT(psSavePosition()));
+
+	if (frameless) {
+		//setWindowFlags(Qt::FramelessWindowHint);
+	}
+
+    connect(windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(psStateChanged(Qt::WindowState)));
+}
+
+void PsMainWindow::psSavePosition(Qt::WindowState state) {
+    if (state == Qt::WindowActive) state = windowHandle()->windowState();
+	if (state == Qt::WindowMinimized || !posInited) return;
+
+	TWindowPos pos(cWindowPos()), curPos = pos;
+
+	if (state == Qt::WindowMaximized) {
+		curPos.maximized = 1;
+	} else {
+		QRect r(geometry());
+		curPos.x = r.x();
+		curPos.y = r.y();
+		curPos.w = r.width();
+		curPos.h = r.height();
+		curPos.maximized = 0;
+	}
+
+	int px = curPos.x + curPos.w / 2, py = curPos.y + curPos.h / 2, d = 0;
+	QScreen *chosen = 0;
+	QList<QScreen*> screens = App::app()->screens();
+	for (QList<QScreen*>::const_iterator i = screens.cbegin(), e = screens.cend(); i != e; ++i) {
+		int dx = (*i)->geometry().x() + (*i)->geometry().width() / 2 - px; if (dx < 0) dx = -dx;
+		int dy = (*i)->geometry().y() + (*i)->geometry().height() / 2 - py; if (dy < 0) dy = -dy;
+		if (!chosen || dx + dy < d) {
+			d = dx + dy;
+			chosen = *i;
+		}
+	}
+	if (chosen) {
+		curPos.x -= chosen->geometry().x();
+		curPos.y -= chosen->geometry().y();
+		QByteArray name = chosen->name().toUtf8();
+		curPos.moncrc = hashCrc32(name.constData(), name.size());
+	}
+
+	if (curPos.w >= st::wndMinWidth && curPos.h >= st::wndMinHeight) {
+		if (curPos.x != pos.x || curPos.y != pos.y || curPos.w != pos.w || curPos.h != pos.h || curPos.moncrc != pos.moncrc || curPos.maximized != pos.maximized) {
+			cSetWindowPos(curPos);
+			App::writeConfig();
+		}
+    }
+}
+
+void PsMainWindow::psUpdatedPosition() {
+    psUpdatedPositionTimer.start(4000);
+}
+
+void PsMainWindow::psStateChanged(Qt::WindowState state) {
+	psUpdateSysMenu(state);
+	psUpdateMargins();
+//    if (state == Qt::WindowMinimized && GetWindowLong(ps_hWnd, GWL_HWNDPARENT)) {
+//		minimizeToTray();
+//    }
+    psSavePosition(state);
+}
+
+void PsMainWindow::psFirstShow() {
+	finished = false;
+
+    psUpdateMargins();
+
+	bool showShadows = true;
+
+	show();
+    //_private.enableShadow(winId());
+	if (cWindowPos().maximized) {
+		setWindowState(Qt::WindowMaximized);
+	}
+
+	if (cFromAutoStart()) {
+		if (cStartMinimized()) {
+			setWindowState(Qt::WindowMinimized);
+			if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
+				hide();
+			} else {
+				show();
+			}
+			showShadows = false;
+		} else {
+			show();
+		}
+	} else {
+		show();
+	}
+	posInited = true;
+}
+
+bool PsMainWindow::psHandleTitle() {
+    return false;
+}
+
+void PsMainWindow::psInitSysMenu() {
+}
+
+void PsMainWindow::psUpdateSysMenu(Qt::WindowState state) {
+}
+
+void PsMainWindow::psUpdateMargins() {
+}
+
+void PsMainWindow::psFlash() {
+    //_private.startBounce();
+}
+
+PsMainWindow::~PsMainWindow() {
+	finished = true;
+    psClearNotifyFast();
+}
+
+void PsMainWindow::psNotify(History *history, MsgId msgId) {
+	if (App::quiting() || !history->notifyFrom) return;
+    
+	bool haveSetting = (history->peer->notify != UnknownNotifySettings);
+	if (haveSetting) {
+		if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
+			history->clearNotifyFrom();
+			return;
+		}
+	} else {
+		App::wnd()->getNotifySetting(MTP_inputNotifyPeer(history->peer->input));
+	}
+    
+	uint64 ms = getms() + NotifyWaitTimeout;
+	notifyWhenAlerts[history].insert(ms);
+	if (cDesktopNotify()) {
+		NotifyWhenMaps::iterator i = notifyWhenMaps.find(history);
+		if (i == notifyWhenMaps.end()) {
+			i = notifyWhenMaps.insert(history, NotifyWhenMap());
+		}
+		if (i.value().constFind(msgId) == i.value().cend()) {
+			i.value().insert(msgId, ms);
+		}
+		NotifyWaiters *addTo = haveSetting ? &notifyWaiters : &notifySettingWaiters;
+		if (addTo->constFind(history) == addTo->cend()) {
+			addTo->insert(history, NotifyWaiter(msgId, ms));
+		}
+	}
+	if (haveSetting) {
+		if (!notifyWaitTimer.isActive()) {
+			notifyWaitTimer.start(NotifyWaitTimeout);
+		}
+	}
+}
+
+void PsMainWindow::psNotifyFire() {
+	psShowNextNotify();
+}
+
+void PsMainWindow::psNotifySettingGot() {
+	int32 t = unixtime();
+	for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) {
+		History *history = i.key();
+		if (history->peer->notify == UnknownNotifySettings) {
+			++i;
+		} else {
+			if (history->peer->notify == EmptyNotifySettings || history->peer->notify->mute <= t) {
+				notifyWaiters.insert(i.key(), i.value());
+			}
+			i = notifySettingWaiters.erase(i);
+		}
+	}
+	notifyWaitTimer.stop();
+	psShowNextNotify();
+}
+
+void PsMainWindow::psClearNotify(History *history) {
+	if (!history) {
+		for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+			(*i)->unlinkHistory();
+		}
+        //_private.clearNotifies();
+		for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) {
+			i.key()->clearNotifyFrom();
+		}
+		notifyWaiters.clear();
+		notifySettingWaiters.clear();
+		notifyWhenMaps.clear();
+		return;
+	}
+	notifyWaiters.remove(history);
+	notifySettingWaiters.remove(history);
+	for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+		(*i)->unlinkHistory(history);
+	}
+    //_private.clearNotifies(history->peer->id);
+	notifyWhenMaps.remove(history);
+	notifyWhenAlerts.remove(history);
+}
+
+void PsMainWindow::psClearNotifyFast() {
+	notifyWaiters.clear();
+	notifySettingWaiters.clear();
+	for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+		(*i)->deleteLater();
+	}
+    //_private.clearNotifies();
+	notifyWindows.clear();
+	notifyWhenMaps.clear();
+	notifyWhenAlerts.clear();
+}
+
+void PsMainWindow::psActivateNotifies() {
+    if (cCustomNotifies()) {
+        for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+            //_private.activateWnd((*i)->winId());
+        }
+    }
+}
+
+namespace {
+	QRect _monitorRect;
+	uint64 _monitorLastGot = 0;
+	QRect _desktopRect() {
+		uint64 tnow = getms();
+		if (tnow > _monitorLastGot + 1000 || tnow < _monitorLastGot) {
+			_monitorLastGot = tnow;
+            _monitorRect = QApplication::desktop()->availableGeometry(App::wnd());
+		}
+		return _monitorRect;
+	}
+}
+
+void PsMainWindow::psShowNextNotify(PsNotifyWindow *remove) {
+	if (App::quiting()) return;
+    
+	int32 count = NotifyWindows;
+	if (remove) {
+		for (PsNotifyWindows::iterator i = notifyWindows.begin(), e = notifyWindows.end(); i != e; ++i) {
+			if ((*i) == remove) {
+				notifyWindows.erase(i);
+				break;
+			}
+		}
+	}
+    
+	uint64 ms = getms(), nextAlert = 0;
+	bool alert = false;
+	for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) {
+		while (!i.value().isEmpty() && *i.value().begin() <= ms) {
+			i.value().erase(i.value().begin());
+			NotifySettingsPtr n = i.key()->peer->notify;
+			if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= unixtime())) {
+				alert = true;
+			}
+		}
+		if (i.value().isEmpty()) {
+			i = notifyWhenAlerts.erase(i);
+		} else {
+			if (!nextAlert || nextAlert > *i.value().begin()) {
+				nextAlert = *i.value().begin();
+			}
+			++i;
+		}
+	}
+	if (alert) {
+		psFlash();
+		App::playSound();
+	}
+    
+    if (cCustomNotifies()) {
+        for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+            int32 ind = (*i)->index();
+            if (ind < 0) continue;
+            --count;
+        }
+    }
+	if (count <= 0 || !cDesktopNotify()) {
+		if (nextAlert) {
+			notifyWaitTimer.start(nextAlert - ms);
+		}
+		return;
+	}
+    
+	QRect r = _desktopRect();
+	int32 x = r.x() + r.width() - st::notifyWidth - st::notifyDeltaX, y = r.y() + r.height() - st::notifyHeight - st::notifyDeltaY;
+	while (count > 0) {
+		uint64 next = 0;
+		HistoryItem *notifyItem = 0;
+		NotifyWaiters::iterator notifyWaiter;
+		for (NotifyWaiters::iterator i = notifyWaiters.begin(); i != notifyWaiters.end(); ++i) {
+			History *history = i.key();
+			if (history->notifyFrom && history->notifyFrom->id != i.value().msg) {
+				NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
+				if (j == notifyWhenMaps.end()) {
+					history->clearNotifyFrom();
+					i = notifyWaiters.erase(i);
+					continue;
+				}
+				do {
+					NotifyWhenMap::const_iterator k = j.value().constFind(history->notifyFrom->id);
+					if (k != j.value().cend()) {
+						i.value().msg = k.key();
+						i.value().when = k.value();
+						break;
+					}
+					history->getNextNotifyFrom();
+				} while (history->notifyFrom);
+			}
+			if (!history->notifyFrom) {
+				notifyWhenMaps.remove(history);
+				i = notifyWaiters.erase(i);
+				continue;
+			}
+			uint64 when = i.value().when;
+			if (!notifyItem || next > when) {
+				next = when;
+				notifyItem = history->notifyFrom;
+				notifyWaiter = i;
+			}
+		}
+		if (notifyItem) {
+			if (next > ms) {
+				if (nextAlert && nextAlert < next) {
+					next = nextAlert;
+					nextAlert = 0;
+				}
+				notifyWaitTimer.start(next - ms);
+				break;
+			} else {
+                if (cCustomNotifies()) {
+                    PsNotifyWindow *notify = new PsNotifyWindow(notifyItem, x, y);
+                    notifyWindows.push_back(notify);
+                    //notify->hide();
+                    //_private.holdOnTop(notify->winId());
+                    //notify->show();
+                    //_private.showOverAll(notify->winId());
+                    --count;
+                } else {
+                    //_private.showNotify(notifyItem->history()->peer->id, notifyItem->history()->peer->name, notifyItem->notificationHeader(), notifyItem->notificationText());
+                }
+                
+				uint64 ms = getms();
+				History *history = notifyItem->history();
+				history->getNextNotifyFrom();
+				NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
+				if (j == notifyWhenMaps.end() || !history->notifyFrom) {
+					history->clearNotifyFrom();
+					notifyWaiters.erase(notifyWaiter);
+					if (j != notifyWhenMaps.end()) notifyWhenMaps.erase(j);
+					continue;
+				}
+				j.value().remove(notifyItem->id);
+				do {
+					NotifyWhenMap::const_iterator k = j.value().constFind(history->notifyFrom->id);
+					if (k != j.value().cend()) {
+						notifyWaiter.value().msg = k.key();
+						notifyWaiter.value().when = k.value();
+						break;
+					}
+					history->getNextNotifyFrom();
+				} while (history->notifyFrom);
+				if (!history->notifyFrom) {
+					notifyWaiters.erase(notifyWaiter);
+					notifyWhenMaps.erase(j);
+					continue;
+				}
+			}
+		} else {
+			break;
+		}
+	}
+	if (nextAlert) {
+		notifyWaitTimer.start(nextAlert - ms);
+	}
+    
+	count = NotifyWindows - count;
+	for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+		int32 ind = (*i)->index();
+		if (ind < 0) continue;
+		--count;
+		(*i)->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY));
+	}
+}
+
+void PsMainWindow::psStopHiding() {
+    if (cCustomNotifies()) {
+        for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+            (*i)->stopHiding();
+        }
+    }
+}
+
+void PsMainWindow::psStartHiding() {
+    if (cCustomNotifies()) {
+        for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+            (*i)->startHiding();
+        }
+    }
+}
+
+void PsMainWindow::psUpdateNotifies() {
+    if (cCustomNotifies()) {
+        for (PsNotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
+            (*i)->updatePeerPhoto();
+        }
+    }
+}
+
+PsNotifyWindow::PsNotifyWindow(HistoryItem *item, int32 x, int32 y) : history(item->history()),// started(GetTickCount()),
+close(this, st::notifyClose), alphaDuration(st::notifyFastAnim), posDuration(st::notifyFastAnim), hiding(false), _index(0), aOpacity(0), aOpacityFunc(st::notifyFastAnimFunc), aY(y + st::notifyHeight + st::notifyDeltaY) {
+    
+	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);
+    
+	{
+		QPainter p(&img);
+		p.setPen(st::notifyBorder->p);
+		p.setBrush(Qt::NoBrush);
+		p.drawRect(0, 0, w - 1, h - 1);
+        
+		if (history->peer->photo->loaded()) {
+			p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), history->peer->photo->pix(st::notifyPhotoSize));
+		} else {
+			MTP::clearLoaderPriorities();
+			peerPhoto = history->peer->photo;
+			peerPhoto->load(true, true);
+		}
+        
+		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 (history->peer->chat) {
+			p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgLeft, rectForName.top() + st::dlgChatImgTop), App::sprite(), st::dlgChatImg);
+			rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip);
+		}
+        
+		QDateTime now(QDateTime::currentDateTime()), lastTime(item->date);
+		QDate nowDate(now.date()), lastDate(lastTime.date());
+		QString dt = lastTime.toString(qsl("hh:mm"));
+		int32 dtWidth = st::dlgHistFont->m.width(dt);
+		rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip);
+		p.setFont(st::dlgDateFont->f);
+		p.setPen(st::dlgDateColor->p);
+		p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::dlgHistFont->ascent, dt);
+        
+		const HistoryItem *textCachedFor = 0;
+		Text itemTextCache(itemWidth);
+		bool active = false;
+		item->drawInDialog(p, QRect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dlgFont->height), active, textCachedFor, itemTextCache);
+        
+		p.setPen(st::dlgNameColor->p);
+		history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
+	}
+	pm = QPixmap::fromImage(img);
+    
+	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(unlinkHistory()));
+	close.setAcceptBoth(true);
+	close.move(w - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y());
+	close.show();
+    
+	aY.start(y);
+	setGeometry(x, aY.current(), st::notifyWidth, st::notifyHeight);
+    
+	aOpacity.start(1);
+	setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
+    setAttribute(Qt::WA_MacAlwaysShowToolWindow);
+    
+	show();
+    
+	setWindowOpacity(aOpacity.current());
+    
+	alphaDuration = posDuration = st::notifyFastAnim;
+	anim::start(this);
+    
+	checkLastInput();
+}
+
+void PsNotifyWindow::checkLastInput() {
+    // TODO
+	if (true) {
+		hideTimer.start(st::notifyWaitLongHide);
+	} else {
+		inputTimer.start(300);
+	}
+}
+
+void PsNotifyWindow::moveTo(int32 x, int32 y, int32 index) {
+	if (index >= 0) {
+		_index = index;
+	}
+	move(x, aY.current());
+	aY.start(y);
+	aOpacity.restart();
+	posDuration = st::notifyFastAnim;
+	anim::start(this);
+}
+
+void PsNotifyWindow::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 = QPixmap::fromImage(img);
+		update();
+	}
+}
+
+void PsNotifyWindow::unlinkHistory(History *hist) {
+	if (!hist || hist == history) {
+		animHide(st::notifyFastAnim, st::notifyFastAnimFunc);
+		history = 0;
+		App::wnd()->psShowNextNotify();
+	}
+}
+
+void PsNotifyWindow::enterEvent(QEvent */*e*/) {
+	if (!history) return;
+	if (App::wnd()) App::wnd()->psStopHiding();
+}
+
+void PsNotifyWindow::leaveEvent(QEvent */*e*/) {
+	if (!history) return;
+	App::wnd()->psStartHiding();
+}
+
+void PsNotifyWindow::startHiding() {
+	hideTimer.start(st::notifyWaitShortHide);
+}
+
+void PsNotifyWindow::mousePressEvent(QMouseEvent *e) {
+	if (!history) return;
+	if (e->button() == Qt::RightButton) {
+		unlinkHistory();
+	} else if (history) {
+		App::wnd()->showFromTray();
+		App::wnd()->hideSettings();
+		App::main()->showPeer(history->peer->id, false, true);
+        unlinkHistory();
+		e->ignore();
+	}
+}
+
+void PsNotifyWindow::paintEvent(QPaintEvent *e) {
+	QPainter p(this);
+	p.drawPixmap(0, 0, pm);
+}
+
+void PsNotifyWindow::animHide(float64 duration, anim::transition func) {
+	if (!history) return;
+	alphaDuration = duration;
+	aOpacityFunc = func;
+	aOpacity.start(0);
+	aY.restart();
+	hiding = true;
+	anim::start(this);
+}
+
+void PsNotifyWindow::stopHiding() {
+	if (!history) return;
+	alphaDuration = st::notifyFastAnim;
+	aOpacityFunc = st::notifyFastAnimFunc;
+	aOpacity.start(1);
+	aY.restart();
+	hiding = false;
+	hideTimer.stop();
+	anim::start(this);
+}
+
+void PsNotifyWindow::hideByTimer() {
+	if (!history) return;
+	animHide(st::notifySlowHide, st::notifySlowHideFunc);
+}
+
+bool PsNotifyWindow::animStep(float64 ms) {
+	float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration;
+	if (dtAlpha >= 1) {
+		aOpacity.finish();
+		if (hiding) {
+			deleteLater();
+		}
+	} else {
+		aOpacity.update(dtAlpha, aOpacityFunc);
+	}
+	setWindowOpacity(aOpacity.current());
+	if (dtPos >= 1) {
+		aY.finish();
+	} else {
+		aY.update(dtPos, anim::linear);
+	}
+	move(x(), aY.current());
+	update();
+	return (dtAlpha < 1 || (!hiding && dtPos < 1));
+}
+
+PsNotifyWindow::~PsNotifyWindow() {
+	if (App::wnd()) App::wnd()->psShowNextNotify(this);
+}
+
+PsApplication::PsApplication(int &argc, char **argv) : QApplication(argc, argv) {
+}
+
+void PsApplication::psInstallEventFilter() {
+    delete _psEventFilter;
+	_psEventFilter = new _PsEventFilter();
+    installNativeEventFilter(_psEventFilter);
+}
+
+PsApplication::~PsApplication() {
+    delete _psEventFilter;
+    _psEventFilter = 0;
+}
+
+PsUpdateDownloader::PsUpdateDownloader(QThread *thread, const MTPDhelp_appUpdate &update) : reply(0), already(0), full(0) {
+	updateUrl = qs(update.vurl);
+	moveToThread(thread);
+	manager.moveToThread(thread);
+	App::setProxySettings(manager);
+
+	connect(thread, SIGNAL(started()), this, SLOT(start()));
+	initOutput();
+}
+
+PsUpdateDownloader::PsUpdateDownloader(QThread *thread, const QString &url) : reply(0), already(0), full(0) {
+	updateUrl = url;
+	moveToThread(thread);
+	manager.moveToThread(thread);
+	App::setProxySettings(manager);
+
+	connect(thread, SIGNAL(started()), this, SLOT(start()));
+	initOutput();
+}
+
+void PsUpdateDownloader::initOutput() {
+	QString fileName;
+	QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl);
+	if (m.hasMatch()) {
+		fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
+	}
+	if (fileName.isEmpty()) {
+		fileName = qsl("tupdate-%1").arg(rand());
+	}
+	QString dirStr = cWorkingDir() + qsl("tupdates/");
+	fileName = dirStr + fileName;
+	QFileInfo file(fileName);
+
+	QDir dir(dirStr);
+	if (dir.exists()) {
+		QFileInfoList all = dir.entryInfoList(QDir::Files);
+		for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) {
+			if (i->absoluteFilePath() != file.absoluteFilePath()) {
+				QFile::remove(i->absoluteFilePath());
+			}
+		}
+	} else {
+		dir.mkdir(dir.absolutePath());
+	}
+	outputFile.setFileName(fileName);
+	if (file.exists()) {
+		uint64 fullSize = file.size();
+		if (fullSize < INT_MAX) {
+			int32 goodSize = (int32)fullSize;
+			if (goodSize % UpdateChunk) {
+				goodSize = goodSize - (goodSize % UpdateChunk);
+				if (goodSize) {
+					if (outputFile.open(QIODevice::ReadOnly)) {
+						QByteArray goodData = outputFile.readAll().mid(0, goodSize);
+						outputFile.close();
+						if (outputFile.open(QIODevice::WriteOnly)) {
+							outputFile.write(goodData);
+							outputFile.close();
+							
+							QMutexLocker lock(&mutex);
+							already = goodSize;
+						}
+					}
+				}
+			} else {
+				QMutexLocker lock(&mutex);
+				already = goodSize;
+			}
+		}
+		if (!already) {
+			QFile::remove(fileName);
+		}
+	}
+}
+
+void PsUpdateDownloader::start() {
+	sendRequest();
+}
+
+void PsUpdateDownloader::sendRequest() {
+	QNetworkRequest req(updateUrl);
+	QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";// + QByteArray::number(already + cUpdateChunk() - 1); 
+	req.setRawHeader("Range", rangeHeaderValue);
+	req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+	if (reply) reply->deleteLater();
+	reply = manager.get(req);
+	connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64)));
+	connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError)));
+	connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot()));
+}
+
+void PsUpdateDownloader::partMetaGot() {
+	typedef QList<QNetworkReply::RawHeaderPair> Pairs;
+	Pairs pairs = reply->rawHeaderPairs();
+	for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) {
+		if (QString::fromUtf8(i->first).toLower() == "content-range") {
+			QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second));
+			if (m.hasMatch()) {
+				{
+					QMutexLocker lock(&mutex);
+					full = m.captured(1).toInt();
+				}
+				emit App::app()->updateDownloading(already, full);
+			}
+		}
+	}
+}
+
+int32 PsUpdateDownloader::ready() {
+	QMutexLocker lock(&mutex);
+	return already;
+}
+
+int32 PsUpdateDownloader::size() {
+	QMutexLocker lock(&mutex);
+	return full;
+}
+
+void PsUpdateDownloader::partFinished(qint64 got, qint64 total) {
+	if (!reply) return;
+
+	QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+    if (statusCode.isValid()) {
+	    int status = statusCode.toInt();
+		if (status != 200 && status != 206 && status != 416) {
+			LOG(("Update Error: Bad HTTP status received in partFinished(): %1").arg(status));
+			return fatalFail();
+		}
+	}
+
+	if (!already && !full) {
+		QMutexLocker lock(&mutex);
+		full = total;
+	}
+	DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total));
+
+	if (!outputFile.isOpen()) {
+		if (!outputFile.open(QIODevice::Append)) {
+			LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName()));
+			return fatalFail();
+		}
+	}
+	QByteArray r = reply->readAll();
+	if (!r.isEmpty()) {
+		outputFile.write(r);
+
+		QMutexLocker lock(&mutex);
+		already += r.size();
+	}
+	if (got >= total) {
+		reply->deleteLater();
+		reply = 0;
+		outputFile.close();
+		unpackUpdate();
+	} else {
+		emit App::app()->updateDownloading(already, full);
+	}
+}
+
+void PsUpdateDownloader::partFailed(QNetworkReply::NetworkError e) {
+	if (!reply) return;
+
+	QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+	reply->deleteLater();
+	reply = 0;
+    if (statusCode.isValid()) {
+	    int status = statusCode.toInt();
+		if (status == 416) { // Requested range not satisfiable
+			outputFile.close();
+			unpackUpdate();
+			return;
+		}
+	}
+	LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e));
+	emit App::app()->updateFailed();
+}
+
+void PsUpdateDownloader::deleteDir(const QString &dir) {
+//	objc_deleteDir(dir);
+}
+
+void PsUpdateDownloader::fatalFail() {
+	clearAll();
+	emit App::app()->updateFailed();
+}
+
+void PsUpdateDownloader::clearAll() {
+	deleteDir(cWorkingDir() + qsl("tupdates"));
+}
+
+#ifdef Q_OS_WIN
+typedef DWORD VerInt;
+typedef WCHAR VerChar;
+#else
+typedef int VerInt;
+typedef wchar_t VerChar;
+#endif
+
+void PsUpdateDownloader::unpackUpdate() {
+    QByteArray packed;
+	if (!outputFile.open(QIODevice::ReadOnly)) {
+		LOG(("Update Error: cant read updates file!"));
+		return fatalFail();
+	}
+#ifdef Q_OS_WIN // use Lzma SDK for win
+	const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
+#else
+	const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
+#endif
+	QByteArray compressed = outputFile.readAll();
+	int32 compressedLen = compressed.size() - hSize;
+	if (compressedLen <= 0) {
+		LOG(("Update Error: bad compressed size: %1").arg(compressed.size()));
+		return fatalFail();
+	}
+	outputFile.close();
+
+	QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyDirPath = cWorkingDir() + qsl("tupdates/ready");
+	deleteDir(tempDirPath);
+	deleteDir(readyDirPath);
+
+	QDir tempDir(tempDirPath), readyDir(readyDirPath);
+	if (tempDir.exists() || readyDir.exists()) {
+		LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!"));
+		return fatalFail();
+	}
+
+	uchar sha1Buffer[20];
+	bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen);
+	if (!goodSha1) {
+		LOG(("Update Error: bad SHA1 hash of update file!"));
+		return fatalFail();
+	}
+
+	RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(UpdatesPublicKey), -1), 0, 0, 0);
+	if (!pbKey) {
+		LOG(("Update Error: cant read public rsa key!"));
+		return fatalFail();
+	}
+    if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
+		RSA_free(pbKey);
+		LOG(("Update Error: bad RSA signature of update file!"));
+		return fatalFail();
+    }
+	RSA_free(pbKey);
+
+	QByteArray uncompressed;
+
+	int32 uncompressedLen;
+	memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen);
+	uncompressed.resize(uncompressedLen);
+
+	size_t resultLen = uncompressed.size();
+#ifdef Q_OS_WIN // use Lzma SDK for win
+	SizeT srcLen = compressedLen;
+	int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
+	if (uncompressRes != SZ_OK) {
+		LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
+		return fatalFail();
+	}
+#else
+	lzma_stream stream = LZMA_STREAM_INIT;
+
+	lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED);
+	if (ret != LZMA_OK) {
+		const char *msg;
+		switch (ret) {
+			case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break;
+			case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break;
+			case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break;
+			default: msg = "Unknown error, possibly a bug"; break;
+		}
+		LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret));
+		return fatalFail();
+	}
+
+	stream.avail_in = compressedLen;
+	stream.next_in = (uint8_t*)(compressed.constData() + hSize);
+	stream.avail_out = resultLen;
+	stream.next_out = (uint8_t*)uncompressed.data();
+
+	lzma_ret res = lzma_code(&stream, LZMA_FINISH);
+	if (stream.avail_in) {
+		LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen));
+		return fatalFail();
+	} else if (stream.avail_out) {
+		LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen));
+		return fatalFail();
+	}
+	lzma_end(&stream);
+	if (res != LZMA_OK && res != LZMA_STREAM_END) {
+		const char *msg;
+		switch (res) {
+			case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break;
+			case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break;
+			case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break;
+			case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break;
+			case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break;
+			default: msg = "Unknown error, possibly a bug"; break;
+		}
+		LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res));
+		return fatalFail();
+	}
+#endif
+
+	tempDir.mkdir(tempDir.absolutePath());
+
+	quint32 version;
+	{
+		QBuffer buffer(&uncompressed);
+		buffer.open(QIODevice::ReadOnly);
+		QDataStream stream(&buffer);
+		stream.setVersion(QDataStream::Qt_5_1);
+
+		stream >> version;
+		if (stream.status() != QDataStream::Ok) {
+			LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status()));
+			return fatalFail();
+		}
+		if (version <= AppVersion) {
+			LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion));
+			return fatalFail();
+		}
+
+		quint32 filesCount;
+		stream >> filesCount;
+		if (stream.status() != QDataStream::Ok) {
+			LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status()));
+			return fatalFail();
+		}
+		if (!filesCount) {
+			LOG(("Update Error: update is empty!"));
+			return fatalFail();
+		}
+		for (uint32 i = 0; i < filesCount; ++i) {
+			QString relativeName;
+			quint32 fileSize;
+			QByteArray fileInnerData;
+			bool executable = false;
+
+			stream >> relativeName >> fileSize >> fileInnerData;
+#if defined Q_OS_MAC || defined Q_OS_LINUX
+			stream >> executable;
+#endif
+			if (stream.status() != QDataStream::Ok) {
+				LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
+				return fatalFail();
+			}
+			if (fileSize != quint32(fileInnerData.size())) {
+				LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size()));
+				return fatalFail();
+			}
+
+			QFile f(tempDirPath + '/' + relativeName);
+			if (!QDir().mkpath(QFileInfo(f).absolutePath())) {
+				LOG(("Update Error: cant mkpath for file '%1'").arg(tempDirPath + '/' + relativeName));
+				return fatalFail();
+			}
+			if (!f.open(QIODevice::WriteOnly)) {
+				LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName));
+				return fatalFail();
+			}
+			if (f.write(fileInnerData) != fileSize) {
+				f.close();
+				LOG(("Update Error: cant write file '%1'").arg(tempDirPath + '/' + relativeName));
+				return fatalFail();
+			}
+			f.close();
+			if (executable) {
+				QFileDevice::Permissions p = f.permissions();
+				p |= QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther;
+				f.setPermissions(p);
+			}
+		}
+
+		// create tdata/version file
+		tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath());
+		std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString();
+
+		VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar));
+		VerChar versionStr[32];
+		memcpy(versionStr, versionString.c_str(), versionLen);
+
+		QFile fVersion(tempDirPath + qsl("/tdata/version"));		
+		if (!fVersion.open(QIODevice::WriteOnly)) {
+			LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version")));
+			return fatalFail();
+		}
+		fVersion.write((const char*)&versionNum, sizeof(VerInt));
+		fVersion.write((const char*)&versionLen, sizeof(VerInt));
+		fVersion.write((const char*)&versionStr[0], versionLen);
+		fVersion.close();
+	}
+	
+	if (!tempDir.rename(tempDir.absolutePath(), readyDir.absolutePath())) {
+		LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2'").arg(tempDir.absolutePath()).arg(readyDir.absolutePath()));
+		return fatalFail();
+	}
+	deleteDir(tempDirPath);
+	outputFile.remove();
+
+    emit App::app()->updateReady();
+}
+
+PsUpdateDownloader::~PsUpdateDownloader() {
+	delete reply;
+	reply = 0;
+}
+
+void psActivateProcess(uint64 pid) {
+//	objc_activateProgram();
+}
+
+QString psCurrentCountry() {
+    QString country;// = objc_currentCountry();
+	return country.isEmpty() ? QString::fromLatin1(DefaultCountry) : country;
+}
+
+QString psCurrentLanguage() {
+    QString lng;// = objc_currentLang();
+	return lng.isEmpty() ? QString::fromLatin1(DefaultLanguage) : lng;
+}
+
+QString psAppDataPath() {
+    return QString();//objc_appDataPath();
+}
+
+QString psCurrentExeDirectory(int argc, char *argv[]) {
+    QString first = argc ? QString::fromLocal8Bit(argv[0]) : QString();
+    if (!first.isEmpty()) {
+        QFileInfo info(first);
+        if (info.exists()) {
+            QDir result(info.absolutePath() + qsl("/../../.."));
+            return result.absolutePath() + '/';
+        }
+    }
+	return QString();
+}
+
+void psDoCleanup() {
+	try {
+		psAutoStart(false, true);
+	} catch (...) {
+	}
+}
+
+int psCleanup() {
+	psDoCleanup();
+	return 0;
+}
+
+void psDoFixPrevious() {
+}
+
+int psFixPrevious() {
+	psDoFixPrevious();
+	return 0;
+}
+
+bool psCheckReadyUpdate() {
+    QString readyPath = cWorkingDir() + qsl("tupdates/ready");
+	if (!QDir(readyPath).exists()) {
+		return false;
+	}
+
+	// check ready version
+	QString versionPath = readyPath + qsl("/tdata/version");
+	{
+		QFile fVersion(versionPath);
+		if (!fVersion.open(QIODevice::ReadOnly)) {
+			LOG(("Update Error: cant read version file '%1'").arg(versionPath));
+			PsUpdateDownloader::clearAll();
+			return false;
+		}
+		VerInt versionNum;
+		if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) {
+			LOG(("Update Error: cant read version from file '%1'").arg(versionPath));
+			PsUpdateDownloader::clearAll();
+			return false;
+		}
+		fVersion.close();
+		if (versionNum <= AppVersion) {
+			LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion));
+			PsUpdateDownloader::clearAll();
+			return false;
+		}
+	}
+
+#ifdef Q_OS_WIN
+	QString curUpdater = (cExeDir() + "Updater.exe");
+	QFileInfo updater(cWorkingDir() + "tupdates/ready/Updater.exe");
+#elif defined Q_OS_MAC
+	QString curUpdater = (cExeDir() + "Telegram.app/Contents/Frameworks/Updater");
+	QFileInfo updater(cWorkingDir() + "tupdates/ready/Telegram.app/Contents/Frameworks/Updater");
+#elif defined Q_OS_LINUX
+    QString curUpdater;
+    QFileInfo updater;
+#endif
+	if (!updater.exists()) {
+		QFileInfo current(curUpdater);
+		if (!current.exists()) {
+			PsUpdateDownloader::clearAll();
+			return false;
+		}
+		if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) {
+			PsUpdateDownloader::clearAll();
+			return false;
+		}
+	}
+#ifdef Q_OS_WIN
+	if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) {
+		PsUpdateDownloader::clearAll();
+		return false;
+	}
+	if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
+		PsUpdateDownloader::clearAll();
+		return false;
+    }
+#elif defined Q_OS_MAC
+	QFileInfo to(curUpdater);
+	QDir().mkpath(to.absolutePath());
+	if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) {
+		PsUpdateDownloader::clearAll();
+		return false;
+	}
+#endif
+    return true;
+}
+
+void psPostprocessFile(const QString &name) {
+}
+
+void psOpenFile(const QString &name, bool openWith) {
+    //objc_openFile(name, openWith);
+}
+
+void psShowInFolder(const QString &name) {
+    //objc_showInFinder(name, QFileInfo(name).absolutePath());
+}
+
+void psFinish() {
+    //objc_finish();
+}
+
+void psExecUpdater() {
+    if (true /*!objc_execUpdater()*/) {
+		QString readyPath = cWorkingDir() + qsl("tupdates/ready");
+		PsUpdateDownloader::deleteDir(readyPath);
+	}
+}
+
+void psExecTelegram() {
+    //objc_execTelegram();
+}
+
+void psAutoStart(bool start, bool silent) {
+}
diff --git a/Telegram/SourceFiles/pspecific_linux.h b/Telegram/SourceFiles/pspecific_linux.h
new file mode 100644
index 000000000..e23826df3
--- /dev/null
+++ b/Telegram/SourceFiles/pspecific_linux.h
@@ -0,0 +1,257 @@
+/*
+This file is part of Telegram Desktop,
+an unofficial desktop 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.
+ 
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014 John Preston, https://tdesktop.com
+*/
+#pragma once
+
+inline QString psServerPrefix() {
+    return qsl("/tmp/");
+}
+inline void psCheckLocalSocket(const QString &serverName) {
+    QFile address(serverName);
+	if (address.exists()) {
+		address.remove();
+	}
+}
+
+
+class PsNotifyWindow : public QWidget, public Animated {
+	Q_OBJECT
+    
+public:
+    
+	PsNotifyWindow(HistoryItem *item, int32 x, int32 y);
+    
+	void enterEvent(QEvent *e);
+	void leaveEvent(QEvent *e);
+	void mousePressEvent(QMouseEvent *e);
+	void paintEvent(QPaintEvent *e);
+    
+	bool animStep(float64 ms);
+	void animHide(float64 duration, anim::transition func);
+	void startHiding();
+	void stopHiding();
+	void moveTo(int32 x, int32 y, int32 index = -1);
+    
+	void updatePeerPhoto();
+    
+	int32 index() const {
+		return history ? _index : -1;
+	}
+    
+	~PsNotifyWindow();
+    
+    public slots:
+    
+	void hideByTimer();
+	void checkLastInput();
+    
+	void unlinkHistory(History *hist = 0);
+    
+private:
+    
+//	DWORD started;
+    
+	History *history;
+	IconedButton close;
+	QPixmap pm;
+	float64 alphaDuration, posDuration;
+	QTimer hideTimer, inputTimer;
+	bool hiding;
+	int32 _index;
+	anim::fvalue aOpacity;
+	anim::transition aOpacityFunc;
+	anim::ivalue aY;
+	ImagePtr peerPhoto;
+    
+};
+
+typedef QList<PsNotifyWindow*> PsNotifyWindows;
+
+class PsMainWindow : public QMainWindow {
+	Q_OBJECT
+
+public:
+	PsMainWindow(QWidget *parent = 0);
+
+	int32 psResizeRowWidth() const {
+		return 0;//st::wndResizeAreaWidth;
+	}
+
+	void psInitFrameless();
+	void psInitSize();
+
+	void psFirstShow();
+	void psInitSysMenu();
+	void psUpdateSysMenu(Qt::WindowState state);
+	void psUpdateMargins();
+	void psUpdatedPosition();
+
+	bool psHandleTitle();
+
+	void psFlash();
+    void psNotifySettingGot();
+
+	bool psIsActive(int state = -1) const;
+	bool psIsOnline(int state) const;
+
+	void psUpdateWorkmode();
+
+	void psRefreshTaskbarIcon();
+	virtual bool minimizeToTray() {
+		return false;
+	}
+
+	void psNotify(History *history, MsgId msgId);
+	void psClearNotify(History *history = 0);
+	void psClearNotifyFast();
+	void psShowNextNotify(PsNotifyWindow *remove = 0);
+    void psActivateNotifies();
+	void psStopHiding();
+	void psStartHiding();
+	void psUpdateNotifies();
+
+	bool psPosInited() const {
+		return posInited;
+	}
+    
+	~PsMainWindow();
+
+public slots:
+
+	void psStateChanged(Qt::WindowState state);
+	void psUpdateCounter();
+	void psSavePosition(Qt::WindowState state = Qt::WindowActive);
+	void psIdleTimeout();
+	void psNotifyFire();
+
+protected:
+
+	void psNotIdle() const;
+
+	bool posInited;
+    QSystemTrayIcon *trayIcon;
+    QMenu *trayIconMenu;
+    QImage icon256;
+    virtual void setupTrayIcon() {
+    }
+    
+	typedef QMap<MsgId, uint64> NotifyWhenMap;
+	typedef QMap<History*, NotifyWhenMap> NotifyWhenMaps;
+	NotifyWhenMaps notifyWhenMaps;
+	struct NotifyWaiter {
+		NotifyWaiter(MsgId msg, uint64 when) : msg(msg), when(when) {
+		}
+		MsgId msg;
+		uint64 when;
+	};
+	typedef QMap<History*, NotifyWaiter> NotifyWaiters;
+	NotifyWaiters notifyWaiters;
+	NotifyWaiters notifySettingWaiters;
+	QTimer notifyWaitTimer;
+    
+	typedef QSet<uint64> NotifyWhenAlert;
+	typedef QMap<History*, NotifyWhenAlert> NotifyWhenAlerts;
+	NotifyWhenAlerts notifyWhenAlerts;
+    
+	PsNotifyWindows notifyWindows;
+
+    QTimer psUpdatedPositionTimer;
+
+private:
+	mutable bool psIdle;
+	mutable QTimer psIdleTimer;
+};
+
+
+class PsApplication : public QApplication {
+	Q_OBJECT
+
+public:
+
+	PsApplication(int &argc, char **argv);
+	void psInstallEventFilter();
+	~PsApplication();
+
+signals:
+
+	void updateChecking();
+	void updateLatest();
+	void updateDownloading(qint64 ready, qint64 total);
+	void updateReady();
+	void updateFailed();
+
+};
+
+class PsUpdateDownloader : public QObject {
+	Q_OBJECT
+
+public:
+	PsUpdateDownloader(QThread *thread, const MTPDhelp_appUpdate &update);
+	PsUpdateDownloader(QThread *thread, const QString &url);
+
+	void unpackUpdate();
+
+	int32 ready();
+	int32 size();
+
+	static void deleteDir(const QString &dir);
+	static void clearAll();
+
+	~PsUpdateDownloader();
+
+public slots:
+
+	void start();
+	void partMetaGot();
+	void partFinished(qint64 got, qint64 total);
+	void partFailed(QNetworkReply::NetworkError e);
+	void sendRequest();
+
+private:
+	void initOutput();
+
+	void fatalFail();
+
+	QString updateUrl;
+	QNetworkAccessManager manager;
+	QNetworkReply *reply;
+	int32 already, full;
+	QFile outputFile;
+
+	QMutex mutex;
+
+};
+
+void psActivateProcess(uint64 pid);
+QString psLocalServerPrefix();
+QString psCurrentCountry();
+QString psCurrentLanguage();
+QString psAppDataPath();
+QString psCurrentExeDirectory(int argc, char *argv[]);
+void psAutoStart(bool start, bool silent = false);
+
+int psCleanup();
+int psFixPrevious();
+
+bool psCheckReadyUpdate();
+void psExecUpdater();
+void psExecTelegram();
+
+void psPostprocessFile(const QString &name);
+void psOpenFile(const QString &name, bool openWith = false);
+void psShowInFolder(const QString &name);
+void psFinish();
diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp
index 7fd4066fc..5600fac6a 100644
--- a/Telegram/SourceFiles/settings.cpp
+++ b/Telegram/SourceFiles/settings.cpp
@@ -68,8 +68,11 @@ QString gLangFile;
 bool gRetina = false;
 float64 gRetinaFactor = 1.;
 int32 gIntRetinaFactor = 1;
+#ifdef Q_OS_MAC
 bool gCustomNotifies = false;
-
+#else
+bool gCustomNotifies = true;
+#endif
 uint64 gInstance = 0.;
 
 #ifdef Q_OS_WIN
diff --git a/Telegram/SourceFiles/stdafx.cpp b/Telegram/SourceFiles/stdafx.cpp
index d1091c7e1..89dd13ec3 100644
--- a/Telegram/SourceFiles/stdafx.cpp
+++ b/Telegram/SourceFiles/stdafx.cpp
@@ -23,3 +23,6 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
 Q_IMPORT_PLUGIN(QWindowsAudioPlugin)
 Q_IMPORT_PLUGIN(AccessibleFactory)
 #endif
+#ifdef Q_OS_LINUX
+Q_IMPORT_PLUGIN(QPulseAudioPlugin)
+#endif
diff --git a/Telegram/SourceFiles/title.cpp b/Telegram/SourceFiles/title.cpp
index 03c61d304..42bb4f8af 100644
--- a/Telegram/SourceFiles/title.cpp
+++ b/Telegram/SourceFiles/title.cpp
@@ -77,7 +77,7 @@ TitleWidget::TitleWidget(Window *window)
 	connect(wnd->windowHandle(), SIGNAL(windowStateChanged(Qt::WindowState)), this, SLOT(stateChanged(Qt::WindowState)));
 	connect(App::app(), SIGNAL(updateReady()), this, SLOT(showUpdateBtn()));
         
-    if (cPlatform() == dbipMac) {
+    if (cPlatform() != dbipWindows) {
         _minimize.hide();
         _maximize.hide();
         _restore.hide();
@@ -127,7 +127,7 @@ TitleWidget::~TitleWidget() {
 void TitleWidget::resizeEvent(QResizeEvent *e) {
 	QPoint p(width() - ((cPlatform() == dbipWindows && lastMaximized) ? 0 : st::sysBtnDelta), 0);
 	
-    if (cPlatform() != dbipMac) {
+    if (cPlatform() == dbipWindows) {
         p.setX(p.x() - _close.width());
         _close.move(p);
         
diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp
index a08383dce..398c745f1 100644
--- a/Telegram/SourceFiles/types.cpp
+++ b/Telegram/SourceFiles/types.cpp
@@ -17,11 +17,10 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
 */
 #include "stdafx.h"
 
-#ifdef Q_OS_MAC
+#ifdef Q_OS_WIN
+#elif defined Q_OS_MAC
 #include <mach/mach_time.h>
-#endif
-
-#ifdef Q_OS_LINUX
+#else
 #include <time.h>
 #endif
 
@@ -175,8 +174,10 @@ namespace {
             _msStart = mach_absolute_time();
 #else
             timespec ts;
-            clock_gettime(CLOCK_REALTIME, &ts);
-            _msStart = 1000000000 * uint64(ts.tv_sec) + uint64(ts.tv_nsec);
+            clock_gettime(CLOCK_MONOTONIC, &ts);
+            //_msFreq = 1 / 1000000.;
+            _msgIdCoef = float64(0xFFFF0000L) / 1000000000.;
+            _msStart = 1000 * uint64(ts.tv_sec) + (uint64(ts.tv_nsec) / 1000000);
 #endif
 
 			srand((uint32)(_msStart & 0xFFFFFFFFL));
@@ -217,13 +218,13 @@ uint64 getms() {
    return (uint64)((msCount - _msStart) * _msFreq);
 #else
     timespec ts;
-    int res = clock_gettime(CLOCK_REALTIME, &ts);
+    int res = clock_gettime(CLOCK_MONOTONIC, &ts);
     if (res != 0) {
         LOG(("Bad clock_gettime result: %1").arg(res));
         return 0;
     }
-    uint64 msCount = 1000000000 * uint64(ts.tv_sec) + uint64(ts.tv_nsec);
-    return (uint64)((msCount - _msStart) / 1000000);
+    uint64 msCount = 1000 * uint64(ts.tv_sec) + (uint64(ts.tv_nsec) / 1000000);
+    return (uint64)(msCount - _msStart);
 #endif
 }
 
@@ -236,8 +237,10 @@ uint64 msgid() {
     uint64 msCount = mach_absolute_time();
     uint64 result = _msgIdStart + (uint64)floor((msCount - _msgIdMsStart) * _msgIdCoef);
 #else
-    uint64 result = 0;
-    //TODO
+    timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    uint64 msCount = 1000000000 * uint64(ts.tv_sec) + uint64(ts.tv_nsec);
+    uint64 result = _msgIdStart + (uint64)floor((msCount - _msgIdMsStart) * _msgIdCoef);
 #endif
 
 	result &= ~0x03L;
diff --git a/Telegram/Telegram.pro b/Telegram/Telegram.pro
index 1f9496cf2..ac47c805a 100644
--- a/Telegram/Telegram.pro
+++ b/Telegram/Telegram.pro
@@ -1,17 +1,19 @@
-QT += core gui widgets network multimedia
+QT += core gui network multimedia widgets
+
+CONFIG += plugin static
 
 CONFIG(debug, debug|release) {
     DEFINES += _DEBUG
-    OBJECTS_DIR = ./../Mac/DebugIntermediate
+    OBJECTS_DIR = ./../Linux/DebugIntermediate
     MOC_DIR = ./GeneratedFiles/Debug
     RCC_DIR = ./GeneratedFiles
-    DESTDIR = ./../Mac/Debug
+    DESTDIR = ./../Linux/Debug
 }
 CONFIG(release, debug|release) {
-    OBJECTS_DIR = ./../Mac/ReleaseIntermediate
+    OBJECTS_DIR = ./../Linux/ReleaseIntermediate
     MOC_DIR = ./GeneratedFiles/Release
     RCC_DIR = ./GeneratedFiles
-    DESTDIR = ./../Mac/Release
+    DESTDIR = ./../Linux/Release
 }
 
 macx {
@@ -21,6 +23,11 @@ macx {
     QMAKE_LFLAGS += -framework Cocoa
 }
 
+linux {
+    SOURCES += ./SourceFiles/pspecific_linux.cpp
+    HEADERS += ./SourceFiles/pspecific_linux.h
+}
+
 SOURCES += \
     ./SourceFiles/main.cpp \
     ./SourceFiles/stdafx.cpp \
@@ -180,17 +187,19 @@ CONFIG += precompile_header
 
 PRECOMPILED_HEADER = ./SourceFiles/stdafx.h
 
-INCLUDEPATH += ./../../Libraries/QtStatic/qtbase/include/QtGui/5.3.0/QtGui\
-               ./../../Libraries/QtStatic/qtbase/include/QtCore/5.3.0/QtCore\
+QMAKE_CXXFLAGS += -fno-strict-aliasing
+QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter -Wno-unused-variable -Wno-switch -Wno-comment -Wno-unused-but-set-variable
+
+INCLUDEPATH += ./../../Libraries/QtStatic/qtbase/include/QtGui/5.3.1/QtGui\
+               ./../../Libraries/QtStatic/qtbase/include/QtCore/5.3.1/QtCore\
                ./../../Libraries/QtStatic/qtbase/include\
                ./SourceFiles\
                ./GeneratedFiles\
-               ./../../Libraries/lzma/C\
-               ./../../Libraries/libexif-0.6.20
-
-LIBS += -lcrypto -lssl -lz
+               ./../../Libraries/libexif-0.6.20\
+               /usr/local/ssl/include
+LIBS += -L/usr/local/ssl/lib -lcrypto -lssl -lz -ldl -llzma
 LIBS += ./../../Libraries/libexif-0.6.20/libexif/.libs/libexif.a
-
+LIBS += ./../../Libraries/QtStatic/qtmultimedia/plugins/audio/libqtmedia_pulse.a
 RESOURCES += \
     ./SourceFiles/telegram.qrc
 
diff --git a/Telegram/_qt_5_3_1_patch/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/Telegram/_qt_5_3_1_patch/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
new file mode 100644
index 000000000..94c4c1d03
--- /dev/null
+++ b/Telegram/_qt_5_3_1_patch/qtbase/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbasicfontdatabase_p.h"
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformscreen.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QLibraryInfo>
+#include <QtCore/QDir>
+#include <QtCore/QUuid>
+#include <QtCore/QtEndian>
+
+#undef QT_NO_FREETYPE
+#include <QtGui/private/qfontengine_ft_p.h>
+#include <QtGui/private/qfontengine_p.h>
+
+#include <ft2build.h>
+#include FT_TRUETYPE_TABLES_H
+#include FT_ERRORS_H
+
+QT_BEGIN_NAMESPACE
+
+typedef struct {
+    quint16 majorVersion;
+    quint16 minorVersion;
+    quint16 numTables;
+    quint16 searchRange;
+    quint16 entrySelector;
+    quint16 rangeShift;
+} OFFSET_TABLE;
+
+typedef struct {
+    quint32 tag;
+    quint32 checkSum;
+    quint32 offset;
+    quint32 length;
+} TABLE_DIRECTORY;
+
+typedef struct {
+    quint16 fontSelector;
+    quint16 nrCount;
+    quint16 storageOffset;
+} NAME_TABLE_HEADER;
+
+typedef struct {
+    quint16 platformID;
+    quint16 encodingID;
+    quint16 languageID;
+    quint16 nameID;
+    quint16 stringLength;
+    quint16 stringOffset;
+} NAME_RECORD;
+
+void QBasicFontDatabase::populateFontDatabase()
+{
+    QString fontpath = fontDir();
+
+    if(!QFile::exists(fontpath)) {
+        qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
+               qPrintable(fontpath));
+    }
+
+    QDir dir(fontpath);
+    dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
+                       << QLatin1String("*.ttc") << QLatin1String("*.pfa")
+                       << QLatin1String("*.pfb")
+                       << QLatin1String("*.otf"));
+    dir.refresh();
+    for (int i = 0; i < int(dir.count()); ++i) {
+        const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+//        qDebug() << "looking at" << file;
+        addTTFile(QByteArray(), file);
+    }
+}
+
+QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr)
+{
+    FontFile *fontfile = static_cast<FontFile *> (usrPtr);
+    QFontEngine::FaceId fid;
+    fid.filename = QFile::encodeName(fontfile->fileName);
+    fid.index = fontfile->indexValue;
+
+    bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
+    QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
+
+    QFontEngineFT *engine = new QFontEngineFT(fontDef);
+    if (!engine->init(fid, antialias, format) || engine->invalid()) {
+        delete engine;
+        engine = 0;
+    }
+
+    return engine;
+}
+
+namespace {
+
+    class QFontEngineFTRawData: public QFontEngineFT
+    {
+    public:
+        QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef)
+        {
+        }
+
+        void updateFamilyNameAndStyle()
+        {
+            fontDef.family = QString::fromLatin1(freetype->face->family_name);
+
+            if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
+                fontDef.style = QFont::StyleItalic;
+
+            if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
+                fontDef.weight = QFont::Bold;
+        }
+
+        bool initFromData(const QByteArray &fontData)
+        {
+            FaceId faceId;
+            faceId.filename = "";
+            faceId.index = 0;
+            faceId.uuid = QUuid::createUuid().toByteArray();
+
+            return init(faceId, true, Format_None, fontData);
+        }
+    };
+
+}
+
+QFontEngine *QBasicFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
+                                                QFont::HintingPreference hintingPreference)
+{
+    QFontDef fontDef;
+    fontDef.pixelSize = pixelSize;
+    fontDef.hintingPreference = hintingPreference;
+
+    QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
+    if (!fe->initFromData(fontData)) {
+        delete fe;
+        return 0;
+    }
+
+    fe->updateFamilyNameAndStyle();
+
+    switch (hintingPreference) {
+    case QFont::PreferNoHinting:
+        fe->setDefaultHintStyle(QFontEngineFT::HintNone);
+        break;
+    case QFont::PreferFullHinting:
+        fe->setDefaultHintStyle(QFontEngineFT::HintFull);
+        break;
+    case QFont::PreferVerticalHinting:
+        fe->setDefaultHintStyle(QFontEngineFT::HintLight);
+        break;
+    default:
+        // Leave it as it is
+        break;
+    }
+
+    return fe;
+}
+
+QStringList QBasicFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
+{
+    Q_UNUSED(family);
+    Q_UNUSED(style);
+    Q_UNUSED(script);
+    Q_UNUSED(styleHint);
+    return QStringList();
+}
+
+QStringList QBasicFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
+{
+    return addTTFile(fontData,fileName.toLocal8Bit());
+}
+
+void QBasicFontDatabase::releaseHandle(void *handle)
+{
+    FontFile *file = static_cast<FontFile *>(handle);
+    delete file;
+}
+
+extern FT_Library qt_getFreetype();
+
+// copied from freetype with some modifications
+
+#ifndef FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY
+#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY FT_MAKE_TAG('i', 'g', 'p', 'f')
+#endif
+
+#ifndef FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY
+#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY FT_MAKE_TAG('i', 'g', 'p', 's')
+#endif
+
+/* there's a Mac-specific extended implementation of FT_New_Face() */
+/* in src/base/ftmac.c                                             */
+
+#if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
+
+/* documentation is in freetype.h */
+
+FT_Error __ft_New_Face(FT_Library library, const char* pathname, FT_Long face_index, FT_Face *aface) {
+  FT_Open_Args args;
+
+  /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+  if ( !pathname )
+    return FT_Err_Invalid_Argument;
+
+  FT_Parameter params[2];
+  params[0].tag   = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY;
+  params[0].data  = 0;
+  params[1].tag   = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY;
+  params[1].data  = 0;
+  args.flags      = FT_OPEN_PATHNAME | FT_OPEN_PARAMS;
+  args.pathname   = (char*)pathname;
+  args.stream     = NULL;
+  args.num_params = 2;
+  args.params     = params;
+
+  return FT_Open_Face( library, &args, face_index, aface );
+}
+
+#else
+
+FT_Error __ft_New_Face(FT_Library library, const char* pathname, FT_Long face_index, FT_Face *aface) {
+    return FT_New_Face(library, pathname, face_index, aface);
+}
+
+#endif  /* defined( FT_MACINTOSH ) && !defined( DARWIN_NO_CARBON ) */
+
+/* documentation is in freetype.h */
+
+FT_Error __ft_New_Memory_Face(FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface) {
+  FT_Open_Args  args;
+
+  /* test for valid `library' and `face' delayed to FT_Open_Face() */
+  if ( !file_base )
+    return FT_Err_Invalid_Argument;
+
+  FT_Parameter params[2];
+  params[0].tag    = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY;
+  params[0].data   = 0;
+  params[1].tag    = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY;
+  params[1].data   = 0;
+  args.flags       = FT_OPEN_MEMORY | FT_OPEN_PARAMS;
+  args.memory_base = file_base;
+  args.memory_size = file_size;
+  args.stream      = NULL;
+  args.num_params  = 2;
+  args.params      = params;
+
+  return FT_Open_Face( library, &args, face_index, aface );
+}
+
+// end
+
+QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file, QSupportedWritingSystems *supportedWritingSystems)
+{
+    FT_Library library = qt_getFreetype();
+
+    int index = 0;
+    int numFaces = 0;
+    QStringList families;
+    do {
+        FT_Face face;
+        FT_Error error;
+        if (!fontData.isEmpty()) {
+            error = __ft_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face);
+        } else {
+            error = __ft_New_Face(library, file.constData(), index, &face);
+        }
+        if (error != FT_Err_Ok) {
+            qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error;
+            break;
+        }
+        numFaces = face->num_faces;
+
+        QFont::Weight weight = QFont::Normal;
+
+        QFont::Style style = QFont::StyleNormal;
+        if (face->style_flags & FT_STYLE_FLAG_ITALIC)
+            style = QFont::StyleItalic;
+
+        if (face->style_flags & FT_STYLE_FLAG_BOLD)
+            weight = QFont::Bold;
+
+        bool fixedPitch = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
+
+        QSupportedWritingSystems writingSystems;
+        // detect symbol fonts
+        for (int i = 0; i < face->num_charmaps; ++i) {
+            FT_CharMap cm = face->charmaps[i];
+            if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM
+                    || cm->encoding == FT_ENCODING_MS_SYMBOL) {
+                writingSystems.setSupported(QFontDatabase::Symbol);
+                if (supportedWritingSystems)
+                    supportedWritingSystems->setSupported(QFontDatabase::Symbol);
+                break;
+            }
+        }
+
+        TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+        if (os2) {
+            quint32 unicodeRange[4] = {
+                quint32(os2->ulUnicodeRange1),
+                quint32(os2->ulUnicodeRange2),
+                quint32(os2->ulUnicodeRange3),
+                quint32(os2->ulUnicodeRange4)
+            };
+            quint32 codePageRange[2] = {
+                quint32(os2->ulCodePageRange1),
+                quint32(os2->ulCodePageRange2)
+            };
+
+            writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+            if (supportedWritingSystems)
+                *supportedWritingSystems = writingSystems;
+
+            if (os2->usWeightClass == 0)
+                ;
+            else if (os2->usWeightClass < 350)
+                weight = QFont::Light;
+            else if (os2->usWeightClass < 450)
+                weight = QFont::Normal;
+            else if (os2->usWeightClass < 650)
+                weight = QFont::DemiBold;
+            else if (os2->usWeightClass < 750)
+                weight = QFont::Bold;
+            else if (os2->usWeightClass < 1000)
+                weight = QFont::Black;
+
+            if (os2->panose[2] >= 2) {
+                int w = os2->panose[2];
+                if (w <= 3)
+                    weight = QFont::Light;
+                else if (w <= 5)
+                    weight = QFont::Normal;
+                else if (w <= 7)
+                    weight = QFont::DemiBold;
+                else if (w <= 8)
+                    weight = QFont::Bold;
+                else if (w <= 10)
+                    weight = QFont::Black;
+            }
+        }
+
+        QString family = QString::fromLatin1(face->family_name);
+        FontFile *fontFile = new FontFile;
+        fontFile->fileName = QFile::decodeName(file);
+        fontFile->indexValue = index;
+
+        QFont::Stretch stretch = QFont::Unstretched;
+
+        registerFont(family,QString::fromLatin1(face->style_name),QString(),weight,style,stretch,true,true,0,fixedPitch,writingSystems,fontFile);
+
+        families.append(family);
+
+        FT_Done_Face(face);
+        ++index;
+    } while (index < numFaces);
+    return families;
+}
+
+QString QBasicFontDatabase::fontNameFromTTFile(const QString &filename)
+{
+    QFile f(filename);
+    QString retVal;
+    qint64 bytesRead;
+    qint64 bytesToRead;
+
+    if (f.open(QIODevice::ReadOnly)) {
+        OFFSET_TABLE ttOffsetTable;
+        bytesToRead = sizeof(OFFSET_TABLE);
+        bytesRead = f.read((char*)&ttOffsetTable, bytesToRead);
+        if (bytesToRead != bytesRead)
+            return retVal;
+        ttOffsetTable.numTables = qFromBigEndian(ttOffsetTable.numTables);
+        ttOffsetTable.majorVersion = qFromBigEndian(ttOffsetTable.majorVersion);
+        ttOffsetTable.minorVersion = qFromBigEndian(ttOffsetTable.minorVersion);
+
+        if (ttOffsetTable.majorVersion != 1 || ttOffsetTable.minorVersion != 0)
+            return retVal;
+
+        TABLE_DIRECTORY tblDir;
+        bool found = false;
+
+        for (int i = 0; i < ttOffsetTable.numTables; i++) {
+            bytesToRead = sizeof(TABLE_DIRECTORY);
+            bytesRead = f.read((char*)&tblDir, bytesToRead);
+            if (bytesToRead != bytesRead)
+                return retVal;
+            if (qFromBigEndian(tblDir.tag) == MAKE_TAG('n', 'a', 'm', 'e')) {
+                found = true;
+                tblDir.length = qFromBigEndian(tblDir.length);
+                tblDir.offset = qFromBigEndian(tblDir.offset);
+                break;
+            }
+        }
+
+        if (found) {
+            f.seek(tblDir.offset);
+            NAME_TABLE_HEADER ttNTHeader;
+            bytesToRead = sizeof(NAME_TABLE_HEADER);
+            bytesRead = f.read((char*)&ttNTHeader, bytesToRead);
+            if (bytesToRead != bytesRead)
+                return retVal;
+            ttNTHeader.nrCount = qFromBigEndian(ttNTHeader.nrCount);
+            ttNTHeader.storageOffset = qFromBigEndian(ttNTHeader.storageOffset);
+            NAME_RECORD ttRecord;
+            found = false;
+
+            for (int i = 0; i < ttNTHeader.nrCount; i++) {
+                bytesToRead = sizeof(NAME_RECORD);
+                bytesRead = f.read((char*)&ttRecord, bytesToRead);
+                if (bytesToRead != bytesRead)
+                    return retVal;
+                ttRecord.nameID = qFromBigEndian(ttRecord.nameID);
+                if (ttRecord.nameID == 1) {
+                    ttRecord.stringLength = qFromBigEndian(ttRecord.stringLength);
+                    ttRecord.stringOffset = qFromBigEndian(ttRecord.stringOffset);
+                    int nPos = f.pos();
+                    f.seek(tblDir.offset + ttRecord.stringOffset + ttNTHeader.storageOffset);
+
+                    QByteArray nameByteArray = f.read(ttRecord.stringLength);
+                    if (!nameByteArray.isEmpty()) {
+                        if (ttRecord.encodingID == 256 || ttRecord.encodingID == 768) {
+                            //This is UTF-16 in big endian
+                            int stringLength = ttRecord.stringLength / 2;
+                            retVal.resize(stringLength);
+                            QChar *data = retVal.data();
+                            const ushort *srcData = (const ushort *)nameByteArray.data();
+                            for (int i = 0; i < stringLength; ++i)
+                                data[i] = qFromBigEndian(srcData[i]);
+                            return retVal;
+                        } else if (ttRecord.encodingID == 0) {
+                            //This is Latin1
+                            retVal = QString::fromLatin1(nameByteArray);
+                        } else {
+                            qWarning("Could not retrieve Font name from file: %s", qPrintable(QDir::toNativeSeparators(filename)));
+                        }
+                        break;
+                    }
+                    f.seek(nPos);
+                }
+            }
+        }
+        f.close();
+    }
+    return retVal;
+}
+
+QT_END_NAMESPACE
diff --git a/Telegram/telegram_plugin_import.cpp b/Telegram/telegram_plugin_import.cpp
index 33b4b9aa5..8e9103300 100644
--- a/Telegram/telegram_plugin_import.cpp
+++ b/Telegram/telegram_plugin_import.cpp
@@ -1,16 +1,11 @@
 // This file is autogenerated by qmake. It imports static plugin classes for
 // static plugins specified using QTPLUGIN and QT_PLUGIN_CLASS.<plugin> variables.
 #include <QtPlugin>
-//Q_IMPORT_PLUGIN(AVFServicePlugin)
-Q_IMPORT_PLUGIN(AVFMediaPlayerServicePlugin)
-Q_IMPORT_PLUGIN(QT7ServicePlugin)
 Q_IMPORT_PLUGIN(AudioCaptureServicePlugin)
-Q_IMPORT_PLUGIN(CoreAudioPlugin)
 Q_IMPORT_PLUGIN(QM3uPlaylistPlugin)
 Q_IMPORT_PLUGIN(AccessibleFactory)
-Q_IMPORT_PLUGIN(QCoreWlanEnginePlugin)
 Q_IMPORT_PLUGIN(QGenericEnginePlugin)
-Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
+Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
 Q_IMPORT_PLUGIN(QDDSPlugin)
 Q_IMPORT_PLUGIN(QICNSPlugin)
 Q_IMPORT_PLUGIN(QICOPlugin)