NB Broken! Build in Xcode fixed, macOS notifications done by Manager.

This commit is contained in:
John Preston 2016-10-02 18:44:54 +03:00
parent 0bf55835f5
commit c2aa8d3c77
8 changed files with 508 additions and 377 deletions

View file

@ -0,0 +1,39 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "lang.h"
#include <Cocoa/Cocoa.h>
namespace Platform {
inline NSString *Q2NSString(const QString &str) {
return [NSString stringWithUTF8String:str.toUtf8().constData()];
}
inline NSString *NSlang(LangKey key) {
return Q2NSString(lang(key));
}
inline QString NS2QString(NSString *str) {
return QString::fromUtf8([str cStringUsingEncoding:NSUTF8StringEncoding]);
}
} // namespace Platform

View file

@ -0,0 +1,19 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "platform/mac/mac_utilities.h"

View file

@ -22,25 +22,39 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "platform/mac/notifications_manager_mac.h" #include "platform/mac/notifications_manager_mac.h"
#include "pspecific.h" #include "pspecific.h"
#include "platform/mac/mac_utilities.h"
#include <Cocoa/Cocoa.h>
NSImage *qt_mac_create_nsimage(const QPixmap &pm);
namespace Platform { namespace Platform {
namespace Notifications { namespace Notifications {
namespace {
NeverFreedPointer<Manager> ManagerInstance;
} // namespace
void start() { void start() {
if (cPlatform() != dbipMacOld) {
ManagerInstance.makeIfNull();
}
} }
Window::Notifications::Manager *manager() { Window::Notifications::Manager *manager() {
return nullptr; return ManagerInstance.data();
} }
void finish() { void finish() {
ManagerInstance.clear();
} }
void defaultNotificationShown(QWidget *widget) { void defaultNotificationShown(QWidget *widget) {
widget->hide(); widget->hide();
objc_holdOnTop(widget->winId()); objc_holdOnTop(widget->winId());
widget->show(); widget->show();
psShowOverAll(w, false); psShowOverAll(widget, false);
} }
class Manager::Impl { class Manager::Impl {
@ -56,18 +70,23 @@ private:
}; };
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) { void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, bool showUserpic, const QString &msg, bool showReplyButton) {
auto notification = [[NSUserNotification alloc] init]; @autoreleasepool {
NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease];
if ([notification respondsToSelector:@selector(setIdentifier:)]) {
auto identifier = QString::number(Global::LaunchId()) + '_' + QString::number(peer->id) + '_' + QString::number(msgId);
auto identifierValue = Q2NSString(identifier);
[notification setIdentifier:identifierValue];
}
[notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer->id],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:Global::LaunchId()],@"launch",nil]]; [notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer->id],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:Global::LaunchId()],@"launch",nil]];
[notification setTitle:QNSString(title).s()]; [notification setTitle:Q2NSString(title)];
[notification setSubtitle:QNSString(subtitle).s()]; [notification setSubtitle:Q2NSString(subtitle)];
[notification setInformativeText:QNSString(msg).s()]; [notification setInformativeText:Q2NSString(msg)];
if (showUserpic && [notification respondsToSelector:@selector(setContentImage:)]) { if (showUserpic && [notification respondsToSelector:@selector(setContentImage:)]) {
auto userpic = peer->genUserpic(st::notifyMacPhotoSize); auto userpic = peer->genUserpic(st::notifyMacPhotoSize);
auto img = qt_mac_create_nsimage(userpic); NSImage *img = [qt_mac_create_nsimage(userpic) autorelease];
[notification setContentImage:img]; [notification setContentImage:img];
[img release];
} }
if (showReplyButton && [notification respondsToSelector:@selector(setHasReplyButton:)]) { if (showReplyButton && [notification respondsToSelector:@selector(setHasReplyButton:)]) {
@ -76,24 +95,32 @@ void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString
[notification setSoundName:nil]; [notification setSoundName:nil];
auto center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center deliverNotification:notification]; [center deliverNotification:notification];
[notification release]; }
} }
void Manager::Impl::clearAll() { void Manager::Impl::clearAll() {
auto center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
NSArray *notificationsList = [center deliveredNotifications];
for (id notify in notificationsList) {
NSDictionary *notifyUserInfo = [notify userInfo];
auto notifyLaunchId = [[notifyUserInfo objectForKey:@"launch"] unsignedLongLongValue];
if (notifyLaunchId == Global::LaunchId()) {
[center removeDeliveredNotification:notify];
}
}
[center removeAllDeliveredNotifications]; [center removeAllDeliveredNotifications];
} }
void Manager::Impl::clearFromHistory(History *history) { void Manager::Impl::clearFromHistory(History *history) {
unsigned long long peerId = history->peer->id; unsigned long long peerId = history->peer->id;
auto center = [NSUserNotificationCenter defaultUserNotificationCenter]; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
auto notificationsList = [center deliveredNotifications]; NSArray *notificationsList = [center deliveredNotifications];
for (id notify in notificationsList) { for (id notify in notificationsList) {
auto notifyUserInfo = [notify userInfo]; NSDictionary *notifyUserInfo = [notify userInfo];
auto notifyPeerId = [[notifyUserInfo objectForKey:@"peer"] unsignedLongLongValue]; auto notifyPeerId = [[notifyUserInfo objectForKey:@"peer"] unsignedLongLongValue];
auto notifyLaunchId = [[notifyUserInfo objectForKey:@"launch"] unsignedLongLongValue]; auto notifyLaunchId = [[notifyUserInfo objectForKey:@"launch"] unsignedLongLongValue];
if (notifyPeerId == peerId && notifyLaunchId == Global::LaunchId()) { if (notifyPeerId == peerId && notifyLaunchId == Global::LaunchId()) {
@ -102,6 +129,9 @@ void Manager::Impl::clearFromHistory(History *history) {
} }
} }
Manager::Impl::~Impl() {
}
Manager::Manager() : _impl(std_::make_unique<Impl>()) { Manager::Manager() : _impl(std_::make_unique<Impl>()) {
} }

View file

@ -50,7 +50,7 @@ namespace {
// Delete notify photo file after 1 minute of not using. // Delete notify photo file after 1 minute of not using.
constexpr int kNotifyDeletePhotoAfterMs = 60000; constexpr int kNotifyDeletePhotoAfterMs = 60000;
NeverFreedPointer<Manager> ToastsManager; NeverFreedPointer<Manager> ManagerInstance;
ComPtr<IToastNotificationManagerStatics> _notificationManager; ComPtr<IToastNotificationManagerStatics> _notificationManager;
ComPtr<IToastNotifier> _notifier; ComPtr<IToastNotifier> _notifier;
@ -361,7 +361,7 @@ QString getImage(const StorageKey &key, PeerData *peer) {
if (i != _images.cend()) { if (i != _images.cend()) {
if (i->until) { if (i->until) {
i->until = ms + kNotifyDeletePhotoAfterMs; i->until = ms + kNotifyDeletePhotoAfterMs;
if (auto manager = ToastsManager.data()) { if (auto manager = ManagerInstance.data()) {
manager->clearNotifyPhotosInMs(-kNotifyDeletePhotoAfterMs); manager->clearNotifyPhotosInMs(-kNotifyDeletePhotoAfterMs);
} }
} }
@ -369,7 +369,7 @@ QString getImage(const StorageKey &key, PeerData *peer) {
Image v; Image v;
if (key.first) { if (key.first) {
v.until = ms + kNotifyDeletePhotoAfterMs; v.until = ms + kNotifyDeletePhotoAfterMs;
if (auto manager = ToastsManager.data()) { if (auto manager = ManagerInstance.data()) {
manager->clearNotifyPhotosInMs(-kNotifyDeletePhotoAfterMs); manager->clearNotifyPhotosInMs(-kNotifyDeletePhotoAfterMs);
} }
} else { } else {
@ -391,16 +391,16 @@ QString getImage(const StorageKey &key, PeerData *peer) {
void start() { void start() {
if (init()) { if (init()) {
ToastsManager.makeIfNull(); ManagerInstance.makeIfNull();
} }
} }
Manager *manager() { Manager *manager() {
return ToastsManager.data(); return ManagerInstance.data();
} }
void finish() { void finish() {
ToastsManager.reset(); ManagerInstance.clear();
} }
uint64 clearImages(uint64 ms) { uint64 clearImages(uint64 ms) {

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "application.h" #include "application.h"
#include "playerwidget.h" #include "playerwidget.h"
#include "localstorage.h" #include "localstorage.h"
#include "platform/mac/mac_utilities.h"
#include "lang.h" #include "lang.h"
@ -32,6 +33,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include <IOKit/hidsystem/ev_keymap.h> #include <IOKit/hidsystem/ev_keymap.h>
using Platform::Q2NSString;
using Platform::NSlang;
using Platform::NS2QString;
@interface qVisualize : NSObject { @interface qVisualize : NSObject {
} }
@ -104,24 +109,6 @@ ApplicationDelegate *_sharedDelegate = nil;
@end @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 { @interface ObserverHelper : NSObject {
} }
@ -241,14 +228,22 @@ public:
@end @end
PsMacWindowPrivate::PsMacWindowPrivate() : data(new PsMacWindowData(this)) { PsMacWindowPrivate::PsMacWindowPrivate() : data(new PsMacWindowData(this)) {
@autoreleasepool {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:data->observerHelper selector:@selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil]; [[[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]; [[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(darkModeChanged:) name:Q2NSString(strNotificationAboutThemeChange()) object:nil];
[[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(screenIsLocked:) name:QNSString(strNotificationAboutScreenLocked()).s() object:nil]; [[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(screenIsLocked:) name:Q2NSString(strNotificationAboutScreenLocked()) object:nil];
[[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(screenIsUnlocked:) name:QNSString(strNotificationAboutScreenUnlocked()).s() object:nil]; [[NSDistributedNotificationCenter defaultCenter] addObserver:data->observerHelper selector:@selector(screenIsUnlocked:) name:Q2NSString(strNotificationAboutScreenUnlocked()) object:nil];
}
} }
void PsMacWindowPrivate::setWindowBadge(const QString &str) { void PsMacWindowPrivate::setWindowBadge(const QString &str) {
[[NSApp dockTile] setBadgeLabel:QNSString(str).s()]; @autoreleasepool {
[[NSApp dockTile] setBadgeLabel:Q2NSString(str)];
}
} }
void PsMacWindowPrivate::startBounce() { void PsMacWindowPrivate::startBounce() {
@ -266,10 +261,16 @@ void objc_holdOnTop(WId winId) {
} }
bool objc_darkMode() { bool objc_darkMode() {
bool result = false;
@autoreleasepool {
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain]; NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
id style = [dict objectForKey:QNSString(strStyleOfInterface()).s()]; id style = [dict objectForKey:Q2NSString(strStyleOfInterface())];
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; result = darkModeOn ? true : false;
}
return result;
} }
void objc_showOverAll(WId winId, bool canFocus) { void objc_showOverAll(WId winId, bool canFocus) {
@ -291,8 +292,6 @@ void objc_activateWnd(WId winId) {
[wnd orderFront:wnd]; [wnd orderFront:wnd];
} }
NSImage *qt_mac_create_nsimage(const QPixmap &pm);
void PsMacWindowPrivate::enableShadow(WId winId) { void PsMacWindowPrivate::enableShadow(WId winId) {
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask]; // [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
// [[(NSView*)winId window] setHasShadow:YES]; // [[(NSView*)winId window] setHasShadow:YES];
@ -333,11 +332,19 @@ bool PsMacWindowPrivate::filterNativeEvent(void *event) {
} }
void objc_debugShowAlert(const QString &str) { void objc_debugShowAlert(const QString &str) {
[[NSAlert alertWithMessageText:@"Debug Message" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", QNSString(str).s()] runModal]; @autoreleasepool {
[[NSAlert alertWithMessageText:@"Debug Message" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", Q2NSString(str)] runModal];
}
} }
void objc_outputDebugString(const QString &str) { void objc_outputDebugString(const QString &str) {
NSLog(@"%@", QNSString(str).s()); @autoreleasepool {
NSLog(@"%@", Q2NSString(str));
}
} }
PsMacWindowPrivate::~PsMacWindowPrivate() { PsMacWindowPrivate::~PsMacWindowPrivate() {
@ -468,7 +475,7 @@ bool objc_idleTime(int64 &idleTime) { // taken from https://github.com/trueinter
} }
- (id) init:(NSString*)file { - (id) init:(NSString*)file {
toOpen = file; toOpen = [file retain];
if (self = [super init]) { if (self = [super init]) {
NSURL *url = [NSURL fileURLWithPath:file]; NSURL *url = [NSURL fileURLWithPath:file];
defUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:url]; defUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:url];
@ -553,7 +560,7 @@ bool objc_idleTime(int64 &idleTime) { // taken from https://github.com/trueinter
} }
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
} }
NSMenuItem *item = [menu insertItemWithTitle:objc_lang(lng_mac_choose_program_menu).s() action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++]; NSMenuItem *item = [menu insertItemWithTitle:NSlang(lng_mac_choose_program_menu) action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
[item setTarget:self]; [item setTarget:self];
[menu popUpMenuPositioningItem:nil atLocation:CGPointMake(x, y) inView:nil]; [menu popUpMenuPositioningItem:nil atLocation:CGPointMake(x, y) inView:nil];
@ -578,22 +585,24 @@ bool objc_idleTime(int64 &idleTime) { // taken from https://github.com/trueinter
if (url) { if (url) {
[[NSWorkspace sharedWorkspace] openFile:toOpen withApplication:[url path]]; [[NSWorkspace sharedWorkspace] openFile:toOpen withApplication:[url path]];
} else { } else {
objc_openFile(objcString(toOpen), true); objc_openFile(NS2QString(toOpen), true);
} }
} }
- (void) dealloc { - (void) dealloc {
if (apps) [apps release]; [toOpen release];
[super dealloc];
if (menu) [menu release]; if (menu) [menu release];
[super dealloc];
} }
@end @end
bool objc_showOpenWithMenu(int x, int y, const QString &f) { bool objc_showOpenWithMenu(int x, int y, const QString &f) {
NSString *file = QNSString(f).s(); @autoreleasepool {
NSString *file = Q2NSString(f);
@try { @try {
OpenFileWithInterface *menu = [[OpenFileWithInterface alloc] init:file]; OpenFileWithInterface *menu = [[[OpenFileWithInterface alloc] init:file] autorelease];
QRect r = QApplication::desktop()->screenGeometry(QPoint(x, y)); QRect r = QApplication::desktop()->screenGeometry(QPoint(x, y));
y = r.y() + r.height() - y; y = r.y() + r.height() - y;
return !![menu popupAtX:x andY:y]; return !![menu popupAtX:x andY:y];
@ -601,12 +610,18 @@ bool objc_showOpenWithMenu(int x, int y, const QString &f) {
@catch (NSException *exception) { @catch (NSException *exception) {
} }
@finally { @finally {
}
} }
return false; return false;
} }
void objc_showInFinder(const QString &file, const QString &path) { void objc_showInFinder(const QString &file, const QString &path) {
[[NSWorkspace sharedWorkspace] selectFile:QNSString(file).s() inFileViewerRootedAtPath:QNSString(path).s()]; @autoreleasepool {
[[NSWorkspace sharedWorkspace] selectFile:Q2NSString(file) inFileViewerRootedAtPath:Q2NSString(path)];
}
} }
@interface NSURL(CompareUrls) @interface NSURL(CompareUrls)
@ -654,7 +669,7 @@ void objc_showInFinder(const QString &file, const QString &path) {
- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc { - (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]) { if (self = [super init]) {
onlyRecommended = YES; onlyRecommended = YES;
recom = [objc_lang(lng_mac_recommended_apps).s() copy]; recom = [NSlang(lng_mac_recommended_apps) copy];
apps = recommendedApps; apps = recommendedApps;
panel = creator; panel = creator;
selector = menu; selector = menu;
@ -720,9 +735,9 @@ void objc_showInFinder(const QString &file, const QString &path) {
- (BOOL) refreshDataInViews: (NSArray*)subviews { - (BOOL) refreshDataInViews: (NSArray*)subviews {
for (id view in subviews) { for (id view in subviews) {
NSString *cls = [view className]; NSString *cls = [view className];
if ([cls isEqualToString:QNSString(strNeedToReload()).s()]) { if ([cls isEqualToString:Q2NSString(strNeedToReload())]) {
[view reloadData]; [view reloadData];
} else if ([cls isEqualToString:QNSString(strNeedToRefresh1()).s()] || [cls isEqualToString:QNSString(strNeedToRefresh2()).s()]) { } else if ([cls isEqualToString:Q2NSString(strNeedToRefresh1())] || [cls isEqualToString:Q2NSString(strNeedToRefresh2())]) {
[view reloadData]; [view reloadData];
return YES; return YES;
} else { } else {
@ -732,14 +747,17 @@ void objc_showInFinder(const QString &file, const QString &path) {
} }
} }
} }
return NO; return NO;
} }
- (void) refreshPanelTable { - (void) refreshPanelTable {
@autoreleasepool {
[self refreshDataInViews:[[panel contentView] subviews]]; [self refreshDataInViews:[[panel contentView] subviews]];
[panel validateVisibleColumns]; [panel validateVisibleColumns];
}
} }
- (void) dealloc { - (void) dealloc {
@ -753,12 +771,14 @@ void objc_showInFinder(const QString &file, const QString &path) {
@end @end
void objc_openFile(const QString &f, bool openwith) { void objc_openFile(const QString &f, bool openwith) {
NSString *file = QNSString(f).s(); @autoreleasepool {
NSString *file = Q2NSString(f);
if (openwith || [[NSWorkspace sharedWorkspace] openFile:file] == NO) { if (openwith || [[NSWorkspace sharedWorkspace] openFile:file] == NO) {
@try { @try {
NSURL *url = [NSURL fileURLWithPath:file]; NSURL *url = [NSURL fileURLWithPath:file];
NSString *ext = [url pathExtension]; NSString *ext = [url pathExtension];
NSArray *names =[url pathComponents]; NSArray *names = [url pathComponents];
NSString *name = [names count] ? [names lastObject] : @""; NSString *name = [names count] ? [names lastObject] : @"";
NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll); NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
@ -771,13 +791,13 @@ void objc_openFile(const QString &f, bool openwith) {
NSPopUpButton *selector = [[NSPopUpButton alloc] init]; NSPopUpButton *selector = [[NSPopUpButton alloc] init];
[accessory addSubview:selector]; [accessory addSubview:selector];
[selector addItemWithTitle:objc_lang(lng_mac_recommended_apps).s()]; [selector addItemWithTitle:NSlang(lng_mac_recommended_apps)];
[selector addItemWithTitle:objc_lang(lng_mac_all_apps).s()]; [selector addItemWithTitle:NSlang(lng_mac_all_apps)];
[selector sizeToFit]; [selector sizeToFit];
NSTextField *enableLabel = [[NSTextField alloc] init]; NSTextField *enableLabel = [[NSTextField alloc] init];
[accessory addSubview:enableLabel]; [accessory addSubview:enableLabel];
[enableLabel setStringValue:objc_lang(lng_mac_enable_filter).s()]; [enableLabel setStringValue:NSlang(lng_mac_enable_filter)];
[enableLabel setFont:[selector font]]; [enableLabel setFont:[selector font]];
[enableLabel setBezeled:NO]; [enableLabel setBezeled:NO];
[enableLabel setDrawsBackground:NO]; [enableLabel setDrawsBackground:NO];
@ -800,7 +820,7 @@ void objc_openFile(const QString &f, bool openwith) {
[accessory addSubview:button]; [accessory addSubview:button];
[button setButtonType:NSSwitchButton]; [button setButtonType:NSSwitchButton];
[button setFont:[selector font]]; [button setFont:[selector font]];
[button setTitle:objc_lang(lng_mac_always_open_with).s()]; [button setTitle:NSlang(lng_mac_always_open_with)];
[button sizeToFit]; [button sizeToFit];
NSRect alwaysRect = [button frame]; NSRect alwaysRect = [button frame];
alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2; alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2;
@ -811,7 +831,7 @@ void objc_openFile(const QString &f, bool openwith) {
[button setHidden:YES]; [button setHidden:YES];
#endif // OS_MAC_STORE #endif // OS_MAC_STORE
NSTextField *goodLabel = [[NSTextField alloc] init]; NSTextField *goodLabel = [[NSTextField alloc] init];
[goodLabel setStringValue:QNSString(lng_mac_this_app_can_open(lt_file, objcString(name))).s()]; [goodLabel setStringValue:Q2NSString(lng_mac_this_app_can_open(lt_file, NS2QString(name)))];
[goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
[goodLabel setBezeled:NO]; [goodLabel setBezeled:NO];
[goodLabel setDrawsBackground:NO]; [goodLabel setDrawsBackground:NO];
@ -824,7 +844,7 @@ void objc_openFile(const QString &f, bool openwith) {
[goodLabel setFrame:goodFrame]; [goodLabel setFrame:goodFrame];
NSTextField *badLabel = [[NSTextField alloc] init]; NSTextField *badLabel = [[NSTextField alloc] init];
[badLabel setStringValue:QNSString(lng_mac_not_known_app(lt_file, objcString(name))).s()]; [badLabel setStringValue:Q2NSString(lng_mac_not_known_app(lt_file, NS2QString(name)))];
[badLabel setFont:[goodLabel font]]; [badLabel setFont:[goodLabel font]];
[badLabel setBezeled:NO]; [badLabel setBezeled:NO];
[badLabel setDrawsBackground:NO]; [badLabel setDrawsBackground:NO];
@ -853,8 +873,8 @@ void objc_openFile(const QString &f, bool openwith) {
[openPanel setCanChooseFiles:YES]; [openPanel setCanChooseFiles:YES];
[openPanel setAllowsMultipleSelection:NO]; [openPanel setAllowsMultipleSelection:NO];
[openPanel setResolvesAliases:YES]; [openPanel setResolvesAliases:YES];
[openPanel setTitle:objc_lang(lng_mac_choose_app).s()]; [openPanel setTitle:NSlang(lng_mac_choose_app)];
[openPanel setMessage:QNSString(lng_mac_choose_text(lt_file, objcString(name))).s()]; [openPanel setMessage:Q2NSString(lng_mac_choose_text(lt_file, NS2QString(name)))];
NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask]; NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask];
if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]]; if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]];
@ -871,7 +891,7 @@ void objc_openFile(const QString &f, bool openwith) {
OSStatus result = LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI, OSStatus result = LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI,
kLSRolesAll, kLSRolesAll,
(CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]); (CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]);
DEBUG_LOG(("App Info: set default handler for '%1' UTI result: %2").arg(objcString(UTI)).arg(result)); DEBUG_LOG(("App Info: set default handler for '%1' UTI result: %2").arg(NS2QString(UTI)).arg(result));
} }
[UTIs release]; [UTIs release];
@ -895,6 +915,8 @@ void objc_openFile(const QString &f, bool openwith) {
@finally { @finally {
} }
} }
}
} }
void objc_start() { void objc_start() {
@ -925,6 +947,8 @@ void objc_registerCustomScheme() {
} }
BOOL _execUpdater(BOOL update = YES, const QString &crashreport = QString()) { BOOL _execUpdater(BOOL update = YES, const QString &crashreport = QString()) {
@autoreleasepool {
NSString *path = @"", *args = @""; NSString *path = @"", *args = @"";
@try { @try {
path = [[NSBundle mainBundle] bundlePath]; path = [[NSBundle mainBundle] bundlePath];
@ -934,7 +958,7 @@ BOOL _execUpdater(BOOL update = YES, const QString &crashreport = QString()) {
} }
path = [path stringByAppendingString:@"/Contents/Frameworks/Updater"]; path = [path stringByAppendingString:@"/Contents/Frameworks/Updater"];
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-workpath", QNSString(cWorkingDir()).s(), @"-procid", nil]; NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:@"-workpath", Q2NSString(cWorkingDir()), @"-procid", nil];
[args addObject:[NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]]; [args addObject:[NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]];
if (cRestartingToSettings()) [args addObject:@"-tosettings"]; if (cRestartingToSettings()) [args addObject:@"-tosettings"];
if (!update) [args addObject:@"-noupdate"]; if (!update) [args addObject:@"-noupdate"];
@ -944,26 +968,28 @@ BOOL _execUpdater(BOOL update = YES, const QString &crashreport = QString()) {
if (cTestMode()) [args addObject:@"-testmode"]; if (cTestMode()) [args addObject:@"-testmode"];
if (cDataFile() != qsl("data")) { if (cDataFile() != qsl("data")) {
[args addObject:@"-key"]; [args addObject:@"-key"];
[args addObject:QNSString(cDataFile()).s()]; [args addObject:Q2NSString(cDataFile())];
} }
if (!crashreport.isEmpty()) { if (!crashreport.isEmpty()) {
[args addObject:@"-crashreport"]; [args addObject:@"-crashreport"];
[args addObject:QNSString(crashreport).s()]; [args addObject:Q2NSString(crashreport)];
} }
DEBUG_LOG(("Application Info: executing %1 %2").arg(objcString(path)).arg(objcString([args componentsJoinedByString:@" "]))); DEBUG_LOG(("Application Info: executing %1 %2").arg(NS2QString(path)).arg(NS2QString([args componentsJoinedByString:@" "])));
Logs::closeMain(); Logs::closeMain();
SignalHandlers::finish(); SignalHandlers::finish();
if (![NSTask launchedTaskWithLaunchPath:path arguments:args]) { if (![NSTask launchedTaskWithLaunchPath:path arguments:args]) {
DEBUG_LOG(("Task not launched while executing %1 %2").arg(objcString(path)).arg(objcString([args componentsJoinedByString:@" "]))); DEBUG_LOG(("Task not launched while executing %1 %2").arg(NS2QString(path)).arg(NS2QString([args componentsJoinedByString:@" "])));
return NO; return NO;
} }
} }
@catch (NSException *exception) { @catch (NSException *exception) {
LOG(("Exception caught while executing %1 %2").arg(objcString(path)).arg(objcString(args))); LOG(("Exception caught while executing %1 %2").arg(NS2QString(path)).arg(NS2QString(args)));
return NO; return NO;
} }
@finally { @finally {
}
} }
return YES; return YES;
} }
@ -976,8 +1002,12 @@ void objc_execTelegram(const QString &crashreport) {
#ifndef OS_MAC_STORE #ifndef OS_MAC_STORE
_execUpdater(NO, crashreport); _execUpdater(NO, crashreport);
#else // OS_MAC_STORE #else // OS_MAC_STORE
@autoreleasepool {
NSDictionary *conf = [NSDictionary dictionaryWithObject:[NSArray array] forKey:NSWorkspaceLaunchConfigurationArguments]; NSDictionary *conf = [NSDictionary dictionaryWithObject:[NSArray array] forKey:NSWorkspaceLaunchConfigurationArguments];
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:QNSString(cExeDir() + cExeName()).s()] options:NSWorkspaceLaunchAsync | NSWorkspaceLaunchNewInstance configuration:conf error:0]; [[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:Q2NSString(cExeDir() + cExeName())] options:NSWorkspaceLaunchAsync | NSWorkspaceLaunchNewInstance configuration:conf error:0];
}
#endif // OS_MAC_STORE #endif // OS_MAC_STORE
} }
@ -990,7 +1020,9 @@ void objc_activateProgram(WId winId) {
} }
bool objc_moveFile(const QString &from, const QString &to) { bool objc_moveFile(const QString &from, const QString &to) {
NSString *f = QNSString(from).s(), *t = QNSString(to).s(); @autoreleasepool {
NSString *f = Q2NSString(from), *t = Q2NSString(to);
if ([[NSFileManager defaultManager] fileExistsAtPath:t]) { if ([[NSFileManager defaultManager] fileExistsAtPath:t]) {
NSData *data = [NSData dataWithContentsOfFile:f]; NSData *data = [NSData dataWithContentsOfFile:f];
if (data) { if (data) {
@ -1005,11 +1037,17 @@ bool objc_moveFile(const QString &from, const QString &to) {
return true; return true;
} }
} }
}
return false; return false;
} }
void objc_deleteDir(const QString &dir) { void objc_deleteDir(const QString &dir) {
[[NSFileManager defaultManager] removeItemAtPath:QNSString(dir).s() error:nil]; @autoreleasepool {
[[NSFileManager defaultManager] removeItemAtPath:Q2NSString(dir) error:nil];
}
} }
double objc_appkitVersion() { double objc_appkitVersion() {
@ -1043,20 +1081,20 @@ QString objc_downloadPath() {
QString objc_currentCountry() { QString objc_currentCountry() {
NSLocale *currentLocale = [NSLocale currentLocale]; // get the current locale. NSLocale *currentLocale = [NSLocale currentLocale]; // get the current locale.
NSString *countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; NSString *countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
return countryCode ? objcString(countryCode) : QString(); return countryCode ? NS2QString(countryCode) : QString();
} }
QString objc_currentLang() { QString objc_currentLang() {
NSLocale *currentLocale = [NSLocale currentLocale]; // get the current locale. NSLocale *currentLocale = [NSLocale currentLocale]; // get the current locale.
NSString *currentLang = [currentLocale objectForKey:NSLocaleLanguageCode]; NSString *currentLang = [currentLocale objectForKey:NSLocaleLanguageCode];
return currentLang ? objcString(currentLang) : QString(); return currentLang ? NS2QString(currentLang) : QString();
} }
QString objc_convertFileUrl(const QString &url) { QString objc_convertFileUrl(const QString &url) {
NSString *nsurl = [[[NSURL URLWithString: [NSString stringWithUTF8String: (qsl("file://") + url).toUtf8().constData()]] filePathURL] path]; NSString *nsurl = [[[NSURL URLWithString: [NSString stringWithUTF8String: (qsl("file://") + url).toUtf8().constData()]] filePathURL] path];
if (!nsurl) return QString(); if (!nsurl) return QString();
return objcString(nsurl); return NS2QString(nsurl);
} }
QByteArray objc_downloadPathBookmark(const QString &path) { QByteArray objc_downloadPathBookmark(const QString &path) {
@ -1100,7 +1138,7 @@ void objc_downloadPathEnableAccess(const QByteArray &bookmark) {
} }
_downloadPathUrl = url; _downloadPathUrl = url;
Global::SetDownloadPath(objcString([_downloadPathUrl path]) + '/'); Global::SetDownloadPath(NS2QString([_downloadPathUrl path]) + '/');
if (isStale) { if (isStale) {
NSData *data = [_downloadPathUrl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error]; NSData *data = [_downloadPathUrl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
if (data) { if (data) {
@ -1141,7 +1179,7 @@ objc_FileBookmark::objc_FileBookmark(const QByteArray &bookmark) {
if ([url startAccessingSecurityScopedResource]) { if ([url startAccessingSecurityScopedResource]) {
data = new objc_FileBookmarkData(); data = new objc_FileBookmarkData();
data->url = [url retain]; data->url = [url retain];
data->name = objcString([url path]); data->name = NS2QString([url path]);
data->bookmark = bookmark; data->bookmark = bookmark;
[url stopAccessingSecurityScopedResource]; [url stopAccessingSecurityScopedResource];
} }

View file

@ -49,6 +49,7 @@ public:
void clearFromHistory(History *history) { void clearFromHistory(History *history) {
doClearFromHistory(history); doClearFromHistory(history);
} }
virtual ~Manager() = default;
protected: protected:
virtual void doUpdateAll() = 0; virtual void doUpdateAll() = 0;

View file

@ -35,20 +35,20 @@ namespace {
// 3 desktop notifies at the same time. // 3 desktop notifies at the same time.
constexpr int kNotifyWindowsCount = 3; constexpr int kNotifyWindowsCount = 3;
NeverFreedPointer<Manager> FallbackManager; NeverFreedPointer<Manager> ManagerInstance;
} // namespace } // namespace
void start() { void start() {
FallbackManager.makeIfNull(); ManagerInstance.makeIfNull();
} }
Manager *manager() { Manager *manager() {
return FallbackManager.data(); return ManagerInstance.data();
} }
void finish() { void finish() {
FallbackManager.reset(); ManagerInstance.clear();
} }
Manager::Manager() { Manager::Manager() {
@ -340,7 +340,7 @@ void Widget::itemRemoved(HistoryItem *deleted) {
void Widget::unlinkHistoryAndNotify() { void Widget::unlinkHistoryAndNotify() {
unlinkHistory(); unlinkHistory();
if (auto manager = FallbackManager.data()) { if (auto manager = ManagerInstance.data()) {
manager->showNextFromQueue(); manager->showNextFromQueue();
} }
} }
@ -355,14 +355,14 @@ void Widget::unlinkHistory(History *history) {
void Widget::enterEvent(QEvent *e) { void Widget::enterEvent(QEvent *e) {
if (!_history) return; if (!_history) return;
if (auto manager = FallbackManager.data()) { if (auto manager = ManagerInstance.data()) {
manager->stopAllHiding(); manager->stopAllHiding();
} }
} }
void Widget::leaveEvent(QEvent *e) { void Widget::leaveEvent(QEvent *e) {
if (!_history) return; if (!_history) return;
if (auto manager = FallbackManager.data()) { if (auto manager = ManagerInstance.data()) {
manager->startAllHiding(); manager->startAllHiding();
} }
} }
@ -446,7 +446,7 @@ void Widget::step_appearance(float64 ms, bool timer) {
} }
Widget::~Widget() { Widget::~Widget() {
if (auto manager = FallbackManager.data()) { if (auto manager = ManagerInstance.data()) {
manager->removeFromShown(this); manager->removeFromShown(this);
} }
} }

View file

@ -326,6 +326,8 @@
'<(src_loc)/platform/linux/main_window_linux.h', '<(src_loc)/platform/linux/main_window_linux.h',
'<(src_loc)/platform/linux/notifications_manager_linux.cpp', '<(src_loc)/platform/linux/notifications_manager_linux.cpp',
'<(src_loc)/platform/linux/notifications_manager_linux.h', '<(src_loc)/platform/linux/notifications_manager_linux.h',
'<(src_loc)/platform/mac/mac_utilities.mm',
'<(src_loc)/platform/mac/mac_utilities.h',
'<(src_loc)/platform/mac/main_window_mac.mm', '<(src_loc)/platform/mac/main_window_mac.mm',
'<(src_loc)/platform/mac/main_window_mac.h', '<(src_loc)/platform/mac/main_window_mac.h',
'<(src_loc)/platform/mac/notifications_manager_mac.mm', '<(src_loc)/platform/mac/notifications_manager_mac.mm',
@ -524,6 +526,8 @@
'<(src_loc)/pspecific_mac.h', '<(src_loc)/pspecific_mac.h',
'<(src_loc)/pspecific_mac_p.mm', '<(src_loc)/pspecific_mac_p.mm',
'<(src_loc)/pspecific_mac_p.h', '<(src_loc)/pspecific_mac_p.h',
'<(src_loc)/platform/mac/mac_utilities.mm',
'<(src_loc)/platform/mac/mac_utilities.h',
'<(src_loc)/platform/mac/main_window_mac.mm', '<(src_loc)/platform/mac/main_window_mac.mm',
'<(src_loc)/platform/mac/main_window_mac.h', '<(src_loc)/platform/mac/main_window_mac.h',
'<(src_loc)/platform/mac/notifications_manager_mac.mm', '<(src_loc)/platform/mac/notifications_manager_mac.mm',