diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp
index 21ab5d2af..03ba4065d 100644
--- a/Telegram/SourceFiles/facades.cpp
+++ b/Telegram/SourceFiles/facades.cpp
@@ -276,7 +276,7 @@ bool hideWindowNoQuit() {
 			if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
 				return w->minimizeToTray();
 			} else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
-				w->hide();
+				w->closeWithoutDestroy();
 				w->updateIsActive(Global::OfflineBlurTimeout());
 				w->updateGlobalMenu();
 				return true;
diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp
index aa0e4d4bf..c4952508e 100644
--- a/Telegram/SourceFiles/mainwindow.cpp
+++ b/Telegram/SourceFiles/mainwindow.cpp
@@ -417,7 +417,9 @@ void MainWindow::onInactiveTimer() {
 	inactivePress(false);
 }
 
-void MainWindow::stateChanged(Qt::WindowState state) {
+void MainWindow::onStateChanged(Qt::WindowState state) {
+	stateChangedHook(state);
+
 	psUserActionDone();
 
 	updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout());
@@ -1069,7 +1071,7 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *e) {
 	case QEvent::WindowStateChange:
 		if (obj == this) {
 			Qt::WindowState state = (windowState() & Qt::WindowMinimized) ? Qt::WindowMinimized : ((windowState() & Qt::WindowMaximized) ? Qt::WindowMaximized : ((windowState() & Qt::WindowFullScreen) ? Qt::WindowFullScreen : Qt::WindowNoState));
-			stateChanged(state);
+			onStateChanged(state);
 		}
 		break;
 
@@ -1107,7 +1109,7 @@ void MainWindow::mouseReleaseEvent(QMouseEvent *e) {
 bool MainWindow::minimizeToTray() {
     if (App::quitting() || !psHasTrayIcon()) return false;
 
-	hide();
+	closeWithoutDestroy();
     if (cPlatform() == dbipWindows && trayIcon && !cSeenTrayTooltip()) {
 		trayIcon->showMessage(str_const_toString(AppName), lang(lng_tray_icon_text), QSystemTrayIcon::Information, 10000);
 		cSetSeenTrayTooltip(true);
diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h
index a599bf061..5a7826c61 100644
--- a/Telegram/SourceFiles/mainwindow.h
+++ b/Telegram/SourceFiles/mainwindow.h
@@ -249,9 +249,7 @@ public:
 	PeerData *ui_getPeerForMouseAction();
 
 public slots:
-
 	void updateIsActive(int timeout = 0);
-	void stateChanged(Qt::WindowState state);
 
 	void checkHistoryActivation();
 
@@ -289,7 +287,6 @@ public slots:
 	void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
 
 signals:
-
 	void resized(const QSize &size);
 	void tempDirCleared(int task);
 	void tempDirClearFailed(int task);
@@ -297,6 +294,9 @@ signals:
 
 	void imageLoaded();
 
+private slots:
+	void onStateChanged(Qt::WindowState state);
+
 private:
 
 	QPixmap grabInner();
diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h
index a2fe866c1..2bbe76dc4 100644
--- a/Telegram/SourceFiles/platform/mac/main_window_mac.h
+++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h
@@ -75,7 +75,7 @@ public:
 	void psNotifyShown(NotifyWindow *w);
 	void psPlatformNotify(HistoryItem *item, int32 fwdCount);
 
-	bool eventFilter(QObject *obj, QEvent *evt);
+	bool eventFilter(QObject *obj, QEvent *evt) override;
 
 	void psUpdateCounter();
 
@@ -85,10 +85,11 @@ public:
 
 	virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
 
+	void closeWithoutDestroy() override;
+
 	~MainWindow();
 
 public slots:
-
 	void psUpdateDelegate();
 	void psSavePosition(Qt::WindowState state = Qt::WindowActive);
 	void psShowTrayMenu();
@@ -101,9 +102,12 @@ public slots:
 	void psMacDelete();
 	void psMacSelectAll();
 
-protected:
+private slots:
+	void onHideAfterFullScreen();
+
+protected:
+	void stateChangedHook(Qt::WindowState state) override;
 
-	void psNotIdle() const;
 	QImage psTrayIcon(bool selected = false) const;
 	bool psHasTrayIcon() const {
 		return trayIcon;
@@ -112,8 +116,8 @@ protected:
 	void psMacUpdateMenu();
 
 	bool posInited;
-	QSystemTrayIcon *trayIcon;
-	QMenu *trayIconMenu;
+	QSystemTrayIcon *trayIcon = nullptr;
+	QMenu *trayIconMenu = nullptr;
 	QImage icon256, iconbig256;
 	QIcon wndIcon;
 
@@ -126,14 +130,27 @@ protected:
 	QTimer psUpdatedPositionTimer;
 
 private:
-	struct PrivateData;
-	std_::unique_ptr<PrivateData> _private;
+	MacPrivate _private;
 
 	mutable bool psIdle;
 	mutable QTimer psIdleTimer;
 
+	QTimer _hideAfterFullScreenTimer;
+
 	QMenuBar psMainMenu;
-	QAction *psLogout, *psUndo, *psRedo, *psCut, *psCopy, *psPaste, *psDelete, *psSelectAll, *psContacts, *psAddContact, *psNewGroup, *psNewChannel, *psShowTelegram;
+	QAction *psLogout = nullptr;
+	QAction *psUndo = nullptr;
+	QAction *psRedo = nullptr;
+	QAction *psCut = nullptr;
+	QAction *psCopy = nullptr;
+	QAction *psPaste = nullptr;
+	QAction *psDelete = nullptr;
+	QAction *psSelectAll = nullptr;
+	QAction *psContacts = nullptr;
+	QAction *psAddContact = nullptr;
+	QAction *psNewGroup = nullptr;
+	QAction *psNewChannel = nullptr;
+	QAction *psShowTelegram = nullptr;
 
 };
 
diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm
index 3dc9e5ee1..d493c9cf7 100644
--- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm
+++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm
@@ -16,12 +16,14 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
 Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 */
 #include "stdafx.h"
-#include "pspecific_mac_p.h"
+#include "platform/mac/main_window_mac.h"
 
 #include "mainwindow.h"
 #include "mainwidget.h"
 #include "application.h"
 #include "playerwidget.h"
+#include "historywidget.h"
+#include "localstorage.h"
 
 #include "lang.h"
 
@@ -31,1080 +33,478 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 
 #include <IOKit/hidsystem/ev_keymap.h>
 
-@interface qVisualize : NSObject {
-}
+namespace Platform {
 
-+ (id)str:(const QString &)str;
-- (id)initWithString:(const QString &)str;
-
-+ (id)bytearr:(const QByteArray &)arr;
-- (id)initWithByteArray:(const QByteArray &)arr;
-
-- (id)debugQuickLookObject;
-
-@end
-
-@implementation qVisualize {
-	NSString *value;
-}
-
-+ (id)bytearr:(const QByteArray &)arr {
-	return [[qVisualize alloc] initWithByteArray:arr];
-}
-- (id)initWithByteArray:(const QByteArray &)arr {
-	if (self = [super init]) {
-		value = [NSString stringWithUTF8String:arr.constData()];
-	}
-	return self;
-}
-
-+ (id)str:(const QString &)str {
-	return [[qVisualize alloc] initWithString:str];
-}
-- (id)initWithString:(const QString &)str {
-	if (self = [super init]) {
-		value = [NSString stringWithUTF8String:str.toUtf8().constData()];
-	}
-	return self;
-}
-
-- (id)debugQuickLookObject {
-	return value;
-}
-
-@end
-
-@interface ApplicationDelegate : NSObject<NSApplicationDelegate> {
-}
-
-- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag;
-- (void)applicationDidBecomeActive:(NSNotification *)aNotification;
-- (void)receiveWakeNote:(NSNotification*)note;
-
-@end
-
-ApplicationDelegate *_sharedDelegate = nil;
-
-@implementation ApplicationDelegate {
-}
-
-- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
-	if (App::wnd() && App::wnd()->isHidden()) App::wnd()->showFromTray();
-	return YES;
-}
-
-- (void)applicationDidBecomeActive:(NSNotification *)aNotification {
-	if (App::app()) App::app()->checkLocalTime();
-}
-
-- (void)receiveWakeNote:(NSNotification*)aNotification {
-	if (App::app()) App::app()->checkLocalTime();
-}
-
-@end
-
-class QNSString {
-public:
-    QNSString(const QString &str) : _str([NSString stringWithUTF8String:str.toUtf8().constData()]) {
-    }
-    NSString *s() {
-        return _str;
-    }
-private:
-    NSString *_str;
-};
-
-QNSString objc_lang(LangKey key) {
-	return QNSString(lang(key));
-}
-QString objcString(NSString *str) {
-	return QString::fromUtf8([str cStringUsingEncoding:NSUTF8StringEncoding]);
-}
-
-@interface ObserverHelper : NSObject {
-}
-
-- (id) init:(PsMacWindowPrivate *)aWnd;
-- (void) activeSpaceDidChange:(NSNotification *)aNotification;
-- (void) darkModeChanged:(NSNotification *)aNotification;
-
-@end
-
-@interface NotifyHandler : NSObject<NSUserNotificationCenterDelegate> {
-}
-
-- (id) init:(PsMacWindowPrivate *)aWnd;
-
-- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
-
-- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
-
-@end
-
-class PsMacWindowData {
-public:
-
-    PsMacWindowData(PsMacWindowPrivate *wnd) :
-    wnd(wnd),
-    observerHelper([[ObserverHelper alloc] init:wnd]),
-    notifyHandler([[NotifyHandler alloc] init:wnd]) {
-    }
-
-    void onNotifyClick(NSUserNotification *notification) {
-		NSDictionary *dict = [notification userInfo];
-		NSNumber *peerObj = [dict objectForKey:@"peer"], *msgObj = [dict objectForKey:@"msgid"];
-		unsigned long long peerLong = peerObj ? [peerObj unsignedLongLongValue] : 0;
-		int msgId = msgObj ? [msgObj intValue] : 0;
-        wnd->notifyClicked(peerLong, msgId);
-    }
-
-    void onNotifyReply(NSUserNotification *notification) {
-		NSDictionary *dict = [notification userInfo];
-		NSNumber *peerObj = [dict objectForKey:@"peer"], *msgObj = [dict objectForKey:@"msgid"];
-		unsigned long long peerLong = peerObj ? [peerObj unsignedLongLongValue] : 0;
-		int msgId = msgObj ? [msgObj intValue] : 0;
-        wnd->notifyReplied(peerLong, msgId, [[[notification response] string] UTF8String]);
-    }
-
-    ~PsMacWindowData() {
-        [observerHelper release];
-        [notifyHandler release];
-    }
-
-    PsMacWindowPrivate *wnd;
-    ObserverHelper *observerHelper;
-    NotifyHandler *notifyHandler;
-};
-
-@implementation ObserverHelper {
-    PsMacWindowPrivate *wnd;
-}
-
-- (id) init:(PsMacWindowPrivate *)aWnd {
-    if (self = [super init]) {
-        wnd = aWnd;
-    }
-    return self;
-}
-
-- (void) activeSpaceDidChange:(NSNotification *)aNotification {
-    wnd->activeSpaceChanged();
-}
-
-- (void) darkModeChanged:(NSNotification *)aNotification {
-	wnd->darkModeChanged();
-}
-
-@end
-
-@implementation NotifyHandler {
-    PsMacWindowPrivate *wnd;
-}
-
-- (id) init:(PsMacWindowPrivate *)aWnd {
-    if (self = [super init]) {
-        wnd = aWnd;
-    }
-    return self;
-}
-
-- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
-    NSNumber *instObj = [[notification userInfo] objectForKey:@"launch"];
-	unsigned long long instLong = instObj ? [instObj unsignedLongLongValue] : 0;
-	DEBUG_LOG(("Received notification with instance %1").arg(instLong));
-	if (instLong != Global::LaunchId()) { // other app instance notification
-        return;
-    }
-    if (notification.activationType == NSUserNotificationActivationTypeReplied) {
-        wnd->data->onNotifyReply(notification);
-    } else if (notification.activationType == NSUserNotificationActivationTypeContentsClicked) {
-        wnd->data->onNotifyClick(notification);
-    }
-    [center removeDeliveredNotification: notification];
-}
-
-- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
-    return YES;
-}
-
-@end
-
-PsMacWindowPrivate::PsMacWindowPrivate() : data(new PsMacWindowData(this)) {
-    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:data->observerHelper selector:@selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
-	[[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(darkModeChanged:) name:QNSString(strNotificationAboutThemeChange()).s() object:nil];
-}
-
-void PsMacWindowPrivate::setWindowBadge(const QString &str) {
-    [[NSApp dockTile] setBadgeLabel:QNSString(str).s()];
-}
-
-void PsMacWindowPrivate::startBounce() {
-    [NSApp requestUserAttention:NSInformationalRequest];
-}
-
-void PsMacWindowPrivate::updateDelegate() {
-    NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
-    [center setDelegate:data->notifyHandler];
-}
-
-void objc_holdOnTop(WId winId) {
-    NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
-    [wnd setHidesOnDeactivate:NO];
-}
-
-bool objc_darkMode() {
-	NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
-	id style = [dict objectForKey:QNSString(strStyleOfInterface()).s()];
-	BOOL darkModeOn = ( style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"] );
-	return darkModeOn ? true : false;
-}
-
-void objc_showOverAll(WId winId, bool canFocus) {
-    NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
-	[wnd setLevel:NSPopUpMenuWindowLevel];
-	if (!canFocus) {
-		[wnd setStyleMask:NSUtilityWindowMask | NSNonactivatingPanelMask];
-		[wnd setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace|NSWindowCollectionBehaviorStationary|NSWindowCollectionBehaviorFullScreenAuxiliary|NSWindowCollectionBehaviorIgnoresCycle];
+void MacPrivate::activeSpaceChanged() {
+	if (App::wnd()) {
+		App::wnd()->notifyActivateAll();
 	}
 }
 
-void objc_bringToBack(WId winId) {
-	NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
-	[wnd setLevel:NSModalPanelWindowLevel];
+void MacPrivate::darkModeChanged() {
+	Notify::unreadCounterUpdated();
 }
 
-void objc_activateWnd(WId winId) {
-    NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
-    [wnd orderFront:wnd];
-}
+void MacPrivate::notifyClicked(unsigned long long peer, int msgid) {
+	History *history = App::history(PeerId(peer));
 
-NSImage *qt_mac_create_nsimage(const QPixmap &pm);
-
-void PsMacWindowPrivate::showNotify(uint64 peer, int32 msgId, const QPixmap &pix, const QString &title, const QString &subtitle, const QString &msg, bool withReply) {
-    NSUserNotification *notification = [[NSUserNotification alloc] init];
-	NSImage *img = qt_mac_create_nsimage(pix);
-
-	DEBUG_LOG(("Sending notification with userinfo: peer %1, msgId %2 and instance %3").arg(peer).arg(msgId).arg(Global::LaunchId()));
-    [notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:Global::LaunchId()],@"launch",nil]];
-
-	[notification setTitle:QNSString(title).s()];
-    [notification setSubtitle:QNSString(subtitle).s()];
-    [notification setInformativeText:QNSString(msg).s()];
-	if ([notification respondsToSelector:@selector(setContentImage:)]) {
-		[notification setContentImage:img];
-	}
-
-	if (withReply && [notification respondsToSelector:@selector(setHasReplyButton:)]) {
-		[notification setHasReplyButton:YES];
-	}
-
-    [notification setSoundName:nil];
-
-    NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
-    [center deliverNotification:notification];
-
-	if (img) [img release];
-    [notification release];
-}
-
-void PsMacWindowPrivate::enableShadow(WId winId) {
-//    [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
-//    [[(NSView*)winId window] setHasShadow:YES];
-}
-
-bool PsMacWindowPrivate::filterNativeEvent(void *event) {
-	NSEvent *e = static_cast<NSEvent*>(event);
-	if (e && [e type] == NSSystemDefined && [e subtype] == 8) {
-		int keyCode = (([e data1] & 0xFFFF0000) >> 16);
-		int keyFlags = ([e data1] & 0x0000FFFF);
-		int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
-		int keyRepeat = (keyFlags & 0x1);
-
-		switch (keyCode) {
-		case NX_KEYTYPE_PLAY:
-			if (keyState == 0) { // Play pressed and released
-				if (App::main()) App::main()->player()->playPausePressed();
-				return true;
-			}
-			break;
-
-		case NX_KEYTYPE_FAST:
-			if (keyState == 0) { // Next pressed and released
-				if (App::main()) App::main()->player()->nextPressed();
-				return true;
-			}
-			break;
-
-		case NX_KEYTYPE_REWIND:
-			if (keyState == 0) { // Previous pressed and released
-				if (App::main()) App::main()->player()->prevPressed();
-				return true;
-			}
-			break;
-		}
-	}
-	return false;
-}
-
-
-void PsMacWindowPrivate::clearNotifies(unsigned long long peer) {
-    NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
-    if (peer) {
-        NSArray *notifies = [center deliveredNotifications];
-        for (id notify in notifies) {
-			NSDictionary *dict = [notify userInfo];
-			if ([[dict objectForKey:@"peer"] unsignedLongLongValue] == peer && [[dict objectForKey:@"launch"] unsignedLongLongValue] == Global::LaunchId()) {
-                [center removeDeliveredNotification:notify];
-            }
-        }
-    } else {
-        [center removeAllDeliveredNotifications];
-    }
-}
-
-void objc_debugShowAlert(const QString &str) {
-    [[NSAlert alertWithMessageText:@"Debug Message" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", QNSString(str).s()] runModal];
-}
-
-void objc_outputDebugString(const QString &str) {
-    NSLog(@"%@", QNSString(str).s());
-}
-
-PsMacWindowPrivate::~PsMacWindowPrivate() {
-    delete data;
-}
-
-bool objc_idleSupported() {
-	int64 idleTime = 0;
-	return objc_idleTime(idleTime);
-}
-
-bool objc_idleTime(int64 &idleTime) { // taken from https://github.com/trueinteractions/tint/issues/53
-    CFMutableDictionaryRef properties = 0;
-    CFTypeRef obj;
-    mach_port_t masterPort;
-    io_iterator_t iter;
-    io_registry_entry_t curObj;
-
-    IOMasterPort(MACH_PORT_NULL, &masterPort);
-
-    /* Get IOHIDSystem */
-    IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOHIDSystem"), &iter);
-    if (iter == 0) {
-        return false;
-    } else {
-        curObj = IOIteratorNext(iter);
-    }
-    if (IORegistryEntryCreateCFProperties(curObj, &properties, kCFAllocatorDefault, 0) == KERN_SUCCESS && properties != NULL) {
-        obj = CFDictionaryGetValue(properties, CFSTR("HIDIdleTime"));
-        CFRetain(obj);
-    } else {
-        return false;
-    }
-
-    uint64 err = ~0L, result = err;
-    if (obj) {
-        CFTypeID type = CFGetTypeID(obj);
-
-        if (type == CFDataGetTypeID()) {
-            CFDataGetBytes((CFDataRef) obj, CFRangeMake(0, sizeof(result)), (UInt8*)&result);
-        } else if (type == CFNumberGetTypeID()) {
-            CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt64Type, &result);
-        } else {
-            // error
-        }
-
-        CFRelease(obj);
-
-        if (result != err) {
-            result /= 1000000; // return as ms
-        }
-    } else {
-        // error
-    }
-
-    CFRelease((CFTypeRef)properties);
-    IOObjectRelease(curObj);
-    IOObjectRelease(iter);
-	if (result == err) return false;
-
-	idleTime = int64(result);
-	return true;
-}
-
-@interface OpenWithApp : NSObject {
-	NSString *fullname;
-	NSURL *app;
-	NSImage *icon;
-}
-@property (nonatomic, retain) NSString *fullname;
-@property (nonatomic, retain) NSURL *app;
-@property (nonatomic, retain) NSImage *icon;
-@end
-
-@implementation OpenWithApp
-@synthesize fullname, app, icon;
-
-- (void) dealloc {
-	[fullname release];
-	[app release];
-	[icon release];
-	[super dealloc];
-}
-
-@end
-
-@interface OpenFileWithInterface : NSObject {
-}
-
-- (id) init:(NSString *)file;
-- (BOOL) popupAtX:(int)x andY:(int)y;
-- (void) itemChosen:(id)sender;
-- (void) dealloc;
-
-@end
-
-@implementation OpenFileWithInterface {
-	NSString *toOpen;
-
-	NSURL *defUrl;
-	NSString *defBundle, *defName, *defVersion;
-	NSImage *defIcon;
-
-	NSMutableArray *apps;
-
-	NSMenu *menu;
-}
-
-- (void) fillAppByUrl:(NSURL*)url bundle:(NSString**)bundle name:(NSString**)name version:(NSString**)version icon:(NSImage**)icon {
-	NSBundle *b = [NSBundle bundleWithURL:url];
-	if (b) {
-		NSString *path = [url path];
-		*name = [[NSFileManager defaultManager] displayNameAtPath: path];
-		if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleDisplayName"];
-		if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleName"];
-		if (*name) {
-			*bundle = [b bundleIdentifier];
-			if (bundle) {
-				*version = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
-				*icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
-				if (*icon && [*icon isValid]) [*icon setSize: CGSizeMake(16., 16.)];
-				return;
-			}
-		}
-	}
-	*bundle = *name = *version = nil;
-	*icon = nil;
-}
-
-- (id) init:(NSString*)file {
-	toOpen = file;
-	if (self = [super init]) {
-		NSURL *url = [NSURL fileURLWithPath:file];
-		defUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:url];
-		if (defUrl) {
-			[self fillAppByUrl:defUrl bundle:&defBundle name:&defName version:&defVersion icon:&defIcon];
-			if (!defBundle || !defName) {
-				defUrl = nil;
-			}
-		}
-		NSArray *appsList = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
-		NSMutableDictionary *data = [NSMutableDictionary dictionaryWithCapacity:16];
-		int fullcount = 0;
-		for (id app in appsList) {
-			if (fullcount > 15) break;
-
-			NSString *bundle = nil, *name = nil, *version = nil;
-			NSImage *icon = nil;
-			[self fillAppByUrl:(NSURL*)app bundle:&bundle name:&name version:&version icon:&icon];
-			if (bundle && name) {
-				if ([bundle isEqualToString:defBundle] && [version isEqualToString:defVersion]) continue;
-				NSString *key = [[NSArray arrayWithObjects:bundle, name, nil] componentsJoinedByString:@"|"];
-				if (!version) version = @"";
-
-				NSMutableDictionary *versions = (NSMutableDictionary*)[data objectForKey:key];
-				if (!versions) {
-					versions = [NSMutableDictionary dictionaryWithCapacity:2];
-					[data setValue:versions forKey:key];
-				}
-				if (![versions objectForKey:version]) {
-					[versions setValue:[NSArray arrayWithObjects:name, icon, app, nil] forKey:version];
-					++fullcount;
-				}
-			}
-		}
-		if (fullcount || defUrl) {
-			apps = [NSMutableArray arrayWithCapacity:fullcount];
-			for (id key in data) {
-				NSMutableDictionary *val = (NSMutableDictionary*)[data objectForKey:key];
-				for (id ver in val) {
-					NSArray *app = (NSArray*)[val objectForKey:ver];
-					OpenWithApp *a = [[OpenWithApp alloc] init];
-					NSString *fullname = (NSString*)[app objectAtIndex:0], *version = (NSString*)ver;
-					BOOL showVersion = ([val count] > 1);
-					if (!showVersion) {
-						NSError *error = NULL;
-						NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$" options:NSRegularExpressionCaseInsensitive error:&error];
-						showVersion = ![regex numberOfMatchesInString:version options:NSMatchingWithoutAnchoringBounds range:{0,[version length]}];
-					}
-					if (showVersion) fullname = [[NSArray arrayWithObjects:fullname, @" (", version, @")", nil] componentsJoinedByString:@""];
-					[a setFullname:fullname];
-					[a setIcon:(NSImage*)[app objectAtIndex:1]];
-					[a setApp:(NSURL*)[app objectAtIndex:2]];
-					[apps addObject:a];
-					[a release];
-				}
-			}
-		}
-		[apps sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"fullname" ascending:YES]]];
-		[appsList release];
-		menu = nil;
-	}
-	return self;
-}
-
-- (BOOL) popupAtX:(int)x andY:(int)y {
-	if (![apps count] && !defName) return NO;
-	menu = [[NSMenu alloc] initWithTitle:@"Open With"];
-
-	int index = 0;
-	if (defName) {
-		NSMenuItem *item = [menu insertItemWithTitle:[[NSArray arrayWithObjects:defName, @" (default)", nil] componentsJoinedByString:@""] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
-		if (defIcon) [item setImage:defIcon];
-		[item setTarget:self];
-		[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
-	}
-	if ([apps count]) {
-		for (id a in apps) {
-			OpenWithApp *app = (OpenWithApp*)a;
-			NSMenuItem *item = [menu insertItemWithTitle:[a fullname] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
-			if ([app icon]) [item setImage:[app icon]];
-			[item setTarget:self];
-		}
-		[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
-	}
-	NSMenuItem *item = [menu insertItemWithTitle:objc_lang(lng_mac_choose_program_menu).s() action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
-	[item setTarget:self];
-
-	[menu popUpMenuPositioningItem:nil atLocation:CGPointMake(x, y) inView:nil];
-
-	return YES;
-}
-
-- (void) itemChosen:(id)sender {
-	NSArray *items = [menu itemArray];
-	NSURL *url = nil;
-	for (int i = 0, l = [items count]; i < l; ++i) {
-		if ([items objectAtIndex:i] == sender) {
-			if (defName) i -= 2;
-			if (i < 0) {
-				url = defUrl;
-			} else if (i < int([apps count])) {
-				url = [(OpenWithApp*)[apps objectAtIndex:i] app];
-			}
-			break;
-		}
-	}
-	if (url) {
-		[[NSWorkspace sharedWorkspace] openFile:toOpen withApplication:[url path]];
+	App::wnd()->showFromTray();
+	if (App::passcoded()) {
+		App::wnd()->setInnerFocus();
+		App::wnd()->notifyClear();
 	} else {
-		objc_openFile(objcString(toOpen), true);
+		App::wnd()->hideSettings();
+		bool tomsg = !history->peer->isUser() && (msgid > 0);
+		if (tomsg) {
+			HistoryItem *item = App::histItemById(peerToChannel(PeerId(peer)), MsgId(msgid));
+			if (!item || !item->mentionsMe()) {
+				tomsg = false;
+			}
+		}
+		Ui::showPeerHistory(history, tomsg ? msgid : ShowAtUnreadMsgId);
+		App::wnd()->notifyClear(history);
 	}
 }
 
-- (void) dealloc {
-	if (apps) [apps release];
-	[super dealloc];
-	if (menu) [menu release];
+void MacPrivate::notifyReplied(unsigned long long peer, int msgid, const char *str) {
+	History *history = App::history(PeerId(peer));
+
+	MainWidget::MessageToSend message;
+	message.history = history;
+	message.textWithTags = { QString::fromUtf8(str), TextWithTags::Tags() };
+	message.replyTo = (msgid > 0 && !history->peer->isUser()) ? msgid : 0;
+	message.silent = false;
+	message.clearDraft = false;
+	App::main()->sendMessage(message);
 }
 
-@end
+MainWindow::MainWindow()
+: posInited(false)
+, icon256(qsl(":/gui/art/icon256.png"))
+, iconbig256(qsl(":/gui/art/iconbig256.png"))
+, wndIcon(QPixmap::fromImage(iconbig256, Qt::ColorOnly)) {
+	QImage tray(qsl(":/gui/art/osxtray.png"));
+	trayImg = tray.copy(0, cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
+	trayImgSel = tray.copy(tray.width() / (cRetina() ? 2 : 4), cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
 
-bool objc_showOpenWithMenu(int x, int y, const QString &f) {
-	NSString *file = QNSString(f).s();
-	@try {
-		OpenFileWithInterface *menu = [[OpenFileWithInterface alloc] init:file];
-		QRect r = QApplication::desktop()->screenGeometry(QPoint(x, y));
-		y = r.y() + r.height() - y;
-		return !![menu popupAtX:x andY:y];
+	_hideAfterFullScreenTimer.setSingleShot(true);
+	connect(&_hideAfterFullScreenTimer, SIGNAL(timeout()), this, SLOT(onHideAfterFullScreen()));
+}
+
+void MainWindow::closeWithoutDestroy() {
+	NSWindow *nsWindow = [reinterpret_cast<NSView*>(winId()) window];
+	bool isFullScreen = (([nsWindow styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask);
+	if (isFullScreen) {
+		_hideAfterFullScreenTimer.start(3000);
+		[nsWindow toggleFullScreen:nsWindow];
+	} else {
+		hide();
 	}
-	@catch (NSException *exception) {
+}
+
+void MainWindow::stateChangedHook(Qt::WindowState state) {
+	if (_hideAfterFullScreenTimer.isActive()) {
+		_hideAfterFullScreenTimer.stop();
+		QTimer::singleShot(0, this, SLOT(onHideAfterFullScreen()));
 	}
-	@finally {
+}
+
+void MainWindow::onHideAfterFullScreen() {
+	hide();
+}
+
+QImage MainWindow::psTrayIcon(bool selected) const {
+	return selected ? trayImgSel : trayImg;
+}
+
+void MainWindow::psShowTrayMenu() {
+}
+
+void MainWindow::psRefreshTaskbarIcon() {
+}
+
+void MainWindow::psTrayMenuUpdated() {
+}
+
+void MainWindow::psSetupTrayIcon() {
+	if (!trayIcon) {
+		trayIcon = new QSystemTrayIcon(this);
+
+		QIcon icon(QPixmap::fromImage(psTrayIcon(), Qt::ColorOnly));
+		icon.addPixmap(QPixmap::fromImage(psTrayIcon(true), Qt::ColorOnly), QIcon::Selected);
+
+		trayIcon->setIcon(icon);
+		trayIcon->setToolTip(str_const_toString(AppName));
+		connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleTray(QSystemTrayIcon::ActivationReason)), Qt::UniqueConnection);
+		App::wnd()->updateTrayMenu();
 	}
-	return false;
+	psUpdateCounter();
+
+	trayIcon->show();
 }
 
-void objc_showInFinder(const QString &file, const QString &path) {
-    [[NSWorkspace sharedWorkspace] selectFile:QNSString(file).s() inFileViewerRootedAtPath:QNSString(path).s()];
+void MainWindow::psUpdateWorkmode() {
+	psSetupTrayIcon();
+	if (cWorkMode() == dbiwmWindowOnly) {
+		if (trayIcon) {
+			trayIcon->setContextMenu(0);
+			delete trayIcon;
+		}
+		trayIcon = 0;
+	}
+	psUpdateDelegate();
+	setWindowIcon(wndIcon);
 }
 
-@interface NSURL(CompareUrls)
+void _placeCounter(QImage &img, int size, int count, style::color bg, style::color color) {
+	if (!count) return;
 
-- (BOOL) isEquivalent:(NSURL *)aURL;
+	QPainter p(&img);
+	QString cnt = (count < 100) ? QString("%1").arg(count) : QString("..%1").arg(count % 100, 2, 10, QChar('0'));
+	int32 cntSize = cnt.size();
 
-@end
+	p.setBrush(bg->b);
+	p.setPen(Qt::NoPen);
+	p.setRenderHint(QPainter::Antialiasing);
+	int32 fontSize, skip;
+	if (size == 22) {
+		skip = 1;
+		fontSize = 8;
+	} else {
+		skip = 2;
+		fontSize = 16;
+	}
+	style::font f(fontSize, 0, 0);
+	int32 w = f->width(cnt), d, r;
+	if (size == 22) {
+		d = (cntSize < 2) ? 3 : 2;
+		r = (cntSize < 2) ? 6 : 5;
+	} else {
+		d = (cntSize < 2) ? 6 : 5;
+		r = (cntSize < 2) ? 9 : 11;
+	}
+	p.drawRoundedRect(QRect(size - w - d * 2 - skip, size - f->height - skip, w + d * 2, f->height), r, r);
 
-@implementation NSURL(CompareUrls)
-
-- (BOOL) isEquivalent:(NSURL *)aURL {
-    if ([self isEqual:aURL]) return YES;
-    if ([[self scheme] caseInsensitiveCompare:[aURL scheme]] != NSOrderedSame) return NO;
-    if ([[self host] caseInsensitiveCompare:[aURL host]] != NSOrderedSame) return NO;
-    if ([[self path] compare:[aURL path]] != NSOrderedSame) return NO;
-    if ([[self port] compare:[aURL port]] != NSOrderedSame) return NO;
-    if ([[self query] compare:[aURL query]] != NSOrderedSame) return NO;
-    return YES;
+	p.setCompositionMode(QPainter::CompositionMode_Source);
+	p.setFont(f->f);
+	p.setPen(color->p);
+	p.drawText(size - w - d - skip, size - f->height + f->ascent - skip, cnt);
 }
 
-@end
+void MainWindow::psUpdateCounter() {
+	int32 counter = App::histories().unreadBadge();
 
-@interface ChooseApplicationDelegate : NSObject<NSOpenSavePanelDelegate> {
+	setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
+	setWindowIcon(wndIcon);
+
+	QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0'));
+	_private.setWindowBadge(counter ? cnt : QString());
+
+	if (trayIcon) {
+		bool muted = App::histories().unreadOnlyMuted();
+		bool dm = objc_darkMode();
+
+		style::color bg = muted ? st::counterMuteBG : st::counterBG;
+		QIcon icon;
+		QImage img(psTrayIcon(dm)), imgsel(psTrayIcon(true));
+		img.detach();
+		imgsel.detach();
+		int32 size = cRetina() ? 44 : 22;
+		_placeCounter(img, size, counter, bg, (dm && muted) ? st::counterMacInvColor : st::counterColor);
+		_placeCounter(imgsel, size, counter, st::white, st::counterMacInvColor);
+		icon.addPixmap(QPixmap::fromImage(img, Qt::ColorOnly));
+		icon.addPixmap(QPixmap::fromImage(imgsel, Qt::ColorOnly), QIcon::Selected);
+		trayIcon->setIcon(icon);
+	}
 }
 
-- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc;
-- (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url;
-- (void) panelSelectionDidChange:(id)sender;
-- (void) menuDidClose;
-- (void) dealloc;
-
-@end
-
-@implementation ChooseApplicationDelegate {
-    BOOL onlyRecommended;
-    NSArray *apps;
-    NSOpenPanel *panel;
-    NSPopUpButton *selector;
-    NSTextField *good, *bad;
-    NSImageView *icon;
-    NSString *recom;
-    NSView *accessory;
+void MainWindow::psUpdateDelegate() {
+	_private.updateDelegate();
 }
 
-- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc {
-    if (self = [super init]) {
-        onlyRecommended = YES;
-        recom = [objc_lang(lng_mac_recommended_apps).s() copy];
-        apps = recommendedApps;
-        panel = creator;
-        selector = menu;
-        good = goodLabel;
-        bad = badLabel;
-        icon = badIcon;
-        accessory = acc;
-        [selector setAction:@selector(menuDidClose)];
-    }
-    return self;
+void MainWindow::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 = Application::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);
 }
 
-- (BOOL) isRecommended:(NSURL *)url {
-    if (apps) {
-        for (id app in apps) {
-            if ([(NSURL*)app isEquivalent:url]) {
-                return YES;
-            }
-        }
-    }
-    return NO;
+void MainWindow::psInitFrameless() {
+	psUpdatedPositionTimer.setSingleShot(true);
+	connect(&psUpdatedPositionTimer, SIGNAL(timeout()), this, SLOT(psSavePosition()));
 }
 
-- (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url {
-    NSNumber *isDirectory;
-    if ([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && isDirectory != nil && [isDirectory boolValue]) {
-        if (onlyRecommended) {
-            CFStringRef ext = CFURLCopyPathExtension((CFURLRef)url);
-            NSNumber *isPackage;
-            if ([url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:nil] && isPackage != nil && [isPackage boolValue]) {
-                return [self isRecommended:url];
-            }
-        }
-        return YES;
-    }
-    return NO;
+void MainWindow::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 = Application::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);
+			Local::writeSettings();
+		}
+	}
 }
 
-- (void) panelSelectionDidChange:(id)sender {
-    NSArray *urls = [panel URLs];
-    if ([urls count]) {
-        if ([self isRecommended:[urls firstObject]]) {
-            [bad removeFromSuperview];
-            [icon removeFromSuperview];
-            [accessory addSubview:good];
-        } else {
-            [good removeFromSuperview];
-            [accessory addSubview:bad];
-            [accessory addSubview:icon];
-        }
-    } else {
-        [good removeFromSuperview];
-        [bad removeFromSuperview];
-        [icon removeFromSuperview];
-    }
+void MainWindow::psUpdatedPosition() {
+	psUpdatedPositionTimer.start(SaveWindowPositionTimeout);
 }
 
-- (void) menuDidClose {
-    onlyRecommended = [[[selector selectedItem] title] isEqualToString:recom];
-    [self refreshPanelTable];
-}
+void MainWindow::psFirstShow() {
+	psUpdateMargins();
 
-- (BOOL) refreshDataInViews: (NSArray*)subviews {
-    for (id view in subviews) {
-        NSString *cls = [view className];
-        if ([cls isEqualToString:QNSString(strNeedToReload()).s()]) {
-            [view reloadData];
-        } else if ([cls isEqualToString:QNSString(strNeedToRefresh1()).s()] || [cls isEqualToString:QNSString(strNeedToRefresh2()).s()]) {
-            [view reloadData];
-            return YES;
-        } else {
-            NSArray *next = [view subviews];
-            if ([next count] && [self refreshDataInViews:next]) {
-                return YES;
-            }
-        }
-    }
+	bool showShadows = true;
 
-    return NO;
-}
+	show();
+	_private.enableShadow(winId());
+	if (cWindowPos().maximized) {
+		setWindowState(Qt::WindowMaximized);
+	}
 
+	if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
+		setWindowState(Qt::WindowMinimized);
+		if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
+			hide();
+		} else {
+			show();
+		}
+		showShadows = false;
+	} else {
+		show();
+	}
 
-- (void) refreshPanelTable {
-    [self refreshDataInViews:[[panel contentView] subviews]];
-    [panel validateVisibleColumns];
-}
+	posInited = true;
 
-- (void) dealloc {
-    if (apps) {
-        [apps release];
-        [recom release];
-    }
-    [super dealloc];
-}
+	// init global menu
+	QMenu *main = psMainMenu.addMenu(qsl("Telegram"));
+	main->addAction(lng_mac_menu_about_telegram(lt_telegram, qsl("Telegram")), App::wnd()->getTitle(), SLOT(onAbout()))->setMenuRole(QAction::AboutQtRole);
+	main->addSeparator();
+	QAction *prefs = main->addAction(lang(lng_mac_menu_preferences), App::wnd(), SLOT(showSettings()), QKeySequence(Qt::ControlModifier | Qt::Key_Comma));
+	prefs->setMenuRole(QAction::PreferencesRole);
 
-@end
+	QMenu *file = psMainMenu.addMenu(lang(lng_mac_menu_file));
+	psLogout = file->addAction(lang(lng_mac_menu_logout), App::wnd(), SLOT(onLogout()));
 
-void objc_openFile(const QString &f, bool openwith) {
-    NSString *file = QNSString(f).s();
-    if (openwith || [[NSWorkspace sharedWorkspace] openFile:file] == NO) {
-        @try {
-            NSURL *url = [NSURL fileURLWithPath:file];
-            NSString *ext = [url pathExtension];
-            NSArray *names =[url pathComponents];
-            NSString *name = [names count] ? [names lastObject] : @"";
-            NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
+	QMenu *edit = psMainMenu.addMenu(lang(lng_mac_menu_edit));
+	psUndo = edit->addAction(lang(lng_mac_menu_undo), this, SLOT(psMacUndo()), QKeySequence::Undo);
+	psRedo = edit->addAction(lang(lng_mac_menu_redo), this, SLOT(psMacRedo()), QKeySequence::Redo);
+	edit->addSeparator();
+	psCut = edit->addAction(lang(lng_mac_menu_cut), this, SLOT(psMacCut()), QKeySequence::Cut);
+	psCopy = edit->addAction(lang(lng_mac_menu_copy), this, SLOT(psMacCopy()), QKeySequence::Copy);
+	psPaste = edit->addAction(lang(lng_mac_menu_paste), this, SLOT(psMacPaste()), QKeySequence::Paste);
+	psDelete = edit->addAction(lang(lng_mac_menu_delete), this, SLOT(psMacDelete()), QKeySequence(Qt::ControlModifier | Qt::Key_Backspace));
+	edit->addSeparator();
+	psSelectAll = edit->addAction(lang(lng_mac_menu_select_all), this, SLOT(psMacSelectAll()), QKeySequence::SelectAll);
 
-            NSOpenPanel *openPanel = [NSOpenPanel openPanel];
+	QMenu *window = psMainMenu.addMenu(lang(lng_mac_menu_window));
+	psContacts = window->addAction(lang(lng_mac_menu_contacts), App::wnd()->getTitle(), SLOT(onContacts()));
+	psAddContact = window->addAction(lang(lng_mac_menu_add_contact), App::wnd(), SLOT(onShowAddContact()));
+	window->addSeparator();
+	psNewGroup = window->addAction(lang(lng_mac_menu_new_group), App::wnd(), SLOT(onShowNewGroup()));
+	psNewChannel = window->addAction(lang(lng_mac_menu_new_channel), App::wnd(), SLOT(onShowNewChannel()));
+	window->addSeparator();
+	psShowTelegram = window->addAction(lang(lng_mac_menu_show), App::wnd(), SLOT(showFromTray()));
 
-			NSRect fullRect = { { 0., 0. }, { st::macAccessoryWidth, st::macAccessoryHeight } };
-			NSView *accessory = [[NSView alloc] initWithFrame:fullRect];
-
-            [accessory setAutoresizesSubviews:YES];
-
-            NSPopUpButton *selector = [[NSPopUpButton alloc] init];
-            [accessory addSubview:selector];
-            [selector addItemWithTitle:objc_lang(lng_mac_recommended_apps).s()];
-            [selector addItemWithTitle:objc_lang(lng_mac_all_apps).s()];
-            [selector sizeToFit];
-
-            NSTextField *enableLabel = [[NSTextField alloc] init];
-            [accessory addSubview:enableLabel];
-            [enableLabel setStringValue:objc_lang(lng_mac_enable_filter).s()];
-            [enableLabel setFont:[selector font]];
-            [enableLabel setBezeled:NO];
-            [enableLabel setDrawsBackground:NO];
-            [enableLabel setEditable:NO];
-            [enableLabel setSelectable:NO];
-            [enableLabel sizeToFit];
-
-            NSRect selectorFrame = [selector frame], enableFrame = [enableLabel frame];
-            enableFrame.size.width += st::macEnableFilterAdd;
-            enableFrame.origin.x = (fullRect.size.width - selectorFrame.size.width - enableFrame.size.width) / 2.;
-            selectorFrame.origin.x = (fullRect.size.width - selectorFrame.size.width + enableFrame.size.width) / 2.;
-            enableFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macEnableFilterTop + (selectorFrame.size.height - enableFrame.size.height) / 2.;
-            selectorFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macSelectorTop;
-            [enableLabel setFrame:enableFrame];
-            [enableLabel setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
-            [selector setFrame:selectorFrame];
-            [selector setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
-
-            NSButton *button = [[NSButton alloc] init];
-            [accessory addSubview:button];
-            [button setButtonType:NSSwitchButton];
-            [button setFont:[selector font]];
-            [button setTitle:objc_lang(lng_mac_always_open_with).s()];
-            [button sizeToFit];
-            NSRect alwaysRect = [button frame];
-            alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2;
-            alwaysRect.origin.y = selectorFrame.origin.y - alwaysRect.size.height - st::macAlwaysThisAppTop;
-            [button setFrame:alwaysRect];
-            [button setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
-            NSTextField *goodLabel = [[NSTextField alloc] init];
-            [goodLabel setStringValue:QNSString(lng_mac_this_app_can_open(lt_file, objcString(name))).s()];
-            [goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
-            [goodLabel setBezeled:NO];
-            [goodLabel setDrawsBackground:NO];
-            [goodLabel setEditable:NO];
-            [goodLabel setSelectable:NO];
-            [goodLabel sizeToFit];
-            NSRect goodFrame = [goodLabel frame];
-            goodFrame.origin.x = (fullRect.size.width - goodFrame.size.width) / 2.;
-            goodFrame.origin.y = alwaysRect.origin.y - goodFrame.size.height - st::macAppHintTop;
-            [goodLabel setFrame:goodFrame];
-
-            NSTextField *badLabel = [[NSTextField alloc] init];
-            [badLabel setStringValue:QNSString(lng_mac_not_known_app(lt_file, objcString(name))).s()];
-            [badLabel setFont:[goodLabel font]];
-            [badLabel setBezeled:NO];
-            [badLabel setDrawsBackground:NO];
-            [badLabel setEditable:NO];
-            [badLabel setSelectable:NO];
-            [badLabel sizeToFit];
-            NSImageView *badIcon = [[NSImageView alloc] init];
-            NSImage *badImage = [NSImage imageNamed:NSImageNameCaution];
-            [badIcon setImage:badImage];
-            [badIcon setFrame:NSMakeRect(0, 0, st::macCautionIconSize, st::macCautionIconSize)];
-
-            NSRect badFrame = [badLabel frame], badIconFrame = [badIcon frame];
-            badFrame.origin.x = (fullRect.size.width - badFrame.size.width + badIconFrame.size.width) / 2.;
-            badIconFrame.origin.x = (fullRect.size.width - badFrame.size.width - badIconFrame.size.width) / 2.;
-            badFrame.origin.y = alwaysRect.origin.y - badFrame.size.height - st::macAppHintTop;
-            badIconFrame.origin.y = badFrame.origin.y;
-            [badLabel setFrame:badFrame];
-            [badIcon setFrame:badIconFrame];
-
-			[openPanel setAccessoryView:accessory];
-
-            ChooseApplicationDelegate *delegate = [[ChooseApplicationDelegate alloc] init:apps withPanel:openPanel withSelector:selector withGood:goodLabel withBad:badLabel withIcon:badIcon withAccessory:accessory];
-            [openPanel setDelegate:delegate];
-
-            [openPanel setCanChooseDirectories:NO];
-            [openPanel setCanChooseFiles:YES];
-            [openPanel setAllowsMultipleSelection:NO];
-            [openPanel setResolvesAliases:YES];
-            [openPanel setTitle:objc_lang(lng_mac_choose_app).s()];
-            [openPanel setMessage:QNSString(lng_mac_choose_text(lt_file, objcString(name))).s()];
-
-            NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask];
-            if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]];
-            [openPanel beginWithCompletionHandler:^(NSInteger result){
-                if (result == NSFileHandlingPanelOKButton) {
-                    if ([[openPanel URLs] count] > 0) {
-                        NSURL *app = [[openPanel URLs] objectAtIndex:0];
-                        NSString *path = [app path];
-                        if ([button state] == NSOnState) {
-                            NSArray *UTIs = (NSArray *)UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension,
-                                                                                        (CFStringRef)ext,
-                                                                                        nil);
-                            for (NSString *UTI in UTIs) {
-								OSStatus result = LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI,
-																						kLSRolesAll,
-																						(CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]);
-								DEBUG_LOG(("App Info: set default handler for '%1' UTI result: %2").arg(objcString(UTI)).arg(result));
-                            }
-
-                            [UTIs release];
-                        }
-                        [[NSWorkspace sharedWorkspace] openFile:file withApplication:[app path]];
-                    }
-                }
-                [selector release];
-                [button release];
-                [enableLabel release];
-                [goodLabel release];
-                [badLabel release];
-                [badIcon release];
-                [accessory release];
-                [delegate release];
-            }];
-        }
-        @catch (NSException *exception) {
-            [[NSWorkspace sharedWorkspace] openFile:file];
-        }
-        @finally {
-        }
-    }
-}
-
-void objc_start() {
-	_sharedDelegate = [[ApplicationDelegate alloc] init];
-	[[NSApplication sharedApplication] setDelegate:_sharedDelegate];
-	[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: _sharedDelegate
-														   selector: @selector(receiveWakeNote:)
-															   name: NSWorkspaceDidWakeNotification object: NULL];
+	psMacUpdateMenu();
 }
 
 namespace {
-	NSURL *_downloadPathUrl = nil;
-}
-
-void objc_finish() {
-	[_sharedDelegate release];
-	if (_downloadPathUrl) {
-		[_downloadPathUrl stopAccessingSecurityScopedResource];
-		_downloadPathUrl = nil;
-	}
-}
-
-void objc_registerCustomScheme() {
-	#ifndef TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
-	OSStatus result = LSSetDefaultHandlerForURLScheme(CFSTR("tg"), (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]);
-	DEBUG_LOG(("App Info: set default handler for 'tg' scheme result: %1").arg(result));
-	#endif
-}
-
-BOOL _execUpdater(BOOL update = YES, const QString &crashreport = QString()) {
-	NSString *path = @"", *args = @"";
-	@try {
-		path = [[NSBundle mainBundle] bundlePath];
-		if (!path) {
-			LOG(("Could not get bundle path!!"));
-			return NO;
-		}
-		path = [path stringByAppendingString:@"/Contents/Frameworks/Updater"];
-
-		NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-workpath", QNSString(cWorkingDir()).s(), @"-procid", nil];
-		[args addObject:[NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]];
-		if (cRestartingToSettings()) [args addObject:@"-tosettings"];
-		if (!update) [args addObject:@"-noupdate"];
-		if (cLaunchMode() == LaunchModeAutoStart) [args addObject:@"-autostart"];
-		if (cDebug()) [args addObject:@"-debug"];
-		if (cStartInTray()) [args addObject:@"-startintray"];
-		if (cTestMode()) [args addObject:@"-testmode"];
-		if (cDataFile() != qsl("data")) {
-			[args addObject:@"-key"];
-			[args addObject:QNSString(cDataFile()).s()];
-		}
-		if (!crashreport.isEmpty()) {
-			[args addObject:@"-crashreport"];
-			[args addObject:QNSString(crashreport).s()];
-		}
-
-		DEBUG_LOG(("Application Info: executing %1 %2").arg(objcString(path)).arg(objcString([args componentsJoinedByString:@" "])));
-		Logs::closeMain();
-		SignalHandlers::finish();
-		if (![NSTask launchedTaskWithLaunchPath:path arguments:args]) {
-			DEBUG_LOG(("Task not launched while executing %1 %2").arg(objcString(path)).arg(objcString([args componentsJoinedByString:@" "])));
-			return NO;
+	void _sendKeySequence(Qt::Key key, Qt::KeyboardModifiers modifiers = Qt::NoModifier) {
+		QWidget *focused = QApplication::focusWidget();
+		if (qobject_cast<QLineEdit*>(focused) || qobject_cast<FlatTextarea*>(focused) || qobject_cast<HistoryInner*>(focused)) {
+			QApplication::postEvent(focused, new QKeyEvent(QEvent::KeyPress, key, modifiers));
+			QApplication::postEvent(focused, new QKeyEvent(QEvent::KeyRelease, key, modifiers));
 		}
 	}
-	@catch (NSException *exception) {
-		LOG(("Exception caught while executing %1 %2").arg(objcString(path)).arg(objcString(args)));
-		return NO;
-	}
-	@finally {
-	}
-	return YES;
-}
-
-bool objc_execUpdater() {
-	return !!_execUpdater();
-}
-
-void objc_execTelegram(const QString &crashreport) {
-	_execUpdater(NO, crashreport);
-}
-
-void objc_activateProgram(WId winId) {
-	[NSApp activateIgnoringOtherApps:YES];
-	if (winId) {
-		NSWindow *w = [reinterpret_cast<NSView*>(winId) window];
-		[w makeKeyAndOrderFront:NSApp];
-	}
-}
-
-bool objc_moveFile(const QString &from, const QString &to) {
-	NSString *f = QNSString(from).s(), *t = QNSString(to).s();
-	if ([[NSFileManager defaultManager] fileExistsAtPath:t]) {
-		NSData *data = [NSData dataWithContentsOfFile:f];
-		if (data) {
-			if ([data writeToFile:t atomically:YES]) {
-				if ([[NSFileManager defaultManager] removeItemAtPath:f error:nil]) {
-					return true;
-				}
-			}
-		}
-	} else {
-		if ([[NSFileManager defaultManager] moveItemAtPath:f toPath:t error:nil]) {
-			return true;
+	void _forceDisabled(QAction *action, bool disabled) {
+		if (action->isEnabled()) {
+			if (disabled) action->setDisabled(true);
+		} else if (!disabled) {
+			action->setDisabled(false);
 		}
 	}
+}
+
+void MainWindow::psMacUndo() {
+	_sendKeySequence(Qt::Key_Z, Qt::ControlModifier);
+}
+
+void MainWindow::psMacRedo() {
+	_sendKeySequence(Qt::Key_Z, Qt::ControlModifier | Qt::ShiftModifier);
+}
+
+void MainWindow::psMacCut() {
+	_sendKeySequence(Qt::Key_X, Qt::ControlModifier);
+}
+
+void MainWindow::psMacCopy() {
+	_sendKeySequence(Qt::Key_C, Qt::ControlModifier);
+}
+
+void MainWindow::psMacPaste() {
+	_sendKeySequence(Qt::Key_V, Qt::ControlModifier);
+}
+
+void MainWindow::psMacDelete() {
+	_sendKeySequence(Qt::Key_Delete);
+}
+
+void MainWindow::psMacSelectAll() {
+	_sendKeySequence(Qt::Key_A, Qt::ControlModifier);
+}
+
+bool MainWindow::psHandleTitle() {
 	return false;
 }
 
-void objc_deleteDir(const QString &dir) {
-	[[NSFileManager defaultManager] removeItemAtPath:QNSString(dir).s() error:nil];
+void MainWindow::psInitSysMenu() {
 }
 
-double objc_appkitVersion() {
-	return NSAppKitVersionNumber;
+void MainWindow::psUpdateSysMenu(Qt::WindowState state) {
 }
 
-QString objc_appDataPath() {
-	NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
-	if (url) {
-		return QString::fromUtf8([[url path] fileSystemRepresentation]) + '/' + str_const_toString(AppName) + '/';
+void MainWindow::psUpdateMargins() {
+}
+
+void MainWindow::psMacUpdateMenu() {
+	if (!posInited) return;
+
+	QWidget *focused = QApplication::focusWidget();
+	bool isLogged = !!App::self(), canUndo = false, canRedo = false, canCut = false, canCopy = false, canPaste = false, canDelete = false, canSelectAll = false;
+	if (QLineEdit *edit = qobject_cast<QLineEdit*>(focused)) {
+		canCut = canCopy = canDelete = edit->hasSelectedText();
+		canSelectAll = !edit->text().isEmpty();
+		canUndo = edit->isUndoAvailable();
+		canRedo = edit->isRedoAvailable();
+		canPaste = !Application::clipboard()->text().isEmpty();
+	} else if (FlatTextarea *edit = qobject_cast<FlatTextarea*>(focused)) {
+		canCut = canCopy = canDelete = edit->textCursor().hasSelection();
+		canSelectAll = !edit->isEmpty();
+		canUndo = edit->isUndoAvailable();
+		canRedo = edit->isRedoAvailable();
+		canPaste = !Application::clipboard()->text().isEmpty();
+	} else if (HistoryInner *list = qobject_cast<HistoryInner*>(focused)) {
+		canCopy = list->canCopySelected();
+		canDelete = list->canDeleteSelected();
 	}
-	return QString();
+	_forceDisabled(psLogout, !isLogged && !App::passcoded());
+	_forceDisabled(psUndo, !canUndo);
+	_forceDisabled(psRedo, !canRedo);
+	_forceDisabled(psCut, !canCut);
+	_forceDisabled(psCopy, !canCopy);
+	_forceDisabled(psPaste, !canPaste);
+	_forceDisabled(psDelete, !canDelete);
+	_forceDisabled(psSelectAll, !canSelectAll);
+	_forceDisabled(psContacts, !isLogged || App::passcoded());
+	_forceDisabled(psAddContact, !isLogged || App::passcoded());
+	_forceDisabled(psNewGroup, !isLogged || App::passcoded());
+	_forceDisabled(psNewChannel, !isLogged || App::passcoded());
+	_forceDisabled(psShowTelegram, App::wnd()->isActive(false));
 }
 
-QString objc_downloadPath() {
-	NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSDownloadsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
-	if (url) {
-		return QString::fromUtf8([[url path] fileSystemRepresentation]) + '/' + str_const_toString(AppName) + '/';
+void MainWindow::psFlash() {
+	_private.startBounce();
+}
+
+void MainWindow::psClearNotifies(PeerId peerId) {
+	_private.clearNotifies(peerId);
+}
+
+void MainWindow::psActivateNotify(NotifyWindow *w) {
+	objc_activateWnd(w->winId());
+}
+
+bool MainWindow::psFilterNativeEvent(void *event) {
+	return _private.filterNativeEvent(event);
+}
+
+void MainWindow::psNotifyShown(NotifyWindow *w) {
+	w->hide();
+	objc_holdOnTop(w->winId());
+	w->show();
+	psShowOverAll(w, false);
+}
+
+void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
+	QString title = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->name : qsl("Telegram Desktop");
+	QString subtitle = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->notificationHeader() : QString();
+	QPixmap pix = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->genUserpic(st::notifyMacPhotoSize) : QPixmap();
+	QString msg = (!App::passcoded() && cNotifyView() <= dbinvShowPreview) ? (fwdCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, fwdCount)) : lang(lng_notification_preview);
+
+	bool withReply = !App::passcoded() && (cNotifyView() <= dbinvShowPreview) && item->history()->peer->canWrite();
+
+	_private.showNotify(item->history()->peer->id, item->id, pix, title, subtitle, msg, withReply);
+}
+
+bool MainWindow::eventFilter(QObject *obj, QEvent *evt) {
+	QEvent::Type t = evt->type();
+	if (t == QEvent::FocusIn || t == QEvent::FocusOut) {
+		if (qobject_cast<QLineEdit*>(obj) || qobject_cast<FlatTextarea*>(obj) || qobject_cast<HistoryInner*>(obj)) {
+			psMacUpdateMenu();
+		}
 	}
-	return QString();
+	return Window::MainWindow::eventFilter(obj, evt);
 }
 
-QString objc_currentCountry() {
-	NSLocale *currentLocale = [NSLocale currentLocale];  // get the current locale.
-	NSString *countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
-	return countryCode ? objcString(countryCode) : QString();
+MainWindow::~MainWindow() {
 }
 
-QString objc_currentLang() {
-	NSLocale *currentLocale = [NSLocale currentLocale];  // get the current locale.
-	NSString *currentLang = [currentLocale objectForKey:NSLocaleLanguageCode];
-	return currentLang ? objcString(currentLang) : QString();
-}
-
-QString objc_convertFileUrl(const QString &url) {
-	NSString *nsurl = [[[NSURL URLWithString: [NSString stringWithUTF8String: (qsl("file://") + url).toUtf8().constData()]] filePathURL] path];
-	if (!nsurl) return QString();
-
-	return objcString(nsurl);
-}
-
-QByteArray objc_downloadPathBookmark(const QString &path) {
-	return QByteArray();
-}
-
-QByteArray objc_pathBookmark(const QString &path) {
-	return QByteArray();
-}
-
-void objc_downloadPathEnableAccess(const QByteArray &bookmark) {
-}
-
-objc_FileBookmark::objc_FileBookmark(const QByteArray &bookmark) {
-}
-
-bool objc_FileBookmark::valid() const {
-	return true;
-}
-
-bool objc_FileBookmark::enable() const {
-	return true;
-}
-
-void objc_FileBookmark::disable() const {
-}
-
-const QString &objc_FileBookmark::name(const QString &original) const {
-	return original;
-}
-
-QByteArray objc_FileBookmark::bookmark() const {
-	return QByteArray();
-}
-
-objc_FileBookmark::~objc_FileBookmark() {
-}
+} // namespace
diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp
index 59a3ff7f1..dc7761b14 100644
--- a/Telegram/SourceFiles/pspecific_mac.cpp
+++ b/Telegram/SourceFiles/pspecific_mac.cpp
@@ -31,9 +31,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 namespace {
     QStringList _initLogs;
 
-    bool frameless = true;
-	bool finished = true;
-
     class _PsEventFilter : public QAbstractNativeEventFilter {
 	public:
 		_PsEventFilter() {
@@ -50,430 +47,6 @@ namespace {
 
 };
 
-void MacPrivate::activeSpaceChanged() {
-    if (App::wnd()) {
-        App::wnd()->notifyActivateAll();
-    }
-}
-
-void MacPrivate::darkModeChanged() {
-	Notify::unreadCounterUpdated();
-}
-
-void MacPrivate::notifyClicked(unsigned long long peer, int msgid) {
-    History *history = App::history(PeerId(peer));
-
-    App::wnd()->showFromTray();
-	if (App::passcoded()) {
-		App::wnd()->setInnerFocus();
-		App::wnd()->notifyClear();
-	} else {
-		App::wnd()->hideSettings();
-		bool tomsg = !history->peer->isUser() && (msgid > 0);
-		if (tomsg) {
-			HistoryItem *item = App::histItemById(peerToChannel(PeerId(peer)), MsgId(msgid));
-			if (!item || !item->mentionsMe()) {
-				tomsg = false;
-			}
-		}
-		Ui::showPeerHistory(history, tomsg ? msgid : ShowAtUnreadMsgId);
-		App::wnd()->notifyClear(history);
-	}
-}
-
-void MacPrivate::notifyReplied(unsigned long long peer, int msgid, const char *str) {
-    History *history = App::history(PeerId(peer));
-
-	MainWidget::MessageToSend message;
-	message.history = history;
-	message.textWithTags = { QString::fromUtf8(str), TextWithTags::Tags() };
-	message.replyTo = (msgid > 0 && !history->peer->isUser()) ? msgid : 0;
-	message.silent = false;
-	message.clearDraft = false;
-	App::main()->sendMessage(message);
-}
-
-PsMainWindow::PsMainWindow(QWidget *parent) : QMainWindow(parent),
-posInited(false), trayIcon(0), trayIconMenu(0), icon256(qsl(":/gui/art/icon256.png")), iconbig256(qsl(":/gui/art/iconbig256.png")), wndIcon(QPixmap::fromImage(iconbig256, Qt::ColorOnly)),
-psLogout(0), psUndo(0), psRedo(0), psCut(0), psCopy(0), psPaste(0), psDelete(0), psSelectAll(0), psContacts(0), psAddContact(0), psNewGroup(0), psNewChannel(0), psShowTelegram(0) {
-	QImage tray(qsl(":/gui/art/osxtray.png"));
-	trayImg = tray.copy(0, cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
-	trayImgSel = tray.copy(tray.width() / (cRetina() ? 2 : 4), cRetina() ? 0 : tray.width() / 2, tray.width() / (cRetina() ? 2 : 4), tray.width() / (cRetina() ? 2 : 4));
-}
-
-QImage PsMainWindow::psTrayIcon(bool selected) const {
-	return selected ? trayImgSel : trayImg;
-}
-
-void PsMainWindow::psShowTrayMenu() {
-}
-
-void PsMainWindow::psRefreshTaskbarIcon() {
-}
-
-void PsMainWindow::psTrayMenuUpdated() {
-}
-
-void PsMainWindow::psSetupTrayIcon() {
-    if (!trayIcon) {
-        trayIcon = new QSystemTrayIcon(this);
-
-        QIcon icon(QPixmap::fromImage(psTrayIcon(), Qt::ColorOnly));
-        icon.addPixmap(QPixmap::fromImage(psTrayIcon(true), Qt::ColorOnly), QIcon::Selected);
-
-        trayIcon->setIcon(icon);
-        trayIcon->setToolTip(str_const_toString(AppName));
-        connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleTray(QSystemTrayIcon::ActivationReason)), Qt::UniqueConnection);
-        App::wnd()->updateTrayMenu();
-    }
-    psUpdateCounter();
-
-    trayIcon->show();
-}
-
-void PsMainWindow::psUpdateWorkmode() {
-    psSetupTrayIcon();
-	if (cWorkMode() == dbiwmWindowOnly) {
-		if (trayIcon) {
-			trayIcon->setContextMenu(0);
-			delete trayIcon;
-		}
-		trayIcon = 0;
-	}
-	psUpdateDelegate();
-	setWindowIcon(wndIcon);
-}
-
-void _placeCounter(QImage &img, int size, int count, style::color bg, style::color color) {
-	if (!count) return;
-
-	QPainter p(&img);
-	QString cnt = (count < 100) ? QString("%1").arg(count) : QString("..%1").arg(count % 100, 2, 10, QChar('0'));
-	int32 cntSize = cnt.size();
-
-	p.setBrush(bg->b);
-	p.setPen(Qt::NoPen);
-	p.setRenderHint(QPainter::Antialiasing);
-	int32 fontSize, skip;
-	if (size == 22) {
-		skip = 1;
-		fontSize = 8;
-	} else {
-		skip = 2;
-		fontSize = 16;
-	}
-	style::font f(fontSize, 0, 0);
-	int32 w = f->width(cnt), d, r;
-	if (size == 22) {
-		d = (cntSize < 2) ? 3 : 2;
-		r = (cntSize < 2) ? 6 : 5;
-	} else {
-		d = (cntSize < 2) ? 6 : 5;
-		r = (cntSize < 2) ? 9 : 11;
-	}
-	p.drawRoundedRect(QRect(size - w - d * 2 - skip, size - f->height - skip, w + d * 2, f->height), r, r);
-
-	p.setCompositionMode(QPainter::CompositionMode_Source);
-	p.setFont(f->f);
-	p.setPen(color->p);
-	p.drawText(size - w - d - skip, size - f->height + f->ascent - skip, cnt);
-}
-
-void PsMainWindow::psUpdateCounter() {
-	int32 counter = App::histories().unreadBadge();
-
-    setWindowTitle((counter > 0) ? qsl("Telegram (%1)").arg(counter) : qsl("Telegram"));
-	setWindowIcon(wndIcon);
-
-    QString cnt = (counter < 1000) ? QString("%1").arg(counter) : QString("..%1").arg(counter % 100, 2, 10, QChar('0'));
-    _private.setWindowBadge(counter ? cnt : QString());
-
-	if (trayIcon) {
-		bool muted = App::histories().unreadOnlyMuted();
-		bool dm = objc_darkMode();
-
-		style::color bg = muted ? st::counterMuteBG : st::counterBG;
-		QIcon icon;
-		QImage img(psTrayIcon(dm)), imgsel(psTrayIcon(true));
-		img.detach();
-		imgsel.detach();
-		int32 size = cRetina() ? 44 : 22;
-		_placeCounter(img, size, counter, bg, (dm && muted) ? st::counterMacInvColor : st::counterColor);
-		_placeCounter(imgsel, size, counter, st::white, st::counterMacInvColor);
-		icon.addPixmap(QPixmap::fromImage(img, Qt::ColorOnly));
-		icon.addPixmap(QPixmap::fromImage(imgsel, Qt::ColorOnly), QIcon::Selected);
-		trayIcon->setIcon(icon);
-	}
-}
-
-void PsMainWindow::psUpdateDelegate() {
-	_private.updateDelegate();
-}
-
-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 = Application::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);
-	}
-}
-
-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 = Application::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);
-			Local::writeSettings();
-		}
-    }
-}
-
-void PsMainWindow::psUpdatedPosition() {
-    psUpdatedPositionTimer.start(SaveWindowPositionTimeout);
-}
-
-void PsMainWindow::psFirstShow() {
-	finished = false;
-
-    psUpdateMargins();
-
-	bool showShadows = true;
-
-	show();
-    _private.enableShadow(winId());
-	if (cWindowPos().maximized) {
-		setWindowState(Qt::WindowMaximized);
-	}
-
-	if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) {
-		setWindowState(Qt::WindowMinimized);
-		if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
-			hide();
-		} else {
-			show();
-		}
-		showShadows = false;
-	} else {
-		show();
-	}
-
-	posInited = true;
-
-	// init global menu
-	QMenu *main = psMainMenu.addMenu(qsl("Telegram"));
-	main->addAction(lng_mac_menu_about_telegram(lt_telegram, qsl("Telegram")), App::wnd()->getTitle(), SLOT(onAbout()))->setMenuRole(QAction::AboutQtRole);
-	main->addSeparator();
-	QAction *prefs = main->addAction(lang(lng_mac_menu_preferences), App::wnd(), SLOT(showSettings()), QKeySequence(Qt::ControlModifier | Qt::Key_Comma));
-	prefs->setMenuRole(QAction::PreferencesRole);
-
-	QMenu *file = psMainMenu.addMenu(lang(lng_mac_menu_file));
-	psLogout = file->addAction(lang(lng_mac_menu_logout), App::wnd(), SLOT(onLogout()));
-
-	QMenu *edit = psMainMenu.addMenu(lang(lng_mac_menu_edit));
-	psUndo = edit->addAction(lang(lng_mac_menu_undo), this, SLOT(psMacUndo()), QKeySequence::Undo);
-	psRedo = edit->addAction(lang(lng_mac_menu_redo), this, SLOT(psMacRedo()), QKeySequence::Redo);
-	edit->addSeparator();
-	psCut = edit->addAction(lang(lng_mac_menu_cut), this, SLOT(psMacCut()), QKeySequence::Cut);
-	psCopy = edit->addAction(lang(lng_mac_menu_copy), this, SLOT(psMacCopy()), QKeySequence::Copy);
-	psPaste = edit->addAction(lang(lng_mac_menu_paste), this, SLOT(psMacPaste()), QKeySequence::Paste);
-	psDelete = edit->addAction(lang(lng_mac_menu_delete), this, SLOT(psMacDelete()), QKeySequence(Qt::ControlModifier | Qt::Key_Backspace));
-	edit->addSeparator();
-	psSelectAll = edit->addAction(lang(lng_mac_menu_select_all), this, SLOT(psMacSelectAll()), QKeySequence::SelectAll);
-
-	QMenu *window = psMainMenu.addMenu(lang(lng_mac_menu_window));
-	psContacts = window->addAction(lang(lng_mac_menu_contacts), App::wnd()->getTitle(), SLOT(onContacts()));
-	psAddContact = window->addAction(lang(lng_mac_menu_add_contact), App::wnd(), SLOT(onShowAddContact()));
-	window->addSeparator();
-	psNewGroup = window->addAction(lang(lng_mac_menu_new_group), App::wnd(), SLOT(onShowNewGroup()));
-	psNewChannel = window->addAction(lang(lng_mac_menu_new_channel), App::wnd(), SLOT(onShowNewChannel()));
-	window->addSeparator();
-	psShowTelegram = window->addAction(lang(lng_mac_menu_show), App::wnd(), SLOT(showFromTray()));
-
-	psMacUpdateMenu();
-}
-
-namespace {
-	void _sendKeySequence(Qt::Key key, Qt::KeyboardModifiers modifiers = Qt::NoModifier) {
-		QWidget *focused = QApplication::focusWidget();
-		if (qobject_cast<QLineEdit*>(focused) || qobject_cast<FlatTextarea*>(focused) || qobject_cast<HistoryInner*>(focused)) {
-			QApplication::postEvent(focused, new QKeyEvent(QEvent::KeyPress, key, modifiers));
-			QApplication::postEvent(focused, new QKeyEvent(QEvent::KeyRelease, key, modifiers));
-		}
-	}
-	void _forceDisabled(QAction *action, bool disabled) {
-		if (action->isEnabled()) {
-			if (disabled) action->setDisabled(true);
-		} else if (!disabled) {
-			action->setDisabled(false);
-		}
-	}
-}
-
-void PsMainWindow::psMacUndo() {
-	_sendKeySequence(Qt::Key_Z, Qt::ControlModifier);
-}
-
-void PsMainWindow::psMacRedo() {
-	_sendKeySequence(Qt::Key_Z, Qt::ControlModifier | Qt::ShiftModifier);
-}
-
-void PsMainWindow::psMacCut() {
-	_sendKeySequence(Qt::Key_X, Qt::ControlModifier);
-}
-
-void PsMainWindow::psMacCopy() {
-	_sendKeySequence(Qt::Key_C, Qt::ControlModifier);
-}
-
-void PsMainWindow::psMacPaste() {
-	_sendKeySequence(Qt::Key_V, Qt::ControlModifier);
-}
-
-void PsMainWindow::psMacDelete() {
-	_sendKeySequence(Qt::Key_Delete);
-}
-
-void PsMainWindow::psMacSelectAll() {
-	_sendKeySequence(Qt::Key_A, Qt::ControlModifier);
-}
-
-bool PsMainWindow::psHandleTitle() {
-    return false;
-}
-
-void PsMainWindow::psInitSysMenu() {
-}
-
-void PsMainWindow::psUpdateSysMenu(Qt::WindowState state) {
-}
-
-void PsMainWindow::psUpdateMargins() {
-}
-
-void PsMainWindow::psMacUpdateMenu() {
-	if (!posInited) return;
-
-	QWidget *focused = QApplication::focusWidget();
-	bool isLogged = !!App::self(), canUndo = false, canRedo = false, canCut = false, canCopy = false, canPaste = false, canDelete = false, canSelectAll = false;
-	if (QLineEdit *edit = qobject_cast<QLineEdit*>(focused)) {
-		canCut = canCopy = canDelete = edit->hasSelectedText();
-		canSelectAll = !edit->text().isEmpty();
-		canUndo = edit->isUndoAvailable();
-		canRedo = edit->isRedoAvailable();
-		canPaste = !Application::clipboard()->text().isEmpty();
-	} else if (FlatTextarea *edit = qobject_cast<FlatTextarea*>(focused)) {
-		canCut = canCopy = canDelete = edit->textCursor().hasSelection();
-		canSelectAll = !edit->isEmpty();
-		canUndo = edit->isUndoAvailable();
-		canRedo = edit->isRedoAvailable();
-		canPaste = !Application::clipboard()->text().isEmpty();
-	} else if (HistoryInner *list = qobject_cast<HistoryInner*>(focused)) {
-		canCopy = list->canCopySelected();
-		canDelete = list->canDeleteSelected();
-	}
-	_forceDisabled(psLogout, !isLogged && !App::passcoded());
-	_forceDisabled(psUndo, !canUndo);
-	_forceDisabled(psRedo, !canRedo);
-	_forceDisabled(psCut, !canCut);
-	_forceDisabled(psCopy, !canCopy);
-	_forceDisabled(psPaste, !canPaste);
-	_forceDisabled(psDelete, !canDelete);
-	_forceDisabled(psSelectAll, !canSelectAll);
-	_forceDisabled(psContacts, !isLogged || App::passcoded());
-	_forceDisabled(psAddContact, !isLogged || App::passcoded());
-	_forceDisabled(psNewGroup, !isLogged || App::passcoded());
-	_forceDisabled(psNewChannel, !isLogged || App::passcoded());
-	_forceDisabled(psShowTelegram, App::wnd()->isActive(false));
-}
-
-void PsMainWindow::psFlash() {
-    _private.startBounce();
-}
-
-PsMainWindow::~PsMainWindow() {
-	finished = true;
-}
-
-void PsMainWindow::psClearNotifies(PeerId peerId) {
-	_private.clearNotifies(peerId);
-}
-
-void PsMainWindow::psActivateNotify(NotifyWindow *w) {
-	objc_activateWnd(w->winId());
-}
-
-bool PsMainWindow::psFilterNativeEvent(void *event) {
-	return _private.filterNativeEvent(event);
-}
-
 namespace {
 	QRect _monitorRect;
 	uint64 _monitorLastGot = 0;
@@ -496,34 +69,6 @@ void psBringToBack(QWidget *w) {
 	objc_bringToBack(w->winId());
 }
 
-void PsMainWindow::psNotifyShown(NotifyWindow *w) {
-	w->hide();
-	objc_holdOnTop(w->winId());
-	w->show();
-	psShowOverAll(w, false);
-}
-
-void PsMainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
-	QString title = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->name : qsl("Telegram Desktop");
-	QString subtitle = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->notificationHeader() : QString();
-	QPixmap pix = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->genUserpic(st::notifyMacPhotoSize) : QPixmap();
-	QString msg = (!App::passcoded() && cNotifyView() <= dbinvShowPreview) ? (fwdCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, fwdCount)) : lang(lng_notification_preview);
-
-	bool withReply = !App::passcoded() && (cNotifyView() <= dbinvShowPreview) && item->history()->peer->canWrite();
-
-	_private.showNotify(item->history()->peer->id, item->id, pix, title, subtitle, msg, withReply);
-}
-
-bool PsMainWindow::eventFilter(QObject *obj, QEvent *evt) {
-	QEvent::Type t = evt->type();
-	if (t == QEvent::FocusIn || t == QEvent::FocusOut) {
-		if (qobject_cast<QLineEdit*>(obj) || qobject_cast<FlatTextarea*>(obj) || qobject_cast<HistoryInner*>(obj)) {
-			psMacUpdateMenu();
-		}
-	}
-	return QMainWindow::eventFilter(obj, evt);
-}
-
 QAbstractNativeEventFilter *psNativeEventFilter() {
     delete _psEventFilter;
 	_psEventFilter = new _PsEventFilter();
diff --git a/Telegram/SourceFiles/pspecific_mac_p.mm b/Telegram/SourceFiles/pspecific_mac_p.mm
index 3dc9e5ee1..f60aa9644 100644
--- a/Telegram/SourceFiles/pspecific_mac_p.mm
+++ b/Telegram/SourceFiles/pspecific_mac_p.mm
@@ -255,7 +255,7 @@ void objc_holdOnTop(WId winId) {
 bool objc_darkMode() {
 	NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
 	id style = [dict objectForKey:QNSString(strStyleOfInterface()).s()];
-	BOOL darkModeOn = ( style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"] );
+	BOOL darkModeOn = (style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"]);
 	return darkModeOn ? true : false;
 }
 
diff --git a/Telegram/SourceFiles/ui/scrollarea.h b/Telegram/SourceFiles/ui/scrollarea.h
index 06ee0ccf5..1552cf5ad 100644
--- a/Telegram/SourceFiles/ui/scrollarea.h
+++ b/Telegram/SourceFiles/ui/scrollarea.h
@@ -166,15 +166,6 @@ public:
 
 	ScrollArea(QWidget *parent, const style::flatScroll &st = st::scrollDef, bool handleTouch = true);
 
-	bool viewportEvent(QEvent *e);
-	void touchEvent(QTouchEvent *e);
-
-	bool eventFilter(QObject *obj, QEvent *e);
-
-	void resizeEvent(QResizeEvent *e);
-	void moveEvent(QMoveEvent *e);
-	void keyPressEvent(QKeyEvent *e);
-
 	int scrollWidth() const;
 	int scrollHeight() const;
 	int scrollLeftMax() const;
@@ -190,13 +181,22 @@ public:
 
 	void updateColors(const style::color &bar, const style::color &bg, const style::color &barOver, const style::color &bgOver);
 
-	bool focusNextPrevChild(bool next);
+	bool focusNextPrevChild(bool next) override;
 	void setMovingByScrollBar(bool movingByScrollBar);
 
+	bool viewportEvent(QEvent *e) override;
+	void keyPressEvent(QKeyEvent *e) override;
+
 	~ScrollArea();
 
 protected:
 
+	bool eventFilter(QObject *obj, QEvent *e) override;
+
+	void resizeEvent(QResizeEvent *e) override;
+	void moveEvent(QMoveEvent *e) override;
+	void touchEvent(QTouchEvent *e);
+
 	void enterEventHook(QEvent *e);
 	void leaveEventHook(QEvent *e);
 
@@ -223,7 +223,7 @@ signals:
 
 protected:
 
-	void scrollContentsBy(int dx, int dy);
+	void scrollContentsBy(int dx, int dy) override;
 
 private:
 
diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h
index 99413ba2f..ae15bd5f9 100644
--- a/Telegram/SourceFiles/window/main_window.h
+++ b/Telegram/SourceFiles/window/main_window.h
@@ -26,10 +26,13 @@ class MainWindow : public QMainWindow {
 public:
 	MainWindow();
 
+	virtual void closeWithoutDestroy();
+
 	virtual ~MainWindow();
 
 protected:
-	virtual void closeWithoutDestroy();
+	virtual void stateChangedHook(Qt::WindowState state) {
+	}
 
 };
 
diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj
index 3540524c0..9eb17fbb6 100644
--- a/Telegram/Telegram.xcodeproj/project.pbxproj
+++ b/Telegram/Telegram.xcodeproj/project.pbxproj
@@ -181,6 +181,9 @@
 		07DE92AA1AA4928200A18F6F /* moc_autolockbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07DE92A91AA4928200A18F6F /* moc_autolockbox.cpp */; };
 		07DE92AD1AA4928B00A18F6F /* moc_passcodebox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07DE92AB1AA4928B00A18F6F /* moc_passcodebox.cpp */; };
 		07DE92AE1AA4928B00A18F6F /* moc_passcodewidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07DE92AC1AA4928B00A18F6F /* moc_passcodewidget.cpp */; };
+		07E1B1911D12DB3F00722BC7 /* main_window_mac.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07E1B1901D12DB3F00722BC7 /* main_window_mac.mm */; };
+		07E1B1931D12DED700722BC7 /* moc_main_window_mac.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07E1B1921D12DED700722BC7 /* moc_main_window_mac.cpp */; };
+		07E1B1961D12DFD200722BC7 /* main_window.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07E1B1941D12DFD200722BC7 /* main_window.cpp */; };
 		07E373941CBBC11000934F77 /* peer_avatar_button.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07E373921CBBC11000934F77 /* peer_avatar_button.cpp */; };
 		0CB7DE9A54CC9BF86FB7B5CA /* facade.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 6D50D70712776D7ED3B00E5C /* facade.cpp */; settings = {ATTRIBUTES = (); }; };
 		0F7872E39EA570249D420912 /* moc_introwidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = A37C7E516201B0264A4CDA38 /* moc_introwidget.cpp */; settings = {ATTRIBUTES = (); }; };
@@ -631,6 +634,26 @@
 		07DE92A91AA4928200A18F6F /* moc_autolockbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_autolockbox.cpp; path = GeneratedFiles/Debug/moc_autolockbox.cpp; sourceTree = SOURCE_ROOT; };
 		07DE92AB1AA4928B00A18F6F /* moc_passcodebox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_passcodebox.cpp; path = GeneratedFiles/Debug/moc_passcodebox.cpp; sourceTree = SOURCE_ROOT; };
 		07DE92AC1AA4928B00A18F6F /* moc_passcodewidget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_passcodewidget.cpp; path = GeneratedFiles/Debug/moc_passcodewidget.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B1781D12DAF100722BC7 /* platform_main_window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform_main_window.h; path = SourceFiles/platform/platform_main_window.h; sourceTree = SOURCE_ROOT; };
+		07E1B1791D12DB0700722BC7 /* main_window_win.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main_window_win.cpp; path = SourceFiles/platform/win/main_window_win.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B17A1D12DB0700722BC7 /* main_window_win.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main_window_win.h; path = SourceFiles/platform/win/main_window_win.h; sourceTree = SOURCE_ROOT; };
+		07E1B17B1D12DB0700722BC7 /* windows_app_user_model_id.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = windows_app_user_model_id.cpp; path = SourceFiles/platform/win/windows_app_user_model_id.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B17C1D12DB0700722BC7 /* windows_app_user_model_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = windows_app_user_model_id.h; path = SourceFiles/platform/win/windows_app_user_model_id.h; sourceTree = SOURCE_ROOT; };
+		07E1B17D1D12DB0700722BC7 /* windows_dlls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = windows_dlls.cpp; path = SourceFiles/platform/win/windows_dlls.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B17E1D12DB0700722BC7 /* windows_dlls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = windows_dlls.h; path = SourceFiles/platform/win/windows_dlls.h; sourceTree = SOURCE_ROOT; };
+		07E1B17F1D12DB0700722BC7 /* windows_event_filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = windows_event_filter.cpp; path = SourceFiles/platform/win/windows_event_filter.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B1801D12DB0700722BC7 /* windows_event_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = windows_event_filter.h; path = SourceFiles/platform/win/windows_event_filter.h; sourceTree = SOURCE_ROOT; };
+		07E1B1811D12DB0700722BC7 /* windows_toasts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = windows_toasts.cpp; path = SourceFiles/platform/win/windows_toasts.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B1821D12DB0700722BC7 /* windows_toasts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = windows_toasts.h; path = SourceFiles/platform/win/windows_toasts.h; sourceTree = SOURCE_ROOT; };
+		07E1B1891D12DB2900722BC7 /* main_window_winrt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main_window_winrt.cpp; path = SourceFiles/platform/winrt/main_window_winrt.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B18A1D12DB2900722BC7 /* main_window_winrt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main_window_winrt.h; path = SourceFiles/platform/winrt/main_window_winrt.h; sourceTree = SOURCE_ROOT; };
+		07E1B18C1D12DB3500722BC7 /* main_window_linux.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main_window_linux.cpp; path = SourceFiles/platform/linux/main_window_linux.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B18D1D12DB3500722BC7 /* main_window_linux.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main_window_linux.h; path = SourceFiles/platform/linux/main_window_linux.h; sourceTree = SOURCE_ROOT; };
+		07E1B18F1D12DB3F00722BC7 /* main_window_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main_window_mac.h; path = SourceFiles/platform/mac/main_window_mac.h; sourceTree = SOURCE_ROOT; };
+		07E1B1901D12DB3F00722BC7 /* main_window_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = main_window_mac.mm; path = SourceFiles/platform/mac/main_window_mac.mm; sourceTree = SOURCE_ROOT; };
+		07E1B1921D12DED700722BC7 /* moc_main_window_mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_main_window_mac.cpp; path = GeneratedFiles/Debug/moc_main_window_mac.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B1941D12DFD200722BC7 /* main_window.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main_window.cpp; path = SourceFiles/window/main_window.cpp; sourceTree = SOURCE_ROOT; };
+		07E1B1951D12DFD200722BC7 /* main_window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main_window.h; path = SourceFiles/window/main_window.h; sourceTree = SOURCE_ROOT; };
 		07E373921CBBC11000934F77 /* peer_avatar_button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = peer_avatar_button.cpp; path = SourceFiles/ui/buttons/peer_avatar_button.cpp; sourceTree = SOURCE_ROOT; };
 		07E373931CBBC11000934F77 /* peer_avatar_button.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = peer_avatar_button.h; path = SourceFiles/ui/buttons/peer_avatar_button.h; sourceTree = SOURCE_ROOT; };
 		08A7682548FB7E671FF03822 /* boxshadow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = boxshadow.cpp; path = SourceFiles/ui/boxshadow.cpp; sourceTree = "<absolute>"; };
@@ -1076,6 +1099,8 @@
 		076B1C581CBFC8DF002C0BC2 /* window */ = {
 			isa = PBXGroup;
 			children = (
+				07E1B1941D12DFD200722BC7 /* main_window.cpp */,
+				07E1B1951D12DFD200722BC7 /* main_window.h */,
 				0716C97B1D058F2400797B22 /* section_memento.h */,
 				0716C97C1D058F2400797B22 /* section_widget.cpp */,
 				0716C97D1D058F2400797B22 /* section_widget.h */,
@@ -1176,6 +1201,62 @@
 			name = toast;
 			sourceTree = "<group>";
 		};
+		07E1B1731D12DAC000722BC7 /* platform */ = {
+			isa = PBXGroup;
+			children = (
+				07E1B1751D12DACB00722BC7 /* linux */,
+				07E1B1761D12DAD100722BC7 /* mac */,
+				07E1B1771D12DAD700722BC7 /* win */,
+				07E1B1881D12DB1500722BC7 /* winrt */,
+				07E1B1781D12DAF100722BC7 /* platform_main_window.h */,
+			);
+			name = platform;
+			sourceTree = "<group>";
+		};
+		07E1B1751D12DACB00722BC7 /* linux */ = {
+			isa = PBXGroup;
+			children = (
+				07E1B18C1D12DB3500722BC7 /* main_window_linux.cpp */,
+				07E1B18D1D12DB3500722BC7 /* main_window_linux.h */,
+			);
+			name = linux;
+			sourceTree = "<group>";
+		};
+		07E1B1761D12DAD100722BC7 /* mac */ = {
+			isa = PBXGroup;
+			children = (
+				07E1B18F1D12DB3F00722BC7 /* main_window_mac.h */,
+				07E1B1901D12DB3F00722BC7 /* main_window_mac.mm */,
+			);
+			name = mac;
+			sourceTree = "<group>";
+		};
+		07E1B1771D12DAD700722BC7 /* win */ = {
+			isa = PBXGroup;
+			children = (
+				07E1B1791D12DB0700722BC7 /* main_window_win.cpp */,
+				07E1B17A1D12DB0700722BC7 /* main_window_win.h */,
+				07E1B17B1D12DB0700722BC7 /* windows_app_user_model_id.cpp */,
+				07E1B17C1D12DB0700722BC7 /* windows_app_user_model_id.h */,
+				07E1B17D1D12DB0700722BC7 /* windows_dlls.cpp */,
+				07E1B17E1D12DB0700722BC7 /* windows_dlls.h */,
+				07E1B17F1D12DB0700722BC7 /* windows_event_filter.cpp */,
+				07E1B1801D12DB0700722BC7 /* windows_event_filter.h */,
+				07E1B1811D12DB0700722BC7 /* windows_toasts.cpp */,
+				07E1B1821D12DB0700722BC7 /* windows_toasts.h */,
+			);
+			name = win;
+			sourceTree = "<group>";
+		};
+		07E1B1881D12DB1500722BC7 /* winrt */ = {
+			isa = PBXGroup;
+			children = (
+				07E1B1891D12DB2900722BC7 /* main_window_winrt.cpp */,
+				07E1B18A1D12DB2900722BC7 /* main_window_winrt.h */,
+			);
+			name = winrt;
+			sourceTree = "<group>";
+		};
 		07E373901CBBBFDE00934F77 /* buttons */ = {
 			isa = PBXGroup;
 			children = (
@@ -1316,6 +1397,7 @@
 				5E35A03E5F2C51353EBCBF00 /* intro */,
 				1A6AA22F4A758C4B5F5138FB /* mtproto */,
 				076B1C5C1CBFC97D002C0BC2 /* overview */,
+				07E1B1731D12DAC000722BC7 /* platform */,
 				0716C92C1D05898D00797B22 /* profile */,
 				0702E99F1CB8D290007A7495 /* serialize */,
 				579DA7AEF5751DF4988869A0 /* ui */,
@@ -1453,6 +1535,7 @@
 				1FE45A67215BEA2434F588E8 /* moc_layerwidget.cpp */,
 				1D7899ACAA9F973CADFA34C1 /* moc_localimageloader.cpp */,
 				07BE85111A20961F008ACB9F /* moc_localstorage.cpp */,
+				07E1B1921D12DED700722BC7 /* moc_main_window_mac.cpp */,
 				3A220FD1AE5AD9FE3DC073A4 /* moc_mainwidget.cpp */,
 				6B46A0EE3C3B9D3B5A24946E /* moc_mainwindow.cpp */,
 				07A6933419927B160099CB9F /* moc_mediaview.cpp */,
@@ -1835,6 +1918,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				07E1B1911D12DB3F00722BC7 /* main_window_mac.mm in Compile Sources */,
 				1299DDAE203A7EDFED9F5D6B /* main.cpp in Compile Sources */,
 				D87463318C8E5211C8C8670A /* stdafx.cpp in Compile Sources */,
 				7BEFA1D273AD62772AA33D73 /* app.cpp in Compile Sources */,
@@ -1872,6 +1956,7 @@
 				0716C97A1D058C8600797B22 /* moc_report_box.cpp in Compile Sources */,
 				077A4AF81CA41C38002188D2 /* connection_auto.cpp in Compile Sources */,
 				4078D5D614EB3ECF7F1848C7 /* basic_types.cpp in Compile Sources */,
+				07E1B1931D12DED700722BC7 /* moc_main_window_mac.cpp in Compile Sources */,
 				68FFEB7CA30BF0149161B809 /* mainwindow.cpp in Compile Sources */,
 				0716C9831D05931400797B22 /* moc_section_widget.cpp in Compile Sources */,
 				0CB7DE9A54CC9BF86FB7B5CA /* facade.cpp in Compile Sources */,
@@ -2045,6 +2130,7 @@
 				074968D01A44D14C00394F46 /* languagebox.cpp in Compile Sources */,
 				077A4AF91CA41C38002188D2 /* connection_http.cpp in Compile Sources */,
 				07BE85121A20961F008ACB9F /* moc_localstorage.cpp in Compile Sources */,
+				07E1B1961D12DFD200722BC7 /* main_window.cpp in Compile Sources */,
 				07AF95F41AFD03B90060B057 /* qrc_telegram_emojis.cpp in Compile Sources */,
 				07C759721B1F7E2800662169 /* moc_autoupdater.cpp in Compile Sources */,
 				0716C9601D058C6600797B22 /* style_profile.cpp in Compile Sources */,
diff --git a/Telegram/Telegram.xcodeproj/qt_preprocess.mak b/Telegram/Telegram.xcodeproj/qt_preprocess.mak
index cbf445390..5d7ef7490 100644
--- a/Telegram/Telegram.xcodeproj/qt_preprocess.mak
+++ b/Telegram/Telegram.xcodeproj/qt_preprocess.mak
@@ -95,6 +95,7 @@ compilers: GeneratedFiles/qrc_telegram.cpp\
 	 GeneratedFiles/Debug/moc_layerwidget.cpp\
 	 GeneratedFiles/Debug/moc_localimageloader.cpp\
 	 GeneratedFiles/Debug/moc_localstorage.cpp\
+	 GeneratedFiles/Debug/moc_main_window_mac.cpp\
 	 GeneratedFiles/Debug/moc_mainwidget.cpp\
 	 GeneratedFiles/Debug/moc_mainwindow.cpp\
 	 GeneratedFiles/Debug/moc_mediaview.cpp\
@@ -114,7 +115,6 @@ compilers: GeneratedFiles/qrc_telegram.cpp\
 	 GeneratedFiles/Debug/moc_profile_settings_widget.cpp\
 	 GeneratedFiles/Debug/moc_profile_shared_media_widget.cpp\
 	 GeneratedFiles/Debug/moc_profile_widget.cpp\
-	 GeneratedFiles/Debug/moc_pspecific_mac.cpp\
 	 GeneratedFiles/Debug/moc_report_box.cpp\
 	 GeneratedFiles/Debug/moc_scrollarea.cpp\
 	 GeneratedFiles/Debug/moc_section_widget.cpp\
@@ -232,6 +232,7 @@ compiler_moc_header_make_all: GeneratedFiles/Debug/moc_aboutbox.cpp\
 	 GeneratedFiles/Debug/moc_layerwidget.cpp\
 	 GeneratedFiles/Debug/moc_localimageloader.cpp\
 	 GeneratedFiles/Debug/moc_localstorage.cpp\
+	 GeneratedFiles/Debug/moc_main_window_mac.cpp\
 	 GeneratedFiles/Debug/moc_mainwidget.cpp\
 	 GeneratedFiles/Debug/moc_mainwindow.cpp\
 	 GeneratedFiles/Debug/moc_mediaview.cpp\
@@ -251,7 +252,6 @@ compiler_moc_header_make_all: GeneratedFiles/Debug/moc_aboutbox.cpp\
 	 GeneratedFiles/Debug/moc_profile_settings_widget.cpp\
 	 GeneratedFiles/Debug/moc_profile_shared_media_widget.cpp\
 	 GeneratedFiles/Debug/moc_profile_widget.cpp\
-	 GeneratedFiles/Debug/moc_pspecific_mac.cpp\
 	 GeneratedFiles/Debug/moc_report_box.cpp\
 	 GeneratedFiles/Debug/moc_scrollarea.cpp\
 	 GeneratedFiles/Debug/moc_section_widget.cpp\
@@ -312,6 +312,7 @@ compiler_moc_header_clean:
 	 GeneratedFiles/Debug/moc_layerwidget.cpp\
 	 GeneratedFiles/Debug/moc_localimageloader.cpp\
 	 GeneratedFiles/Debug/moc_localstorage.cpp\
+	 GeneratedFiles/Debug/moc_main_window_mac.cpp\
 	 GeneratedFiles/Debug/moc_mainwidget.cpp\
 	 GeneratedFiles/Debug/moc_mainwindow.cpp\
 	 GeneratedFiles/Debug/moc_mediaview.cpp\
@@ -331,7 +332,6 @@ compiler_moc_header_clean:
 	 GeneratedFiles/Debug/moc_profile_settings_widget.cpp\
 	 GeneratedFiles/Debug/moc_profile_shared_media_widget.cpp\
 	 GeneratedFiles/Debug/moc_profile_widget.cpp\
-	 GeneratedFiles/Debug/moc_pspecific_mac.cpp\
 	 GeneratedFiles/Debug/moc_report_box.cpp\
 	 GeneratedFiles/Debug/moc_scrollarea.cpp\
 	 GeneratedFiles/Debug/moc_section_widget.cpp\
@@ -483,6 +483,9 @@ GeneratedFiles/Debug/moc_localimageloader.cpp: SourceFiles/localimageloader.h
 GeneratedFiles/Debug/moc_localstorage.cpp: SourceFiles/localstorage.h
 	$(MOC_FILE) SourceFiles/localstorage.h -o GeneratedFiles/Debug/moc_localstorage.cpp
 
+GeneratedFiles/Debug/moc_main_window_mac.cpp: SourceFiles/platform/mac/main_window_mac.h
+	$(MOC_FILE) SourceFiles/platform/mac/main_window_mac.h -o GeneratedFiles/Debug/moc_main_window_mac.cpp
+
 GeneratedFiles/Debug/moc_mainwidget.cpp: SourceFiles/mainwidget.h
 	$(MOC_FILE) SourceFiles/mainwidget.h -o GeneratedFiles/Debug/moc_mainwidget.cpp
 
@@ -540,9 +543,6 @@ GeneratedFiles/Debug/moc_profile_shared_media_widget.cpp: SourceFiles/profile/pr
 GeneratedFiles/Debug/moc_profile_widget.cpp: SourceFiles/profile/profile_widget.h
 	$(MOC_FILE) SourceFiles/profile/profile_widget.h -o GeneratedFiles/Debug/moc_profile_widget.cpp
 
-GeneratedFiles/Debug/moc_pspecific_mac.cpp: SourceFiles/pspecific_mac.h
-	$(MOC_FILE) SourceFiles/pspecific_mac.h -o GeneratedFiles/Debug/moc_pspecific_mac.cpp
-
 GeneratedFiles/Debug/moc_report_box.cpp: SourceFiles/boxes/report_box.h
 	$(MOC_FILE) SourceFiles/boxes/report_box.h -o GeneratedFiles/Debug/moc_report_box.cpp