diff --git a/CMakeLists.txt b/CMakeLists.txt index 57e71ebb..645e4691 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.0.2) -project(filer-qt) +if(AIRYX) + project(Filer) +else() + project(filer-qt) +endif() set(PCMANFM_QT_VERSION_MAJOR 0) set(PCMANFM_QT_VERSION_MINOR 10) @@ -11,6 +15,11 @@ set(LIBFM_QT_VERSION_MINOR 10) set(LIBFM_QT_VERSION_PATCH 0) set(LIBFM_QT_VERSION ${LIBFM_QT_VERSION_MAJOR}.${LIBFM_QT_VERSION_MINOR}.${LIBFM_QT_VERSION_PATCH}) +if(AIRYX) + set(CMAKE_INSTALL_BINDIR "/Contents/Airyx") + set(CMAKE_INSTALL_DATAROOTDIR "/Contents/Resources") +endif() + list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # We use the libtool versioning scheme for the internal so name, "current:revision:age" @@ -28,6 +37,9 @@ find_package(Qt5Widgets 5.2 REQUIRED) find_package(Qt5DBus 5.2 REQUIRED) find_package(Qt5LinguistTools 5.2 REQUIRED) find_package(Qt5X11Extras 5.2 REQUIRED) +if(AIRYX) + find_package(Qt5Xdg 3.7 REQUIRED) +endif() find_package(PkgConfig) pkg_check_modules(SYSTEM_LIBS REQUIRED @@ -64,9 +76,15 @@ configure_file( "${CMAKE_CURRENT_BINARY_DIR}/filer-qt.1" @ONLY ) +if(AIRYX) + set(MAN1PATH "${CMAKE_INSTALL_DATAROOTDIR}") +else() + set(MAN1PATH "${CMAKE_INSTALL_MANDIR}/man1") +endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/filer-qt.1" - DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" + DESTINATION "${MAN1PATH}" ) # add Doxygen support to generate API docs diff --git a/Info.plist b/Info.plist new file mode 100644 index 00000000..7097dde3 --- /dev/null +++ b/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleName + Filer + CFBundleDisplayName + Filer + CFBundleIdentifier + org.airyx.Filer + CFBundleVersion + 1.0 + CFBundlePackageType + APPL + CFBundleSignature + OBJC + CFBundleExecutable + Filer + CFBundleShortVersionString + 1.0.0 + NSHumanReadableCopyright + Copyright (C) 2021 Airyx Project + CFBundleIconFile + Icon.png + NSPrincipalClass + + CFBundleDocumentTypes + + + LSItemContentTypes + + public.folder + + CFBundleTypeName + Folder + CFBundleTypeRole + Editor + + + LSItemContentTypes + + public.volume + + CFBundleTypeName + Volume + CFBundleTypeRole + Editor + + + + diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..a159fee0 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +# Filer is built by cmake. This dummy makefile just creates the .app bundle. + +APP=Filer +SRCS= +MK_DEBUG_FILES=no +RESOURCES= +FRAMEWORKS= + +build: Filer.app + cp -fv ${.CURDIR}/airyxOSFiler.png ${APP_DIR}/Contents/Resources/Icon.png + cp -fv ${.CURDIR}/Info.plist ${APP_DIR}/Contents + +clean: + rm -f ${.CURDIR}/build/src/*.o + +.include diff --git a/airyxOSFiler.png b/airyxOSFiler.png new file mode 100755 index 00000000..ccf4790d Binary files /dev/null and b/airyxOSFiler.png differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31edb177..28ff7d10 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,14 @@ set(LIBFM_LIBRARY "fm-qt5") set(QTX_INCLUDE_DIRS "") -set(QTX_LIBRARIES Qt5::Widgets Qt5::DBus Qt5::X11Extras) +if(AIRYX) + set(QTX_LIBRARIES Qt5::Widgets Qt5::DBus Qt5::X11Extras Qt5Xdg) + set(EXEC_NAME "Filer") + set(PCMANFM_DIR "/Contents/Resources") +else() + set(QTX_LIBRARIES Qt5::Widgets Qt5::DBus Qt5::X11Extras) + set(EXEC_NAME "filer-qt") + set(PCMANFM_DIR "${CMAKE_INSTALL_PREFIX}/share/filer-qt") +endif() include_directories( ${QTX_INCLUDE_DIRS} @@ -17,6 +25,7 @@ link_directories( ) set(filer_SRCS + airyx.cpp bundle.cpp # probono libfmqt.cpp bookmarkaction.cpp @@ -129,43 +138,51 @@ lxqt_translate_desktop(DESKTOP_FILES if(APPLE) set(CMAKE_INSTALL_RPATH "@executable_path") # Darwin, macOS else() - set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") # FreeBSD + if(AIRYX) + set(CMAKE_INSTALL_RPATH "$ORIGIN/../Resources/lib") # Airyx + else() + set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") # FreeBSD + endif() endif() if(NOT LINUX) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) # On Linux we let appimagetool handle it endif() -add_executable(filer-qt + +add_executable(${EXEC_NAME} ${filer_SRCS} ${filer_UIS_H} ${QM_FILES} ${DESKTOP_FILES} ) set_property( - TARGET filer-qt APPEND + TARGET ${EXEC_NAME} APPEND PROPERTY COMPILE_DEFINITIONS LIBFM_QT_API=Q_DECL_IMPORT - PCMANFM_DATA_DIR="${CMAKE_INSTALL_PREFIX}/share/filer-qt" + PCMANFM_DATA_DIR="${PCMANFM_DIR}" LIBFM_DATA_DIR="${LIBFM_PREFIX}/share/libfm" # This is a little bit dirty PCMANFM_QT_VERSION="${PCMANFM_QT_VERSION}" ) -target_link_libraries(filer-qt +target_link_libraries(${EXEC_NAME} ${QTX_LIBRARIES} ${LIBFM_LIBRARIES} ${LIBMENUCACHE_LIBRARIES} ${SYSTEM_LIBS_LIBRARIES} + ${SYSTEM_FRAMEWORKS} ) -install(TARGETS filer-qt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(TARGETS ${EXEC_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -# install a desktop entry file for filer-qt and desktop preferences -install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" -) +if(NOT AIRYX) + # install a desktop entry file for filer-qt and desktop preferences + install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" + ) +endif() -install(FILES ${QM_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/filer-qt/translations") +install(FILES ${QM_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/translations") # prevent the generated files from being deleted during make clean set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM true) -qt5_use_modules(filer-qt Widgets DBus) +qt5_use_modules(${EXEC_NAME} Widgets DBus) diff --git a/src/about.ui b/src/about.ui index 259796ed..a94ff931 100644 --- a/src/about.ui +++ b/src/about.ui @@ -7,7 +7,7 @@ 0 0 543 - 418 + 541 @@ -24,7 +24,7 @@ - icons/filer-256.png + ./Resources/Icon.png Qt::AlignCenter @@ -67,7 +67,7 @@ - <html><head/><body><p><a href="https://github.com/probonopd/filer/"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/probonopd/filer/</span></a></p></body></html> + <html><head/><body><p><a href="https://github.com/mszoek/Filer/"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/mszoek/Filer/</span></a></p></body></html> Qt::RichText @@ -80,7 +80,7 @@ - 1 + 0 false @@ -97,6 +97,7 @@ Programming: +* Zoe Knox (mszoek) * Simon Peter (probono) * Chris Moore (moochris) * Hong Jen Yee (PCMan) <pcman.tw@gmail.com> @@ -124,6 +125,7 @@ Application icon: Filer +Copyright (C) 2021 Zoe Knox Copyright (C) 2020-21 Simon Peter Copyright (C) 2021 Chris Moore diff --git a/src/airyx.cpp b/src/airyx.cpp new file mode 100644 index 00000000..edbf9ba5 --- /dev/null +++ b/src/airyx.cpp @@ -0,0 +1,207 @@ +/* + * Glue code to integrate Filer with Airyx Cocoa frameworks + * + * Copyright (C) 2021 Zoe Knox + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if defined(__AIRYX__) +#import "airyx.h" +#import +#include + +QList programArguments() +{ + CFArrayRef args = (CFArrayRef)CFBundleGetValueForInfoDictionaryKey( + CFBundleGetMainBundle(), CFSTR("ProgramArguments" )); + QList list; + if(!args) + return list; + + for(int x = 0; x < CFArrayGetCount(args); ++x) { + CFStringRef value = (CFStringRef)CFArrayGetValueAtIndex(args, x); + list.append(QString::fromUtf8( CFStringGetCStringPtr(value, kCFStringEncodingUTF8) )); + } + return list; +} + +bool checkWhetherAppDirOrBundle(QString path) +{ + CFStringRef cfpath = CFStringCreateWithCString(NULL, path.toUtf8(), kCFStringEncodingUTF8); + CFURLRef url = CFURLCreateWithFileSystemPath(NULL, cfpath, kCFURLPOSIXPathStyle, true); + bool check = (LSIsNSBundle(url) | LSIsAppDir(url)); + CFRelease(url); + CFRelease(cfpath); + return check; +} + +QString displayNameForBundle(QString path) +{ + // This function is only called for App Bundles or + // AppDirs, so just a quick check to tell them apart... + if(path.toLower().endsWith(".app")) { + CFStringRef cfpath = CFStringCreateWithCString(NULL, path.toUtf8(), kCFStringEncodingUTF8); + CFURLRef url = CFURLCreateWithFileSystemPath(NULL, cfpath, kCFURLPOSIXPathStyle, true); + CFRelease(cfpath); + CFBundleRef bundle = CFBundleCreate(NULL, url); + CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); + CFStringRef name = (CFStringRef)CFDictionaryGetValue(infoDict, CFSTR("CFBundleDisplayName")); + if(name == NULL) + name = (CFStringRef)CFDictionaryGetValue(infoDict, CFSTR("CFBundleName")); + if(name == NULL) { + CFURLRef noExt = CFURLCreateCopyDeletingPathExtension(NULL, url); + name = CFURLCopyLastPathComponent(noExt); + CFRelease(noExt); + } + QString qname = QString::fromUtf8(CFStringGetCStringPtr(name, kCFStringEncodingUTF8)); + CFRelease(bundle); + CFRelease(url); + return qname; + } + + // Handle AppDirs by looking for .desktop files. This is ugly. + QStringList fileList; + QDir folder(path); + QStringList entryList(folder.entryList(QStringList(), QDir::Files)); + for(QStringList::iterator entry = entryList.begin(); entry != entryList.end(); entry++) + fileList.append(folder.absoluteFilePath(*entry)); + + QDir share(path.append("/usr/share/applications")); + entryList = folder.entryList(QStringList(), QDir::Files); + for(QStringList::iterator entry = entryList.begin(); entry != entryList.end(); entry++) + fileList.append(share.absoluteFilePath(*entry)); + + for(QStringList::iterator filepath = fileList.begin(); filepath != fileList.end(); filepath++) { + if(filepath->toLower().endsWith(".desktop")) { + XdgDesktopFile df; + df.load(*filepath); + if(df.type() == XdgDesktopFile::ApplicationType) { + if(df.name() != QString()) { + return df.name(); + } + } + } + } + + return QFileInfo(path).baseName(); +} + +QString getPathForMainBundle() +{ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef url = CFBundleCopyBundleURL(mainBundle); + CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + QString result(QString::fromUtf8(CFStringGetCStringPtr(path, kCFStringEncodingUTF8))); + CFRelease(path); + CFRelease(url); + return result; +} + +QIcon getIconForBundle(QString path = NULL) +{ + QIcon icon = QIcon::fromTheme("do"); // default "executable folder" icon + + // This function is only called for App Bundles or + // AppDirs, so just a quick check to tell them apart... + if(path.toLower().endsWith(".app")) { + CFStringRef cfpath = CFStringCreateWithCString(NULL, path.toUtf8(), kCFStringEncodingUTF8); + CFURLRef url = CFURLCreateWithFileSystemPath(NULL, cfpath, kCFURLPOSIXPathStyle, true); + CFBundleRef bundle = CFBundleCreate(NULL, url); + CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); + CFStringRef iconfile = (CFStringRef)CFDictionaryGetValue(infoDict, CFSTR("CFBundleIconFile")); + + if(iconfile == NULL) + iconfile = (CFStringRef)CFDictionaryGetValue(infoDict, CFSTR("NSIcon")); + + if(iconfile != NULL) { + CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(bundle); + CFStringRef resourcePath = CFURLCopyFileSystemPath(resourceURL, kCFURLPOSIXPathStyle); + QDir resourceDir(QString::fromUtf8(CFStringGetCStringPtr(resourcePath, kCFStringEncodingUTF8))); + CFRelease(resourcePath); + CFRelease(resourceURL); + + QString iconPath(resourceDir.filePath(QString::fromUtf8( + CFStringGetCStringPtr(iconfile, kCFStringEncodingUTF8)))); + if(resourceDir.exists(iconPath)) + icon = QIcon(iconPath); + } + + CFRelease(bundle); + CFRelease(url); + CFRelease(cfpath); + return icon; + } + + // Look for a .DirIcon in AppDir + QDir appdir(path); + QString iconPath = appdir.filePath(".DirIcon"); + if(appdir.exists(iconPath)) + icon = QIcon(iconPath); + return icon; +} + +// Scan well-known locations for apps and add to LaunchServices +AppHunter::AppHunter(QObject *p): QThread(p) +{ +} + +void AppHunter::run(void) +{ + QStringList dirs; + dirs.append("/Applications"); + dirs.append("/System/Library/CoreServices"); + dirs.append("/System/Library/Applications"); + dirs.append(QDir::homePath().append("/Applications")); + dirs.append("/usr/share/applications"); + dirs.append("/usr/local/share/applications"); + + size_t nDirs = dirs.size(); + for(size_t pos = 0; pos < nDirs; ++pos) { + QDir dir(dirs.at(pos)); + for(QString entry : dir.entryList()) { + if(entry == "." || entry == "..") + continue; + + QString filepath(dir.filePath(entry)); + QFileInfo fi(dir, entry); + + if(checkWhetherAppDirOrBundle(filepath) || entry.endsWith(".desktop", Qt::CaseInsensitive)) { + CFStringRef cfpath = CFStringCreateWithCString(NULL, filepath.toUtf8(), kCFStringEncodingUTF8); + CFURLRef url = CFURLCreateWithFileSystemPath(NULL, cfpath, kCFURLPOSIXPathStyle, true); + +// qDebug() << "Registering " << filepath; + LSRegisterURL(url, true); + CFRelease(url); + CFRelease(cfpath); + } else if(fi.isDir()) { // is a regular dir? + dirs.append(filepath); + ++nDirs; + } + } + } + // FIXME: Bus Error on thread exit without these lines. + // There is an incompatibility with QThread and objc's ARC pools + // which results in a Bus Error when the thread exits, crashing + // Filer. This little hack gets around the problem for now. + yieldCurrentThread(); + while(1) sleep(1); +} + +#endif diff --git a/src/airyx.h b/src/airyx.h new file mode 100644 index 00000000..8005f87e --- /dev/null +++ b/src/airyx.h @@ -0,0 +1,58 @@ +/* + * Glue code to integrate Filer with Airyx Cocoa frameworks + * + * Copyright (C) 2021 Zoe Knox + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#import +#import + +extern "C" void __NSInitializeProcess(int argc, const char **argv); + +// Returns the list of strings from key "ProgramArguments" in +// the bundle's Info.plist +QList programArguments(); + +// Returns true if path is an App Bundle or AppDir +bool checkWhetherAppDirOrBundle(QString path); + +// Returns the value of CFBundleDisplayName or CFBundleName +// and falls back to folder name on error +QString displayNameForBundle(QString path); + +// Returns an icon for a bundle or a generic default +QIcon getIconForBundle(QString path); + +QString getPathForMainBundle(); + +class AppHunter: public QThread { + public: + AppHunter(QObject *); + void run(); +}; diff --git a/src/application.cpp b/src/application.cpp index 0ceeb420..bc36d570 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -53,6 +53,9 @@ #include #include "dbusinterface.h" +#if defined(__AIRYX__) +#include "airyx.h" +#endif using namespace Filer; static const char* serviceName = "org.freedesktop.FileManager1"; @@ -84,6 +87,9 @@ Application::Application(int& argc, char** argv): argc_ = argc; argv_ = argv; +#if defined(__AIRYX__) + __NSInitializeProcess(argc, (const char **)argv); +#endif QDBusConnection dbus = QDBusConnection::sessionBus(); if(dbus.registerService(serviceName)) { @@ -128,6 +134,40 @@ Application::Application(int& argc, char** argv): delay(100); } } +#if defined(__AIRYX__) + // On Airyx, plasmashell provides the global menu bar and some widgets + qDebug("Waiting for services to appear on DBus..."); + bool plasmaHere(false), menuHere(false); + while(plasmaHere == false || menuHere == false) { + if(!menuHere) { + QDBusInterface* menuIface = new QDBusInterface( + QStringLiteral("com.canonical.AppMenu.Registrar"), + QStringLiteral("/com/canonical/AppMenu/Registrar")); + if (menuIface) { + if (menuIface->isValid()) { + qDebug("Global menu is available"); + menuHere = true; + } + delete menuIface; + menuIface = 0; + } + } + if(!plasmaHere) { + QDBusInterface* plasmaIface = new QDBusInterface( + QStringLiteral("org.kde.plasmashell"), + QStringLiteral("/org/kde/plasmashell")); + if (plasmaIface) { + if (plasmaIface->isValid()) { + qDebug("Plasma shell is available"); + plasmaHere = true; + } + delete plasmaIface; + plasmaIface = 0; + } + } + delay(500); + } +#endif // Check if LXQt Session is running. LXQt has it's own Desktop Folder // editor. We just hide our editor when LXQt is running. @@ -222,11 +262,19 @@ bool Application::parseCommandLineArgs() { parser.addPositionalArgument("files", tr("Files or directories to open"), tr("[FILE1, FILE2,...]")); - parser.process(arguments()); + QList args = arguments(); +#if defined(__AIRYX__) + if(args.length() <= 1) + args.append(programArguments()); +#endif + parser.process(args); if(isPrimaryInstance) { qDebug("isPrimaryInstance"); + AppHunter *apphunter = new AppHunter(this); + apphunter->start(); + if(parser.isSet(daemonOption)) daemonMode_ = true; if(parser.isSet(profileOption)) @@ -326,7 +374,22 @@ void Application::init() { translator.load("filer-qt_" + QLocale::system().name(), PCMANFM_DATA_DIR "/translations"); // qDebug("probono: Use relative path from main executable so that this works when it is not installed system-wide, too:"); // qDebug((QCoreApplication::applicationDirPath() + QString("/../share/filer-qt/translations/")).toUtf8()); // probono - translator.load("filer-qt_" + QLocale::system().name(), QCoreApplication::applicationDirPath() + QString("/../share/filer-qt/translations/")); // probono +#if defined(__AIRYX__) + CFBundleRef watashi = CFBundleGetMainBundle(); + CFURLRef bundleURL = CFBundleCopyBundleURL(watashi); + LSRegisterURL(bundleURL, true); // make sure this app is known to LaunchServices + CFRelease(bundleURL); + + CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(watashi); + CFStringRef cfResourcePath = CFURLCopyFileSystemPath(resourceURL, kCFURLPOSIXPathStyle); + QString resourcePath = QString(CFStringGetCStringPtr(cfResourcePath, kCFStringEncodingUTF8)); + CFRelease(cfResourcePath); + CFRelease(resourceURL); + CFRelease(watashi); + translator.load("filer-qt_" + QLocale::system().name(), resourcePath + "/translations"); +#else + translator.load("filer-qt_" + QLocale::system().name(), QCoreApplication::applicationDirPath() + QString("../share/filer-qt/translations")); // probono +#endif installTranslator(&translator); } @@ -559,8 +622,10 @@ void Application::setWallpaper(QString path, QString modeString) { for(int i = 0; i < G_N_ELEMENTS(valid_wallpaper_modes); ++i) { if(modeString == valid_wallpaper_modes[i]) { mode = (DesktopWindow::WallpaperMode)i; - if(mode != settings_.wallpaperMode()) + if(mode != settings_.wallpaperMode()) { + settings_.setWallpaperMode(mode); changed = true; + } break; } } diff --git a/src/bundle.cpp b/src/bundle.cpp index 612dc881..21c38552 100644 --- a/src/bundle.cpp +++ b/src/bundle.cpp @@ -1,5 +1,5 @@ // File added by probono - +#if !defined(__AIRYX__) #include "bundle.h" #include @@ -149,3 +149,4 @@ QIcon getIconForBundle(FmFileInfo* _info) } } +#endif // not __AIRYX__ diff --git a/src/desktopwindow.cpp b/src/desktopwindow.cpp index 19c5b486..b6919716 100644 --- a/src/desktopwindow.cpp +++ b/src/desktopwindow.cpp @@ -58,6 +58,9 @@ #include "ui_about.h" #include "tabpage.h" #include "trash.h" +#if defined(__AIRYX__) +#include "airyx.h" +#endif #include #include @@ -525,6 +528,10 @@ void DesktopWindow::onAbout() explicit AboutDialog(QWidget* parent = 0, Qt::WindowFlags f = 0) { ui.setupUi(this); ui.version->setText(tr("Version: %1").arg(PCMANFM_QT_VERSION)); +#if defined(__AIRYX__) + QIcon icon = getIconForBundle(getPathForMainBundle()); + ui.label_4->setPixmap(icon.pixmap(icon.availableSizes().first())); +#endif } private: Ui::AboutDialog ui; diff --git a/src/filelauncher.cpp b/src/filelauncher.cpp index 16420923..f0086fe1 100644 --- a/src/filelauncher.cpp +++ b/src/filelauncher.cpp @@ -27,7 +27,11 @@ #include "execfiledialog_p.h" #include "appchooserdialog.h" #include "utilities.h" +#if defined(__AIRYX__) +#include "airyx.h" +#else #include "bundle.h" +#endif using namespace Fm; @@ -72,15 +76,33 @@ bool FileLauncher::launchFiles(QWidget* parent, GList* file_infos) { // Since fm_launch_files needs all items to be opened in multiple tabs at once, we need // to construct a list that contains those that are not bundles GList* itemsToBeLaunched = NULL; +#if defined(__AIRYX__) + QStringList LSFiles; +#endif for(GList* l = file_infos; l; l = l->next) { FmFileInfo* info = FM_FILE_INFO(l->data); +#if defined(__AIRYX__) + QString path = QString(fm_path_to_str(fm_file_info_get_path(info))); + bool isAppDirOrBundle = checkWhetherAppDirOrBundle(path); +#else bool isAppDirOrBundle = checkWhetherAppDirOrBundle(info); +#endif if(isAppDirOrBundle == false) { +#if !defined(__AIRYX__) qDebug() << "probono: Not an .AppDir or .app bundle. TODO: Make it possible to use the 'launch' command for those, too"; +#endif // probono: URLs like network://, sftp:// and so on will continue to be handled like this in any case since they need GIO, // but documents, non-bundle executables etc. could all be handled by 'launch' if we make 'launch' understand them - itemsToBeLaunched = g_list_append(itemsToBeLaunched, l->data); +#if defined(__AIRYX__) + if(fm_file_info_is_native(info) && !fm_file_info_is_dir(info)) + LSFiles.append(path); + else +#endif + itemsToBeLaunched = g_list_append(itemsToBeLaunched, l->data); } else { +#if defined(__AIRYX__) + LSFiles.append(path); +#else QString launchableExecutable = getLaunchableExecutable(info); if(QStandardPaths::findExecutable("launch") != "") { qDebug() << "probono: Launching using the 'launch' command"; @@ -91,8 +113,28 @@ bool FileLauncher::launchFiles(QWidget* parent, GList* file_infos) { FmFileInfo* launchableExecutableFileInfo = fm_file_info_new_from_native_file(nullptr, launchableExecutable.toUtf8(),nullptr); itemsToBeLaunched = g_list_append(itemsToBeLaunched, launchableExecutableFileInfo); } +#endif } +#if defined(__AIRYX__) } + + CFMutableArrayRef CFLSFiles = CFArrayCreateMutable(NULL, LSFiles.count(), NULL); + for(QStringList::iterator f = LSFiles.begin(); f != LSFiles.end(); f++) { + CFStringRef item = CFStringCreateWithCString(NULL, f->toUtf8(), kCFStringEncodingUTF8); + CFURLRef itemURL = CFURLCreateWithFileSystemPath(NULL, item, kCFURLPOSIXPathStyle, false); + CFArrayAppendValue(CFLSFiles, itemURL); + CFRelease(item); + } + + LSLaunchURLSpec spec; + memset(&spec, 0, sizeof(spec)); + spec.appURL = NULL; + spec.itemURLs = CFLSFiles; + LSOpenFromURLSpec(&spec, NULL); + CFRelease(CFLSFiles); +#else + } +#endif bool ret = fm_launch_files(G_APP_LAUNCH_CONTEXT(context), itemsToBeLaunched, &funcs, this); g_list_free(itemsToBeLaunched); g_object_unref(context); diff --git a/src/filepropsdialog.cpp b/src/filepropsdialog.cpp index ec0f4932..a3d3f7d8 100644 --- a/src/filepropsdialog.cpp +++ b/src/filepropsdialog.cpp @@ -31,7 +31,11 @@ #include #include #include +#if defined(__AIRYX__) +#include "airyx.h" +#else #include "bundle.h" +#endif #define DIFFERENT_UIDS ((uid)-1) #define DIFFERENT_GIDS ((gid)-1) @@ -230,7 +234,12 @@ void FilePropsDialog::initPermissionsPage() { void FilePropsDialog::initGeneralPage() { +#if defined(__AIRYX__) + QString path = QString(fm_path_to_str(fm_file_info_get_path(fileInfo))); + bool isAppDirOrBundle = checkWhetherAppDirOrBundle(path); +#else bool isAppDirOrBundle = checkWhetherAppDirOrBundle(fileInfo); +#endif // probono: Set some things differently for AppDir/app bundle than for normal folder if(isAppDirOrBundle) { @@ -248,7 +257,11 @@ void FilePropsDialog::initGeneralPage() { qDebug() << "probono: fm_file_info_get_icon(fileInfo) called"; if(isAppDirOrBundle){ +#if defined(__AIRYX__) + icon = getIconForBundle(path); +#else icon = getIconForBundle(fileInfo); +#endif } } if(mimeType) { diff --git a/src/foldermodelitem.cpp b/src/foldermodelitem.cpp index 8b826609..16446c4e 100644 --- a/src/foldermodelitem.cpp +++ b/src/foldermodelitem.cpp @@ -22,7 +22,11 @@ #include #include #include +#if defined(__AIRYX__) +#include "airyx.h" +#else #include "bundle.h" +#endif using namespace Fm; @@ -31,13 +35,18 @@ FolderModelItem::FolderModelItem(FmFileInfo* _info): displayName = QString::fromUtf8(fm_file_info_get_disp_name(info)); // qDebug() << "probono: (1) FolderModelItem created for" << displayName; +#if defined(__AIRYX__) + QString path = QString(fm_path_to_str(fm_file_info_get_path(_info))); + bool isAppDirOrBundle = checkWhetherAppDirOrBundle(path); +#else bool isAppDirOrBundle = checkWhetherAppDirOrBundle(_info); +#endif icon = IconTheme::icon(fm_file_info_get_icon(_info)); // probono: Set some things differently for AppDir/app bundle than for normal folder if(isAppDirOrBundle) { - +#if !defined(__AIRYX__) QString path = QString(fm_path_to_str(fm_file_info_get_path(info))); QFileInfo fileInfo = QFileInfo(path); QString nameWithoutSuffix = QFileInfo(fileInfo.completeBaseName()).fileName(); @@ -45,14 +54,27 @@ FolderModelItem::FolderModelItem(FmFileInfo* _info): qDebug("probono: AppDir/app bundle detected xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx " + path.toUtf8()); qDebug("probono: Set different icon for AppDir/app bundle"); - icon = getIconForBundle(info); + icon = getIconForBundle(_info); +#else + icon = getIconForBundle(path); +#endif // probono: Set display name +#if defined(__AIRYX__) + fm_file_info_set_disp_name(_info, displayNameForBundle(path).toUtf8()); + + CFStringRef cfpath = CFStringCreateWithCString(NULL, path.toUtf8(), kCFStringEncodingUTF8); + CFURLRef appURL = CFURLCreateWithFileSystemPath(NULL, cfpath, kCFURLPOSIXPathStyle, true); + + LSRegisterURL(appURL, false); + CFRelease(appURL); + CFRelease(cfpath); +#else fm_file_info_set_disp_name(_info, nameWithoutSuffix.toUtf8()); // probono: Remove the suffix from display name qDebug("probono: TODO: Set the proper display name for AppDir based on Name= entries in desktop file. Similar to what happens when desktop files are displayed"); qDebug("probono: TODO: Submit it to some Launch Services like database?"); - +#endif } thumbnails.reserve(2); diff --git a/src/icons/.DS_Store b/src/icons/.DS_Store new file mode 100644 index 00000000..a5cbfd39 Binary files /dev/null and b/src/icons/.DS_Store differ diff --git a/src/icons/Filer.icns b/src/icons/Filer.icns index 8e53b9f6..91a4ffbd 100644 Binary files a/src/icons/Filer.icns and b/src/icons/Filer.icns differ diff --git a/src/icons/filer-1024.png b/src/icons/filer-1024.png index e18cd6ea..26e46fe4 100644 Binary files a/src/icons/filer-1024.png and b/src/icons/filer-1024.png differ diff --git a/src/icons/filer-128.png b/src/icons/filer-128.png index ce47053b..9a8def22 100644 Binary files a/src/icons/filer-128.png and b/src/icons/filer-128.png differ diff --git a/src/icons/filer-16.png b/src/icons/filer-16.png index ce2d768c..418df666 100644 Binary files a/src/icons/filer-16.png and b/src/icons/filer-16.png differ diff --git a/src/icons/filer-256.png b/src/icons/filer-256.png index daae3947..ec01d2c8 100644 Binary files a/src/icons/filer-256.png and b/src/icons/filer-256.png differ diff --git a/src/icons/filer-32.png b/src/icons/filer-32.png index cd44d654..9f43a7b5 100644 Binary files a/src/icons/filer-32.png and b/src/icons/filer-32.png differ diff --git a/src/icons/filer-512.png b/src/icons/filer-512.png index f0ac632e..f32fac88 100644 Binary files a/src/icons/filer-512.png and b/src/icons/filer-512.png differ diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d0340df1..c4f47beb 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -49,6 +49,9 @@ #include "windowregistry.h" #include "gotofolderwindow.h" #include "trash.h" +#if defined(__AIRYX__) +#include "airyx.h" +#endif // #include "qmodeltest/modeltest.h" @@ -701,6 +704,10 @@ void MainWindow::on_actionAbout_triggered() { explicit AboutDialog(QWidget* parent = 0, Qt::WindowFlags f = 0) { ui.setupUi(this); ui.version->setText(tr("Version: %1").arg(PCMANFM_QT_VERSION)); +#if defined(__AIRYX__) + QIcon icon = getIconForBundle(getPathForMainBundle()); + ui.label_4->setPixmap(icon.pixmap(icon.availableSizes().first())); +#endif } private: Ui::AboutDialog ui;