#include "MacUtils.h" #include "UBPlatformUtils.h" #include "core/UBApplication.h" #include "core/UBSettings.h" #include "frameworks/UBFileSystemUtils.h" #include #import #import #import /* // commented because Sankore crashes on Java Script. It seems to backends dependencies. #import #import */ NSString* bundleShortVersion(NSBundle *bundle) { return [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; } OSStatus emptySetSystemUIMode ( SystemUIMode inMode, SystemUIOptions inOptions) { Q_UNUSED(inMode); Q_UNUSED(inOptions); // NOOP return noErr; } void *originalSetSystemUIMode = 0; void UBPlatformUtils::init() { initializeKeyboardLayouts(); // qwidget_mac.mm qt_mac_set_fullscreen_mode uses kUIModeAllSuppressed which is unfortunate in our case // // http://developer.apple.com/mac/library/documentation/Carbon/Reference/Dock_Manager/Reference/reference.html#//apple_ref/c/func/SetSystemUIMode // originalSetSystemUIMode = APEPatchCreate((const void *)SetSystemUIMode, (const void *)emptySetSystemUIMode); setDesktopMode(false); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *currentPath = [[NSBundle mainBundle] pathForResource:@"Save PDF to Open-Sankore" ofType:@"workflow"]; NSString *installedPath = [[[@"~/Library/PDF Services" stringByExpandingTildeInPath] stringByAppendingPathComponent:@"Save PDF to Open-Sankore"] stringByAppendingPathExtension:@"workflow"]; NSString *currentVersion = bundleShortVersion([NSBundle bundleWithPath:currentPath]); NSString *installedVersion = bundleShortVersion([NSBundle bundleWithPath:installedPath]); if (![installedVersion isEqualToString:currentVersion]) { NSFileManager *fileManager = [NSFileManager defaultManager]; [fileManager removeFileAtPath:installedPath handler:nil]; // removing the old version of the script named Save PDF to Uniboard [fileManager removeFileAtPath:[[[@"~/Library/PDF Services" stringByExpandingTildeInPath] stringByAppendingPathComponent:@"Save PDF to Uniboard"] stringByAppendingPathExtension:@"workflow"] handler:nil]; [fileManager createDirectoryAtPath:[installedPath stringByDeletingLastPathComponent] attributes:nil]; BOOL copyOK = [fileManager copyPath:currentPath toPath:installedPath handler:nil]; if (!copyOK) { qWarning("Could not install the 'Save PDF to Open-Sankoré workflow"); } } [pool drain]; } void UBPlatformUtils::setDesktopMode(bool desktop) { OSStatus (*functor)(SystemUIMode, SystemUIOptions) = (OSStatus (*)(SystemUIMode, SystemUIOptions))originalSetSystemUIMode; if (desktop) { functor(kUIModeNormal, 0); } else { functor(kUIModeAllHidden, 0); } } QString UBPlatformUtils::applicationResourcesDirectory() { QString path; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; path = QString::fromUtf8([resourcePath fileSystemRepresentation], strlen([resourcePath fileSystemRepresentation])); [pool drain]; return path; } void UBPlatformUtils::hideFile(const QString &filePath) { FSRef ref; CFStringRef path = CFStringCreateWithCharacters(0, reinterpret_cast(filePath.unicode()), filePath.length()); const CFIndex maxSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path); UInt8 fileSystemRepresentation[maxSize]; CFRelease(path); if (!CFStringGetFileSystemRepresentation(path, (char*)fileSystemRepresentation, maxSize)) { return; } OSStatus status = FSPathMakeRefWithOptions(fileSystemRepresentation, kFSPathMakeRefDefaultOptions, &ref, NULL); if (status != noErr) { return; } FSCatalogInfo catalogInfo; FSCatalogInfoBitmap whichInfo = kFSCatInfoFinderInfo; OSErr err = FSGetCatalogInfo(&ref, whichInfo, &catalogInfo, NULL, NULL, NULL); if (err != noErr) { return; } ((FileInfo*)(catalogInfo.finderInfo))->finderFlags |= kIsInvisible; FSSetCatalogInfo(&ref, whichInfo, &catalogInfo); } void UBPlatformUtils::setFileType(const QString &filePath, unsigned long fileType) { FSRef ref; CFStringRef path = CFStringCreateWithCharacters(0, reinterpret_cast(filePath.unicode()), filePath.length()); const CFIndex maxSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path); UInt8 fileSystemRepresentation[maxSize]; CFRelease(path); if (!CFStringGetFileSystemRepresentation(path, (char*)fileSystemRepresentation, maxSize)) { return; } OSStatus status = FSPathMakeRefWithOptions(fileSystemRepresentation, kFSPathMakeRefDefaultOptions, &ref, NULL); if (status != noErr) { return; } FSCatalogInfo catalogInfo; FSCatalogInfoBitmap whichInfo = kFSCatInfoFinderInfo; OSErr err = FSGetCatalogInfo(&ref, whichInfo, &catalogInfo, NULL, NULL, NULL); if (err != noErr) { return; } ((FileInfo*)(catalogInfo.finderInfo))->fileType = fileType; ((FileInfo*)(catalogInfo.finderInfo))->fileCreator = 'UniB'; FSSetCatalogInfo(&ref, whichInfo, &catalogInfo); } static CGDisplayFadeReservationToken token = NULL; void UBPlatformUtils::fadeDisplayOut() { if (CGAcquireDisplayFadeReservation(1.2, &token) == kCGErrorSuccess) { CGDisplayFade(token, 1.0, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, true); } } void UBPlatformUtils::fadeDisplayIn() { if (CGAcquireDisplayFadeReservation(0.6, &token) == kCGErrorSuccess) { CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, true); } } QStringList UBPlatformUtils::availableTranslations() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *lprojPath = [[NSBundle mainBundle] resourcePath]; QString translationsPath = QString::fromUtf8([lprojPath UTF8String], strlen([lprojPath UTF8String])); QStringList translationsList = UBFileSystemUtils::allFiles(translationsPath, false); QRegExp sankoreTranslationFiles(".*lproj"); translationsList=translationsList.filter(sankoreTranslationFiles); [pool drain]; return translationsList.replaceInStrings(QRegExp("(.*)/(.*).lproj"),"\\2"); } QString UBPlatformUtils::translationPath(QString pFilePrefix, QString pLanguage) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *lprojPath = [[NSBundle mainBundle] resourcePath]; QString translationsPath = QString::fromUtf8([lprojPath UTF8String], strlen([lprojPath UTF8String])); [pool drain]; return translationsPath + "/" + pLanguage + ".lproj/" + pFilePrefix + pLanguage + ".qm"; } QString UBPlatformUtils::systemLanguage() { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSUserDefaults* defs = [NSUserDefaults standardUserDefaults]; NSArray* languages = [defs objectForKey:@"AppleLanguages"]; NSString* preferredLang = [languages objectAtIndex:0]; QString result = QString::fromUtf8([preferredLang UTF8String], strlen([preferredLang UTF8String])); [pool drain]; return result; } void UBPlatformUtils::runInstaller(const QString &installerFilePath) { UBApplication::setDisabled(true); // Save app config file to temp directory (will be restored at launch) QString appSettings = UBPlatformUtils::applicationResourcesDirectory() + "/etc/Uniboard.config"; QString tmpSettings = QDir::tempPath() + "/Uniboard.config"; QFile::remove(tmpSettings); QFile::copy(appSettings, tmpSettings); QString updateFilePath = QDir::tempPath() + "/upgrade.sh"; QFile file(":/macx/upgrade.sh"); QFile updateFile(updateFilePath); if (file.open(QIODevice::ReadOnly) && updateFile.open(QIODevice::WriteOnly)) { QByteArray payload = file.readAll(); updateFile.write(payload); updateFile.close(); QString uniboardAndVersion = QApplication::applicationName() + QString(" ") + QApplication::applicationVersion(); QFileInfo fi(installerFilePath); uniboardAndVersion = fi.fileName().remove(".dmg"); QString bundlePath; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *nssBundlePath = [[NSBundle mainBundle] bundlePath]; bundlePath = QString::fromUtf8([nssBundlePath fileSystemRepresentation], strlen([nssBundlePath fileSystemRepresentation])); [pool drain]; QString escaped = QString("/bin/sh \"%1\" \"%2\" \"%3\" \"%4\"") .arg(updateFilePath) .arg(uniboardAndVersion) .arg(installerFilePath) .arg(bundlePath); qDebug() << "Installing New Version" << escaped; QProcess process; bool success = process.startDetached(escaped); if(success) return; } // did not work .. lets load the dmg ... QDesktopServices::openUrl(QUrl::fromLocalFile(installerFilePath)); } void UBPlatformUtils::bringPreviousProcessToFront() { ProcessSerialNumber previousProcessPSN = {0, kNoProcess}; CFArrayRef apps = CopyLaunchedApplicationsInFrontToBackOrder(); if (apps != NULL) { if (CFArrayGetCount(apps) > 1) { SInt64 psn64; CFDictionaryRef appInfo = (CFDictionaryRef)CFArrayGetValueAtIndex(apps, 1); CFNumberRef psn = (CFNumberRef)CFDictionaryGetValue(appInfo, CFSTR("PSN")); if (psn != NULL) { CFNumberGetValue(psn, kCFNumberSInt64Type, &psn64); previousProcessPSN.highLongOfPSN = psn64 >> 32; previousProcessPSN.lowLongOfPSN = psn64 & 0xFFFFFFFF; } } CFRelease(apps); } else { // On 10.4, we can't get the apps in front to back order, so we default to Finder OSStatus status; ProcessSerialNumber psn = {0, kNoProcess}; while ((status = GetNextProcess(&psn)) == noErr) { CFDictionaryRef processInfo = ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask); if (processInfo != NULL) { CFStringRef bundleIdentifier = (CFStringRef)CFDictionaryGetValue(processInfo, kCFBundleIdentifierKey); if (bundleIdentifier && CFStringCompare(CFSTR("com.apple.finder"), bundleIdentifier, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { previousProcessPSN.highLongOfPSN = psn.highLongOfPSN; previousProcessPSN.lowLongOfPSN = psn.lowLongOfPSN; } CFRelease(processInfo); } } } SetFrontProcess(&previousProcessPSN); } QString UBPlatformUtils::osUserLoginName() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *nsUserName = NSUserName(); QString userName = QString::fromUtf8([nsUserName UTF8String], strlen([nsUserName UTF8String])); [pool drain]; return userName; } QString UBPlatformUtils::computerName() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *nsComputerName = [[NSHost currentHost] name]; QString computerName = QString::fromUtf8([nsComputerName UTF8String], strlen([nsComputerName UTF8String])); [pool drain]; return computerName; } void UBPlatformUtils::setWindowNonActivableFlag(QWidget* widget, bool nonAcivable) { Q_UNUSED(widget); Q_UNUSED(nonAcivable); } QPixmap qpixmapFromIconRef(IconRef iconRef, int size) { OSErr result; int iconSize; OSType elementType; // Determine elementType and iconSize if (size <= 16) { elementType = kSmall32BitData; iconSize = 16; } else if (size <= 32) { elementType = kLarge32BitData; iconSize = 32; } else { elementType = kThumbnail32BitData; iconSize = 128; } // Get icon into an IconFamily IconFamilyHandle hIconFamily = 0; IconRefToIconFamily(iconRef, kSelectorAllAvailableData, &hIconFamily); // Extract data Handle hRawBitmapData = NewHandle(iconSize * iconSize * 4); result = GetIconFamilyData( hIconFamily, elementType, hRawBitmapData ); if (result != noErr) { DisposeHandle(hRawBitmapData); return QPixmap(); } // Convert data to QImage QImage image(iconSize, iconSize, QImage::Format_ARGB32); HLock(hRawBitmapData); unsigned long* data = (unsigned long*) *hRawBitmapData; for (int posy=0; posy> 8) & 0xff, kbdType, kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 100, &cnt2, unicodeString2); UCKeyTranslate(keyLayout, vkk, kUCKeyActionDisplay, (alphaLock >> 8) & 0xff, kbdType, kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 100, &cnt2, unicodeString3); return new KEYBT(unicodeString1[0], unicodeString2[0], unicodeString1[0] != unicodeString3[0], 0,0, KEYCODE(0, vkk, 0), KEYCODE(0, vkk, 1)); } void UBPlatformUtils::initializeKeyboardLayouts() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; CFStringRef keys[] = { kTISPropertyInputSourceCategory, kTISPropertyInputSourceIsEnableCapable, kTISPropertyInputSourceIsSelectCapable }; const void* values[] = { kTISCategoryKeyboardInputSource, kCFBooleanTrue, kCFBooleanTrue }; CFDictionaryRef dict = CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, 3, NULL, NULL); CFArrayRef kbds = TISCreateInputSourceList(dict, false); int count = CFArrayGetCount(kbds); QList result; qDebug() << "initializeKeyboardLayouts"; qDebug() << "Found system locales: " << count; for(int i=0; i0) { CFStringRef langRef = (CFStringRef)CFArrayGetValueAtIndex(langs, 0); name = QStringFromStringRef(langRef); qDebug() << "name is " + name; } //IconRef iconRef = (IconRef)TISGetInputSourceProperty(kTISPropertyIconRef, kTISPropertyInputSourceLanguages); const QString resName = ":/images/flags/" + name + ".png"; QIcon *iconLang = new QIcon(resName); qDebug() << "Locale: " << ID << ", name: " << name; result.append(new UBKeyboardLocale(fullName, name, ID, iconLang, keybt)); } if (result.size()==0) { nKeyboardLayouts = 0; keyboardLayouts = NULL; } else { nKeyboardLayouts = result.size(); keyboardLayouts = new UBKeyboardLocale*[nKeyboardLayouts]; for(int i=0; i