Warning, file /frameworks/kdelibs4support/src/kdecore/kkernel_mac.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of the KDE libraries 0003 Copyright (C) 2008 Benjamin Reed <rangerrick@befunk.com> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License version 2 as published by the Free Software Foundation. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "kkernel_mac.h" 0021 0022 #ifdef Q_OS_MACX 0023 0024 #include <unistd.h> 0025 #include <string.h> 0026 #include <stdio.h> 0027 #include <stdlib.h> 0028 #include <sys/param.h> 0029 #include <crt_externs.h> 0030 #include <mach-o/dyld.h> 0031 0032 #include <CoreFoundation/CFBundle.h> 0033 #include <CoreFoundation/CFURL.h> 0034 #include <QFile> 0035 #include <QProcess> 0036 #include <QStringList> 0037 #include <qvarlengtharray.h> 0038 0039 #include <ksharedconfig.h> 0040 #include <kconfig.h> 0041 #include <kdebug.h> 0042 0043 int timeout = 3000; // msec 0044 0045 bool dbus_initialized = false; 0046 0047 /** 0048 qAppFileName() is not public in qt4/mac, so we need to redo it here 0049 */ 0050 0051 QString convert_CFString_to_QString(CFStringRef str) 0052 { 0053 CFIndex length = CFStringGetLength(str); 0054 const UniChar *chars = CFStringGetCharactersPtr(str); 0055 if (chars) { 0056 return QString(reinterpret_cast<const QChar *>(chars), length); 0057 } 0058 0059 QVarLengthArray<UniChar> buffer(length); 0060 CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); 0061 return QString(reinterpret_cast<const QChar *>(buffer.constData()), length); 0062 } 0063 0064 /** 0065 Calling CoreFoundation APIs (which is unavoidable in Qt/Mac) has always had issues 0066 on Mac OS X, but as of 10.5 is explicitly disallowed with an exception. As a 0067 result, in the case where we would normally fork and then dlopen code, or continue 0068 to run other code, we must now fork-and-exec. 0069 0070 See "CoreFoundation and fork()" at http://developer.apple.com/releasenotes/CoreFoundation/CoreFoundation.html 0071 */ 0072 0073 void 0074 mac_fork_and_reexec_self() 0075 { 0076 int argc = *_NSGetArgc(); 0077 char **argv = *_NSGetArgv(); 0078 char *newargv[argc + 2]; 0079 char progname[PATH_MAX]; 0080 uint32_t buflen = PATH_MAX; 0081 _NSGetExecutablePath(progname, &buflen); 0082 bool found_psn = false; 0083 0084 for (int i = 0; i < argc; i++) { 0085 newargv[i] = argv[i]; 0086 } 0087 0088 newargv[argc] = "--nofork"; 0089 newargv[argc + 1] = NULL; 0090 0091 int x_fork_result = fork(); 0092 switch (x_fork_result) { 0093 0094 case -1: 0095 #ifndef NDEBUG 0096 fprintf(stderr, "Mac OS X workaround fork() failed!\n"); 0097 #endif 0098 ::_exit(255); 0099 break; 0100 0101 case 0: 0102 // Child 0103 execvp(progname, newargv); 0104 break; 0105 0106 default: 0107 // Parent 0108 _exit(0); 0109 break; 0110 0111 } 0112 } 0113 0114 /** 0115 Set the D-Bus environment based on session bus socket 0116 */ 0117 0118 bool mac_set_dbus_address(QString value) 0119 { 0120 if (!value.isEmpty() && QFile::exists(value) && (QFile::permissions(value) & QFile::WriteUser)) { 0121 value = QLatin1String("unix:path=") + value; 0122 qputenv("DBUS_SESSION_BUS_ADDRESS", value.toLocal8Bit()); 0123 kDebug() << "set session bus address to" << value; 0124 return true; 0125 } 0126 return false; 0127 } 0128 0129 /** 0130 Make sure D-Bus is initialized, by any means necessary. 0131 */ 0132 0133 void mac_initialize_dbus() 0134 { 0135 if (dbus_initialized) { 0136 return; 0137 } 0138 0139 QString dbusVar = QString::fromLocal8Bit(qgetenv("DBUS_SESSION_BUS_ADDRESS")); 0140 if (!dbusVar.isEmpty()) { 0141 dbus_initialized = true; 0142 return; 0143 } 0144 0145 dbusVar = QFile::decodeName(qgetenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET")); 0146 if (mac_set_dbus_address(dbusVar)) { 0147 dbus_initialized = true; 0148 return; 0149 } 0150 0151 QString externalProc; 0152 QStringList path = QFile::decodeName(qgetenv("KDEDIRS")).split(QLatin1Char(':')).replaceInStrings(QRegExp(QLatin1String("$")), QLatin1String("/bin")); 0153 path << QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':')) << QLatin1String("/usr/local/bin"); 0154 0155 for (int i = 0; i < path.size(); ++i) { 0156 QString testLaunchctl = QString(path.at(i)).append(QLatin1String("/launchctl")); 0157 if (QFile(testLaunchctl).exists()) { 0158 externalProc = testLaunchctl; 0159 break; 0160 } 0161 } 0162 0163 if (!externalProc.isEmpty()) { 0164 QProcess qp; 0165 qp.setTextModeEnabled(true); 0166 0167 qp.start(externalProc, QStringList() << QLatin1String("getenv") << QLatin1String("DBUS_LAUNCHD_SESSION_BUS_SOCKET")); 0168 if (!qp.waitForFinished(timeout)) { 0169 kDebug() << "error running" << externalProc << qp.errorString(); 0170 return; 0171 } 0172 if (qp.exitCode() != 0) { 0173 kDebug() << externalProc << "unsuccessful:" << qp.readAllStandardError(); 0174 return; 0175 } 0176 0177 QString line = QString::fromLatin1(qp.readLine()).trimmed(); // read the first line 0178 if (mac_set_dbus_address(line)) { 0179 dbus_initialized = true; // hooray 0180 } 0181 } 0182 0183 if (dbus_initialized == false) { 0184 kDebug() << "warning: unable to initialize D-Bus environment!"; 0185 } 0186 0187 } 0188 0189 QString mac_app_filename() 0190 { 0191 static QString appFileName; 0192 if (appFileName.isEmpty()) { 0193 CFURLRef bundleURL = NULL; 0194 CFBundleRef bundle = NULL; 0195 CFStringRef bundlePath = NULL; 0196 0197 bundle = CFBundleGetMainBundle(); 0198 if (bundle) { 0199 bundleURL = CFBundleCopyBundleURL(bundle); 0200 bundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle); 0201 0202 if (bundleURL) { 0203 CFRelease(bundleURL); 0204 } 0205 0206 if (bundlePath) { 0207 appFileName = convert_CFString_to_QString(bundlePath); 0208 CFRelease(bundlePath); 0209 } 0210 } 0211 } 0212 return appFileName; 0213 } 0214 0215 #endif