diff --git a/CMakeLists.txt b/CMakeLists.txt index f340712..1d08681 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,9 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) +include(GNUInstallDirs) + find_package(Qt6 COMPONENTS Core DBus Quick LinguistTools REQUIRED) -# find_package(FishUI REQUIRED) find_package(KF6KIO) find_package(KF6Solid) @@ -20,15 +21,30 @@ find_package(KF6WindowSystem) find_package(KF6Config) find_package(KF6XmlGui REQUIRED) -qt6_add_dbus_adaptor(DBUS_SOURCES - com.cutefish.FileManager.xml - application.h Application) - -add_executable(cutefish-filemanager - main.cpp - application.cpp +# Where QML modules go, so the desktop plugin lands next to FishUI. +find_program(QT_PATHS_EXECUTABLE NAMES qtpaths6 REQUIRED) +execute_process(COMMAND ${QT_PATHS_EXECUTABLE} -query QT_INSTALL_QML + OUTPUT_VARIABLE INSTALL_QMLDIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if (NOT INSTALL_QMLDIR) + message(FATAL_ERROR "qml directory cannot be detected.") +endif () + +# --------------------------------------------------------------------------- +# cutefish-filemanager-core +# +# Everything the file manager knows about files: models, jobs, thumbnails, +# dialogs, drag and drop, and the shared QML. Both the file manager window and +# the desktop QML plugin are built on top of it, so the desktop and the browser +# behave the same and there is only one place to fix a bug. +# --------------------------------------------------------------------------- +add_library(cutefish-filemanager-core STATIC + qmltypes.cpp + + # FolderModel opens its delete dialog through Window, so the shared code + # cannot live in the executable alone -- the desktop plugin needs it too. window.cpp - dbusinterface.cpp draganddrop/declarativedroparea.cpp draganddrop/declarativedragdropevent.cpp @@ -47,11 +63,10 @@ add_executable(cutefish-filemanager dialogs/createfolderdialog.cpp dialogs/filepropertiesdialog.cpp dialogs/openwithdialog.cpp + widgets/rubberband.cpp widgets/itemviewadapter.cpp - desktop/desktop.cpp - desktop/desktopview.cpp desktop/desktopsettings.cpp desktop/dockdbusinterface.cpp @@ -71,12 +86,18 @@ add_executable(cutefish-filemanager desktopiconprovider.cpp qml.qrc +) - ${DBUS_SOURCES} +# The core is linked into a shared plugin, so it has to be position independent. +set_target_properties(cutefish-filemanager-core PROPERTIES POSITION_INDEPENDENT_CODE ON) + +target_include_directories(cutefish-filemanager-core PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} ) -target_link_libraries(cutefish-filemanager - PRIVATE +target_link_libraries(cutefish-filemanager-core + PUBLIC Qt6::Core Qt6::DBus Qt6::Quick @@ -88,10 +109,30 @@ target_link_libraries(cutefish-filemanager KF6::WindowSystem KF6::ConfigCore KF6::XmlGui +) - # FishUI +# --------------------------------------------------------------------------- +# cutefish-filemanager -- the file browser window +# --------------------------------------------------------------------------- +qt6_add_dbus_adaptor(DBUS_SOURCES + com.cutefish.FileManager.xml + application.h Application) + +add_executable(cutefish-filemanager + main.cpp + application.cpp + dbusinterface.cpp + + ${DBUS_SOURCES} ) +target_link_libraries(cutefish-filemanager PRIVATE cutefish-filemanager-core) + +# --------------------------------------------------------------------------- +# The desktop, as a QML module for cutefish-shell +# --------------------------------------------------------------------------- +add_subdirectory(desktopplugin) + file(GLOB TS_FILES translations/*.ts) qt6_add_translation(QM_FILES ${TS_FILES}) add_custom_target(translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES}) diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp deleted file mode 100644 index 403d00b..0000000 --- a/desktop/desktop.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * This program 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 - * any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "desktop.h" -#include -#include - -#include -#include - -Desktop::Desktop(QObject *parent) - : QObject(parent) -{ - for (QScreen *screen : QGuiApplication::screens()) { - screenAdded(screen); - } - - connect(qApp, &QGuiApplication::screenAdded, this, &Desktop::screenAdded); - connect(qApp, &QGuiApplication::screenRemoved, this, &Desktop::screenRemoved); -} - -void Desktop::screenAdded(QScreen *screen) -{ - if (!m_list.contains(screen)) { - DesktopView *view = new DesktopView(screen); - view->show(); - m_list.insert(screen, view); - } -} - -void Desktop::screenRemoved(QScreen *screen) -{ - if (m_list.contains(screen)) { - DesktopView *view = m_list.find(screen).value(); - view->setVisible(false); - view->deleteLater(); - m_list.remove(screen); - } -} diff --git a/desktop/desktopview.cpp b/desktop/desktopview.cpp deleted file mode 100644 index 49cf914..0000000 --- a/desktop/desktopview.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: revenmartin - * - * This program 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 - * any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "desktopview.h" -#include "dockdbusinterface.h" -#include "thumbnailer/thumbnailprovider.h" -#include "desktopiconprovider.h" - -#include -#include - -#include -#include -#include - -#include - -DesktopView::DesktopView(QScreen *screen, QQuickView *parent) - : QQuickView(parent) - , m_screen(screen) -{ - m_screenRect = m_screen->geometry(); - this->setFlag(Qt::FramelessWindowHint); - this->setColor(QColor(Qt::transparent)); - KX11Extras::setType(winId(), NET::Desktop); - KX11Extras::setState(winId(), NET::KeepBelow); - - engine()->rootContext()->setContextProperty("desktopView", this); - engine()->rootContext()->setContextProperty("Dock", DockDBusInterface::self()); - QWindow::fromWinId(winId())->setOpacity(0.99); - engine()->addImageProvider("thumbnailer", new ThumbnailProvider()); - engine()->addImageProvider("icontheme", new DesktopIconProvider()); - - setTitle(tr("Desktop")); - setScreen(m_screen); - setResizeMode(QQuickView::SizeRootObjectToView); - - onGeometryChanged(); - onPrimaryScreenChanged(QGuiApplication::primaryScreen()); - - // 主屏改变 - connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DesktopView::onPrimaryScreenChanged); - - connect(m_screen, &QScreen::virtualGeometryChanged, this, &DesktopView::onGeometryChanged); - connect(m_screen, &QScreen::geometryChanged, this, &DesktopView::onGeometryChanged); -} - -QRect DesktopView::screenRect() -{ - return m_screenRect; -} - -void DesktopView::onPrimaryScreenChanged(QScreen *screen) -{ - bool isPrimaryScreen = m_screen->name() == screen->name(); - - onGeometryChanged(); - - setSource(isPrimaryScreen ? QStringLiteral("qrc:/qml/Desktop/Main.qml") - : QStringLiteral("qrc:/qml/Desktop/Wallpaper.qml")); -} - -void DesktopView::onGeometryChanged() -{ - m_screenRect = m_screen->geometry().adjusted(0, 0, 1, 1); - setGeometry(m_screenRect); - emit screenRectChanged(); -} diff --git a/desktop/desktopview.h b/desktop/desktopview.h deleted file mode 100644 index 6bbc98d..0000000 --- a/desktop/desktopview.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: revenmartin - * - * This program 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 - * any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef DESKTOPVIEW_H -#define DESKTOPVIEW_H - -#include -#include - -class Desktop; -class DesktopView : public QQuickView -{ - Q_OBJECT - Q_PROPERTY(QRect screenRect READ screenRect NOTIFY screenRectChanged) - -public: - explicit DesktopView(QScreen *screen = nullptr, QQuickView *parent = nullptr); - - QRect screenRect(); - -signals: - void screenRectChanged(); - -private slots: - void onPrimaryScreenChanged(QScreen *screen); - void onGeometryChanged(); - -private: - QScreen *m_screen; - QRect m_screenRect; -}; - -#endif // DESKTOPVIEW_H diff --git a/desktopplugin/CMakeLists.txt b/desktopplugin/CMakeLists.txt new file mode 100644 index 0000000..815f2db --- /dev/null +++ b/desktopplugin/CMakeLists.txt @@ -0,0 +1,23 @@ +# org.cutefish.filemanager.desktop +# +# Wraps the file manager core as a QML module so a shell can host the desktop +# without depending on KIO. The module installs as a normal Qt QML module, so +# `import org.cutefish.filemanager.desktop 1.0` just works. + +set(PLUGIN_TARGET cutefishdesktopplugin) +set(PLUGIN_INSTALL_DIR ${INSTALL_QMLDIR}/org/cutefish/filemanager/desktop) + +add_library(${PLUGIN_TARGET} MODULE + desktopplugin.cpp + desktopview.cpp +) + +target_link_libraries(${PLUGIN_TARGET} PRIVATE + Qt6::Core + Qt6::Qml + Qt6::Quick + cutefish-filemanager-core +) + +install(TARGETS ${PLUGIN_TARGET} DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES qmldir DESTINATION ${PLUGIN_INSTALL_DIR}) diff --git a/desktopplugin/desktopplugin.cpp b/desktopplugin/desktopplugin.cpp new file mode 100644 index 0000000..4234064 --- /dev/null +++ b/desktopplugin/desktopplugin.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "desktopview.h" +#include "qmltypes.h" + +#include +#include + +/** + * "org.cutefish.filemanager.desktop" -- the file manager's desktop, packaged so + * that any QML host (currently cutefish-shell) can place it in a window without + * linking against KIO or knowing anything about files. + */ +class CutefishDesktopPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) + +public: + void registerTypes(const char *uri) override + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("org.cutefish.filemanager.desktop")); + + CutefishFM::initResources(); + CutefishFM::registerQmlTypes(); + + qmlRegisterType(uri, 1, 0, "DesktopView"); + } + + void initializeEngine(QQmlEngine *engine, const char *uri) override + { + Q_UNUSED(uri) + + // Qt 6 only runs this for the first engine that imports the module, so + // DesktopView registers the providers itself as well. Doing it here too + // keeps them available before any desktop item is instantiated. + CutefishFM::registerImageProviders(engine); + } +}; + +#include "desktopplugin.moc" diff --git a/desktopplugin/desktopview.cpp b/desktopplugin/desktopview.cpp new file mode 100644 index 0000000..163a00d --- /dev/null +++ b/desktopplugin/desktopview.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "desktopview.h" + +#include "qmltypes.h" +#include "desktop/dockdbusinterface.h" + +#include +#include +#include +#include +#include + +static const char *kDesktopRootQml = "qrc:/qml/Desktop/Root.qml"; + +DesktopView::DesktopView(QQuickItem *parent) + : QQuickItem(parent) + , m_component(nullptr) + , m_context(nullptr) + , m_content(nullptr) + , m_primary(false) +{ + setFlag(ItemHasContents, false); + CutefishFM::initResources(); +} + +DesktopView::~DesktopView() = default; + +QScreen *DesktopView::screen() const +{ + return m_screen.data(); +} + +void DesktopView::setScreen(QScreen *screen) +{ + if (m_screen == screen) + return; + + if (m_screen) + disconnect(m_screen, nullptr, this, nullptr); + + m_screen = screen; + + if (m_screen) { + connect(m_screen, &QScreen::geometryChanged, this, &DesktopView::updateScreenRect); + connect(m_screen, &QScreen::virtualGeometryChanged, this, &DesktopView::updateScreenRect); + } + + emit screenChanged(); + updateScreenRect(); +} + +bool DesktopView::isPrimary() const +{ + return m_primary; +} + +void DesktopView::setPrimary(bool primary) +{ + if (m_primary == primary) + return; + + m_primary = primary; + emit primaryChanged(); +} + +QString DesktopView::screenName() const +{ + return m_screen ? m_screen->name() : QString(); +} + +QRect DesktopView::screenRect() const +{ + return m_screenRect; +} + +void DesktopView::updateScreenRect() +{ + const QRect rect = m_screen ? m_screen->geometry() : QRect(); + + if (m_screenRect == rect) + return; + + m_screenRect = rect; + emit screenRectChanged(); +} + +void DesktopView::componentComplete() +{ + QQuickItem::componentComplete(); + createContent(); +} + +void DesktopView::createContent() +{ + if (m_content) + return; + + QQmlEngine *engine = qmlEngine(this); + if (!engine) { + qWarning() << "DesktopView: no QML engine, cannot create the desktop."; + return; + } + + CutefishFM::registerQmlTypes(); + CutefishFM::registerImageProviders(engine); + + // A dedicated child context keeps the desktop's context properties out of + // the host's root context, so several desktops (one per screen) can live in + // one engine without seeing each other's state. + m_context = new QQmlContext(qmlContext(this), this); + m_context->setContextProperty(QStringLiteral("desktopView"), this); + m_context->setContextProperty(QStringLiteral("Dock"), DockDBusInterface::self()); + + m_component = new QQmlComponent(engine, QUrl(QString::fromLatin1(kDesktopRootQml)), this); + + if (m_component->isError()) { + qWarning() << "DesktopView: failed to load" << kDesktopRootQml << m_component->errors(); + return; + } + + QObject *object = m_component->beginCreate(m_context); + m_content = qobject_cast(object); + + if (!m_content) { + qWarning() << "DesktopView: the desktop root is not an Item." << m_component->errors(); + delete object; + return; + } + + m_content->setParentItem(this); + resizeContent(); + m_component->completeCreate(); + + if (m_component->isError()) + qWarning() << "DesktopView:" << m_component->errors(); +} + +void DesktopView::resizeContent() +{ + if (m_content) { + m_content->setPosition(QPointF(0, 0)); + m_content->setSize(size()); + } +} + +void DesktopView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + QQuickItem::geometryChange(newGeometry, oldGeometry); + resizeContent(); +} diff --git a/desktopplugin/desktopview.h b/desktopplugin/desktopview.h new file mode 100644 index 0000000..5be6708 --- /dev/null +++ b/desktopplugin/desktopview.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CUTEFISH_DESKTOPVIEW_H +#define CUTEFISH_DESKTOPVIEW_H + +#include +#include +#include + +class QQmlComponent; +class QQmlContext; +class QScreen; + +/** + * The whole Cutefish desktop as a single QML item. + * + * Everything the desktop does -- wallpaper, icons, layout, selection, drag and + * drop, context menus and file operations -- lives behind this item and reuses + * the file manager core. A host only has to place the item in a window and tell + * it which screen it is on: + * + * import org.cutefish.filemanager.desktop 1.0 + * + * DesktopView { + * anchors.fill: parent + * screen: Qt.application.screens[0] + * primary: true + * } + * + * The item owns no window state (flags, type hints, stacking); that is the + * host's job, so the same item works on X11, Wayland or inside a test harness. + */ +class DesktopView : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QScreen *screen READ screen WRITE setScreen NOTIFY screenChanged) + Q_PROPERTY(bool primary READ isPrimary WRITE setPrimary NOTIFY primaryChanged) + Q_PROPERTY(QString screenName READ screenName NOTIFY screenChanged) + Q_PROPERTY(QRect screenRect READ screenRect NOTIFY screenRectChanged) + +public: + explicit DesktopView(QQuickItem *parent = nullptr); + ~DesktopView() override; + + QScreen *screen() const; + void setScreen(QScreen *screen); + + /** + * Only the primary screen shows icons; the others show the wallpaper alone, + * which is what the standalone desktop process used to do by swapping its + * QML source. + */ + bool isPrimary() const; + void setPrimary(bool primary); + + QString screenName() const; + QRect screenRect() const; + +signals: + void screenChanged(); + void primaryChanged(); + void screenRectChanged(); + +protected: + void componentComplete() override; + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private: + void createContent(); + void updateScreenRect(); + void resizeContent(); + + QQmlComponent *m_component; + QQmlContext *m_context; + QQuickItem *m_content; + QPointer m_screen; + QRect m_screenRect; + bool m_primary; +}; + +#endif // CUTEFISH_DESKTOPVIEW_H diff --git a/desktopplugin/qmldir b/desktopplugin/qmldir new file mode 100644 index 0000000..5faebbe --- /dev/null +++ b/desktopplugin/qmldir @@ -0,0 +1,2 @@ +module org.cutefish.filemanager.desktop +plugin cutefishdesktopplugin diff --git a/main.cpp b/main.cpp index 23faa0f..17b43b6 100644 --- a/main.cpp +++ b/main.cpp @@ -18,55 +18,16 @@ */ #include "application.h" -#include "model/placesmodel.h" -#include "model/foldermodel.h" -#include "model/pathbarmodel.h" -#include "model/positioner.h" -#include "widgets/rubberband.h" -#include "widgets/itemviewadapter.h" -#include "desktop/desktop.h" -#include "desktop/desktopsettings.h" -#include "desktop/desktopview.h" -#include "helper/datehelper.h" -#include "helper/fm.h" -#include "helper/shortcut.h" - -#include "draganddrop/declarativedragdropevent.h" -#include "draganddrop/declarativedroparea.h" -#include "draganddrop/declarativemimedata.h" - -#include +#include "qmltypes.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); - // Register QML Type. - const char *uri = "Cutefish.FileManager"; - const char *dragandrop_uri = "Cutefish.DragDrop"; - - qmlRegisterType(uri, 1, 0, "PlacesModel"); - qmlRegisterType(uri, 1, 0, "FolderModel"); - qmlRegisterType(uri, 1, 0, "PathBarModel"); - qmlRegisterType(uri, 1, 0, "Positioner"); - qmlRegisterType(uri, 1, 0, "RubberBand"); - qmlRegisterType(uri, 1, 0, "ItemViewAdapter"); - qmlRegisterType(uri, 1, 0, "DesktopSettings"); - qmlRegisterType(uri, 1, 0, "Fm"); - qmlRegisterType(uri, 1, 0, "ShortCut"); - -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - qmlRegisterType(); - qmlRegisterType(); -#else - qmlRegisterAnonymousType(uri, 1); - qmlRegisterAnonymousType(dragandrop_uri, 1); -#endif - - qmlRegisterType(dragandrop_uri, 1, 0, "DropArea"); - qmlRegisterUncreatableType(dragandrop_uri, 1, 0, "MimeData", QStringLiteral("MimeData cannot be created from QML.")); - qmlRegisterUncreatableType(dragandrop_uri, 2, 0, "DragDropEvent", QStringLiteral("DragDropEvent cannot be created from QML.")); + // Same registration the desktop plugin performs, so both hosts of the + // shared QML see exactly the same types. + CutefishFM::registerQmlTypes(); Application app(argc, argv); return app.run(); diff --git a/qml.qrc b/qml.qrc index 9b5e165..f28455f 100644 --- a/qml.qrc +++ b/qml.qrc @@ -16,6 +16,7 @@ images/light/grid.svg images/light/list.svg qml/PathBar.qml + qml/Desktop/Root.qml qml/Desktop/Main.qml qml/FolderGridView.qml qml/GlobalSettings.qml diff --git a/desktop/desktop.h b/qml/Desktop/Root.qml similarity index 59% rename from desktop/desktop.h rename to qml/Desktop/Root.qml index 87e4f19..547c6e8 100644 --- a/desktop/desktop.h +++ b/qml/Desktop/Root.qml @@ -1,8 +1,6 @@ /* * Copyright (C) 2021 CutefishOS Team. * - * Author: Reion Wong - * * This program 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 @@ -17,28 +15,19 @@ * along with this program. If not, see . */ -#ifndef DESKTOP_H -#define DESKTOP_H - -#include -#include -#include - -#include "desktopview.h" - -class Desktop : public QObject -{ - Q_OBJECT - -public: - explicit Desktop(QObject *parent = nullptr); +import QtQuick 2.12 -private slots: - void screenAdded(QScreen *qscreen); - void screenRemoved(QScreen *qscreen); +// Entry point of the desktop, loaded by the DesktopView item. The primary +// screen gets the full desktop (wallpaper + icons); the others get the +// wallpaper on its own. +Loader { + id: root -private: - QMap m_list; -}; + asynchronous: false + source: desktopView.primary ? "Main.qml" : "Wallpaper.qml" -#endif // DESKTOP_H + onLoaded: { + item.width = Qt.binding(function() { return root.width }) + item.height = Qt.binding(function() { return root.height }) + } +} diff --git a/qml/Desktop/Wallpaper.qml b/qml/Desktop/Wallpaper.qml index 640e300..f52664a 100644 --- a/qml/Desktop/Wallpaper.qml +++ b/qml/Desktop/Wallpaper.qml @@ -43,8 +43,12 @@ Item { visible: settings.backgroundVisible cache: false - // Clear cache - onSourceChanged: dirModel.clearPixmapCache() + // Clear cache. On secondary screens the wallpaper is the whole + // desktop, so there is no folder model to clear. + onSourceChanged: { + if (typeof dirModel !== "undefined") + dirModel.clearPixmapCache() + } ColorOverlay { id: dimsWallpaper diff --git a/qml/GlobalSettings.qml b/qml/GlobalSettings.qml index 2fa5f54..35a3aaf 100644 --- a/qml/GlobalSettings.qml +++ b/qml/GlobalSettings.qml @@ -18,9 +18,17 @@ */ import QtQuick 2.12 -import Qt.labs.settings 1.0 +import QtCore Settings { + // Pinned to one file on purpose. This QML is loaded both by the file + // manager window and, through the desktop plugin, by cutefish-shell; the + // default location follows the host application's name, which would give + // the two hosts different preferences and silently reset the desktop's + // icon size the first time the shell started. + location: StandardPaths.writableLocation(StandardPaths.GenericConfigLocation) + + "/cutefishos/cutefish-filemanager.conf" + property int viewMethod: 1 // controls display mode: list or grid // Port to C++ diff --git a/qmltypes.cpp b/qmltypes.cpp new file mode 100644 index 0000000..a27dc50 --- /dev/null +++ b/qmltypes.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qmltypes.h" + +#include "model/placesmodel.h" +#include "model/foldermodel.h" +#include "model/pathbarmodel.h" +#include "model/positioner.h" +#include "widgets/rubberband.h" +#include "widgets/itemviewadapter.h" +#include "desktop/desktopsettings.h" +#include "helper/datehelper.h" +#include "helper/fm.h" +#include "helper/shortcut.h" +#include "desktopiconprovider.h" +#include "thumbnailer/thumbnailprovider.h" + +#include "draganddrop/declarativedragdropevent.h" +#include "draganddrop/declarativedroparea.h" +#include "draganddrop/declarativemimedata.h" + +#include +#include +#include + +// Q_INIT_RESOURCE declares an extern symbol, so it must be expanded at global +// scope rather than inside the CutefishFM namespace. +static void initCoreResources() +{ + Q_INIT_RESOURCE(qml); +} + +namespace CutefishFM { + +void registerQmlTypes() +{ + static bool registered = false; + if (registered) + return; + registered = true; + + const char *uri = "Cutefish.FileManager"; + const char *dragandrop_uri = "Cutefish.DragDrop"; + + qmlRegisterType(uri, 1, 0, "PlacesModel"); + qmlRegisterType(uri, 1, 0, "FolderModel"); + qmlRegisterType(uri, 1, 0, "PathBarModel"); + qmlRegisterType(uri, 1, 0, "Positioner"); + qmlRegisterType(uri, 1, 0, "RubberBand"); + qmlRegisterType(uri, 1, 0, "ItemViewAdapter"); + qmlRegisterType(uri, 1, 0, "DesktopSettings"); + qmlRegisterType(uri, 1, 0, "Fm"); + qmlRegisterType(uri, 1, 0, "ShortCut"); + + qmlRegisterAnonymousType(uri, 1); + qmlRegisterAnonymousType(dragandrop_uri, 1); + + qmlRegisterType(dragandrop_uri, 1, 0, "DropArea"); + qmlRegisterUncreatableType(dragandrop_uri, 1, 0, "MimeData", + QStringLiteral("MimeData cannot be created from QML.")); + qmlRegisterUncreatableType(dragandrop_uri, 2, 0, "DragDropEvent", + QStringLiteral("DragDropEvent cannot be created from QML.")); +} + +void initResources() +{ + // The core is a static library, so the resource initialiser is only pulled + // in if something references it explicitly. + initCoreResources(); +} + +void registerImageProviders(QQmlEngine *engine) +{ + if (!engine) + return; + + if (!engine->imageProvider(QStringLiteral("thumbnailer"))) + engine->addImageProvider(QStringLiteral("thumbnailer"), new ThumbnailProvider); + + if (!engine->imageProvider(QStringLiteral("icontheme"))) + engine->addImageProvider(QStringLiteral("icontheme"), new DesktopIconProvider); +} + +} diff --git a/qmltypes.h b/qmltypes.h new file mode 100644 index 0000000..69b2799 --- /dev/null +++ b/qmltypes.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * This program 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 + * any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CUTEFISH_FILEMANAGER_QMLTYPES_H +#define CUTEFISH_FILEMANAGER_QMLTYPES_H + +class QQmlEngine; + +namespace CutefishFM { + +/** + * Registers every QML type of the file manager core: the "Cutefish.FileManager" + * and "Cutefish.DragDrop" modules. + * + * Both the file manager executable and the desktop QML plugin call this, so the + * shared QML (FolderGridView, dialogs, the desktop) behaves identically in + * either host. Calling it more than once is harmless. + */ +void registerQmlTypes(); + +/** + * Makes the core's compiled-in resources (":/qml", ":/images", ":/templates") + * available. Required because the core is a static library: without an explicit + * reference the linker would drop the resource initialiser. + */ +void initResources(); + +/** + * Installs the image providers the shared QML expects ("thumbnailer" and + * "icontheme") on @p engine, unless they are already present. + * + * Qt 6 only calls QQmlExtensionPlugin::initializeEngine() for the first engine + * that imports a module, so FishUI's own "icontheme" provider is missing from + * every engine created afterwards. + */ +void registerImageProviders(QQmlEngine *engine); + +} + +#endif // CUTEFISH_FILEMANAGER_QMLTYPES_H diff --git a/window.cpp b/window.cpp index 1297503..67d1102 100644 --- a/window.cpp +++ b/window.cpp @@ -18,7 +18,7 @@ */ #include "window.h" -#include "desktopiconprovider.h" +#include "qmltypes.h" #include #include #include @@ -30,7 +30,7 @@ Window::Window(QObject *parent) // Qt6 only calls QQmlExtensionPlugin::initializeEngine() for the first engine // that imports a module, so FishUI's "icontheme" provider is missing in every // engine created afterwards. Register our own copy for each window. - addImageProvider("icontheme", new DesktopIconProvider()); + CutefishFM::registerImageProviders(this); } void Window::load(const QUrl &url)