1/* 2This file is part of Telegram Desktop, 3the official desktop application for the Telegram messaging service. 4 5For license and copyright information please follow this link: 6https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7*/ 8#include "platform/mac/specific_mac.h" 9 10#include "lang/lang_keys.h" 11#include "mainwidget.h" 12#include "history/history_widget.h" 13#include "core/crash_reports.h" 14#include "core/sandbox.h" 15#include "core/application.h" 16#include "core/core_settings.h" 17#include "storage/localstorage.h" 18#include "window/window_controller.h" 19#include "mainwindow.h" 20#include "history/history_location_manager.h" 21#include "base/platform/mac/base_utilities_mac.h" 22#include "base/platform/base_platform_info.h" 23 24#include <QtGui/QDesktopServices> 25#include <QtWidgets/QApplication> 26 27#include <cstdlib> 28#include <execinfo.h> 29#include <sys/xattr.h> 30 31#include <Cocoa/Cocoa.h> 32#include <CoreFoundation/CFURL.h> 33#include <IOKit/IOKitLib.h> 34#include <IOKit/hidsystem/ev_keymap.h> 35#include <mach-o/dyld.h> 36#include <AVFoundation/AVFoundation.h> 37 38void psActivateProcess(uint64 pid) { 39 if (!pid) { 40 const auto window = Core::App().activeWindow(); 41 objc_activateProgram(window ? window->widget()->winId() : 0); 42 } 43} 44 45QString psAppDataPath() { 46 return objc_appDataPath(); 47} 48 49void psDoCleanup() { 50 try { 51 Platform::AutostartToggle(false); 52 psSendToMenu(false, true); 53 } catch (...) { 54 } 55} 56 57int psCleanup() { 58 psDoCleanup(); 59 return 0; 60} 61 62void psDoFixPrevious() { 63} 64 65int psFixPrevious() { 66 psDoFixPrevious(); 67 return 0; 68} 69 70namespace Platform { 71 72void start() { 73 objc_start(); 74} 75 76void finish() { 77 objc_finish(); 78} 79 80QString SingleInstanceLocalServerName(const QString &hash) { 81#ifndef OS_MAC_STORE 82 return qsl("/tmp/") + hash + '-' + cGUIDStr(); 83#else // OS_MAC_STORE 84 return objc_documentsPath() + hash.left(4); 85#endif // OS_MAC_STORE 86} 87 88bool IsDarkMenuBar() { 89 bool result = false; 90 @autoreleasepool { 91 92 NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain]; 93 id style = [dict objectForKey:Q2NSString(strStyleOfInterface())]; 94 BOOL darkModeOn = (style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"]); 95 result = darkModeOn ? true : false; 96 97 } 98 return result; 99} 100 101std::optional<bool> IsDarkMode() { 102 return IsMac10_14OrGreater() 103 ? std::make_optional(IsDarkMenuBar()) 104 : std::nullopt; 105} 106 107void WriteCrashDumpDetails() { 108#ifndef DESKTOP_APP_DISABLE_CRASH_REPORTS 109 double v = objc_appkitVersion(); 110 CrashReports::dump() << "OS-Version: " << v; 111#endif // DESKTOP_APP_DISABLE_CRASH_REPORTS 112} 113 114// I do check for availability, just not in the exact way clang is content with 115#pragma clang diagnostic push 116#pragma clang diagnostic ignored "-Wunguarded-availability" 117PermissionStatus GetPermissionStatus(PermissionType type) { 118 switch (type) { 119 case PermissionType::Microphone: 120 case PermissionType::Camera: 121 const auto nativeType = (type == PermissionType::Microphone) 122 ? AVMediaTypeAudio 123 : AVMediaTypeVideo; 124 if ([AVCaptureDevice respondsToSelector: @selector(authorizationStatusForMediaType:)]) { // Available starting with 10.14 125 switch ([AVCaptureDevice authorizationStatusForMediaType:nativeType]) { 126 case AVAuthorizationStatusNotDetermined: 127 return PermissionStatus::CanRequest; 128 case AVAuthorizationStatusAuthorized: 129 return PermissionStatus::Granted; 130 case AVAuthorizationStatusDenied: 131 case AVAuthorizationStatusRestricted: 132 return PermissionStatus::Denied; 133 } 134 } 135 break; 136 } 137 return PermissionStatus::Granted; 138} 139 140void RequestPermission(PermissionType type, Fn<void(PermissionStatus)> resultCallback) { 141 switch (type) { 142 case PermissionType::Microphone: 143 case PermissionType::Camera: 144 const auto nativeType = (type == PermissionType::Microphone) 145 ? AVMediaTypeAudio 146 : AVMediaTypeVideo; 147 if ([AVCaptureDevice respondsToSelector: @selector(requestAccessForMediaType:completionHandler:)]) { // Available starting with 10.14 148 [AVCaptureDevice requestAccessForMediaType:nativeType completionHandler:^(BOOL granted) { 149 crl::on_main([=] { 150 resultCallback(granted ? PermissionStatus::Granted : PermissionStatus::Denied); 151 }); 152 }]; 153 } 154 break; 155 } 156 resultCallback(PermissionStatus::Granted); 157} 158#pragma clang diagnostic pop // -Wunguarded-availability 159 160void OpenSystemSettingsForPermission(PermissionType type) { 161 switch (type) { 162 case PermissionType::Microphone: 163 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone"]]; 164 break; 165 case PermissionType::Camera: 166 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Camera"]]; 167 break; 168 } 169} 170 171bool OpenSystemSettings(SystemSettingsType type) { 172 switch (type) { 173 case SystemSettingsType::Audio: 174 [[NSWorkspace sharedWorkspace] openFile:@"/System/Library/PreferencePanes/Sound.prefPane"]; 175 break; 176 } 177 return true; 178} 179 180void IgnoreApplicationActivationRightNow() { 181 objc_ignoreApplicationActivationRightNow(); 182} 183 184void AutostartToggle(bool enabled, Fn<void(bool)> done) { 185 if (done) { 186 done(false); 187 } 188} 189 190bool AutostartSkip() { 191 return !cAutoStart(); 192} 193 194} // namespace Platform 195 196void psNewVersion() { 197} 198 199void psSendToMenu(bool send, bool silent) { 200} 201 202void psDownloadPathEnableAccess() { 203 objc_downloadPathEnableAccess(Core::App().settings().downloadPathBookmark()); 204} 205 206QByteArray psDownloadPathBookmark(const QString &path) { 207 return objc_downloadPathBookmark(path); 208} 209 210bool psLaunchMaps(const Data::LocationPoint &point) { 211 return QDesktopServices::openUrl(qsl("https://maps.apple.com/?q=Point&z=16&ll=%1,%2").arg(point.latAsString()).arg(point.lonAsString())); 212} 213 214QString strNotificationAboutThemeChange() { 215 const uint32 letters[] = { 0x75E86256, 0xD03E11B1, 0x4D92201D, 0xA2144987, 0x99D5B34F, 0x037589C3, 0x38ED2A7C, 0xD2371ABC, 0xDC98BB02, 0x27964E1B, 0x01748AED, 0xE06679F8, 0x761C9580, 0x4F2595BF, 0x6B5FCBF4, 0xE4D9C24E, 0xBA2F6AB5, 0xE6E3FA71, 0xF2CFC255, 0x56A50C19, 0x43AE1239, 0x77CA4254, 0x7D189A89, 0xEA7663EE, 0x84CEB554, 0xA0ADF236, 0x886512D4, 0x7D3FBDAF, 0x85C4BE4F, 0x12C8255E, 0x9AD8BD41, 0xAC154683, 0xB117598B, 0xDFD9F947, 0x63F06C7B, 0x6340DCD6, 0x3AAE6B3E, 0x26CB125A }; 216 return Platform::MakeFromLetters(letters); 217} 218 219QString strNotificationAboutScreenLocked() { 220 const uint32 letters[] = { 0x34B47F28, 0x47E95179, 0x73D05C42, 0xB4E2A933, 0x924F22D1, 0x4265D8EA, 0x9E4D2CC2, 0x02E8157B, 0x35BF7525, 0x75901A41, 0xB0400FCC, 0xE801169D, 0x4E04B589, 0xC1CEF054, 0xAB2A7EB0, 0x5C67C4F6, 0xA4E2B954, 0xB35E12D2, 0xD598B22B, 0x4E3B8AAB, 0xBEA5E439, 0xFDA8AA3C, 0x1632DBA8, 0x88FE8965 }; 221 return Platform::MakeFromLetters(letters); 222} 223 224QString strNotificationAboutScreenUnlocked() { 225 const uint32 letters[] = { 0xF897900B, 0x19A04630, 0x144DA6DF, 0x643CA7ED, 0x81DDA343, 0x88C6B149, 0x5F9A3A15, 0x31804E13, 0xDF2202B8, 0x9BD1B500, 0x61B92735, 0x7DDF5D43, 0xB74E06C3, 0x16FF1665, 0x9098F702, 0x4461DAF0, 0xA3134FA5, 0x52B01D3C, 0x6BC35769, 0xA7CC945D, 0x8B5327C0, 0x7630B9A0, 0x4E52E3CE, 0xED7765E3, 0xCEB7862D, 0xA06B34F0 }; 226 return Platform::MakeFromLetters(letters); 227} 228 229QString strStyleOfInterface() { 230 const uint32 letters[] = { 0x3BBB7F05, 0xED4C5EC3, 0xC62C15A3, 0x5D10B283, 0x1BB35729, 0x63FB674D, 0xDBE5C174, 0x401EA195, 0x87B0C82A, 0x311BD596, 0x7063ECFA, 0x4AB90C27, 0xDA587DC4, 0x0B6296F8, 0xAA5603FA, 0xE1140A9F, 0x3D12D094, 0x339B5708, 0x712BA5B1 }; 231 return Platform::MakeFromLetters(letters); 232} 233 234QString strTitleWrapClass() { 235 const uint32 letters[] = { 0x066C95DD, 0xA289D425, 0x000EF1A5, 0xB53C76AA, 0x5096391D, 0x212BF5B8, 0xE6BCA526, 0x2A5B8EC6, 0xC1457BDB, 0xA1BEE033, 0xA8ADFA11, 0xFF151585, 0x36EC257D, 0x4D96241D, 0xD0341BAA, 0xDE2908BF, 0xFE7978E8, 0x26875E1D, 0x70DA5557, 0x14C02B69, 0x7EFF7E69, 0x008D7217, 0x5EB01138 }; 236 return Platform::MakeFromLetters(letters); 237} 238 239QString strTitleClass() { 240 const uint32 letters[] = { 0x1054BBE5, 0xA39FC333, 0x54B51E1E, 0x24895213, 0x50B71830, 0xBF07478C, 0x10BA5503, 0x5C70D3E6, 0x65079D9D, 0xACAAF939, 0x6A56C3CD }; 241 return Platform::MakeFromLetters(letters); 242} 243