├── src
├── ui
│ ├── first-run.h
│ ├── resources.qrc
│ ├── settings_main.cpp
│ ├── settings_dialog.h
│ ├── CMakeLists.txt
│ ├── settings_dialog.cpp
│ ├── remove.ui
│ ├── remove_main.cpp
│ ├── settings_dialog.ui
│ ├── first-run.cpp
│ ├── first-run.ui
│ ├── update_main.cpp
│ └── main.cpp
├── cli
│ ├── logging
│ │ ├── CMakeLists.txt
│ │ └── logging.h
│ ├── commands
│ │ ├── CMakeLists.txt
│ │ ├── IntegrateCommand.h
│ │ ├── CommandFactory.h
│ │ ├── Command.h
│ │ ├── CommandFactory.cpp
│ │ ├── exceptions.h
│ │ └── IntegrateCommand.cpp
│ ├── CMakeLists.txt
│ └── cli_main.cpp
├── trashbin
│ ├── CMakeLists.txt
│ ├── trashbin.h
│ └── trashbin.cpp
├── fswatcher
│ ├── CMakeLists.txt
│ ├── filesystemwatcher.h
│ └── filesystemwatcher.cpp
├── i18n
│ ├── CMakeLists.txt
│ ├── translationmanager.h
│ └── translationmanager.cpp
├── daemon
│ ├── CMakeLists.txt
│ ├── worker.h
│ ├── main.cpp
│ └── worker.cpp
├── shared
│ ├── CMakeLists.txt
│ └── shared.h
├── fusefs
│ ├── CMakeLists.txt
│ ├── fs.h
│ ├── error.h
│ └── main.cpp
└── CMakeLists.txt
├── resources
├── doc
│ └── screenshot.png
├── icons
│ ├── hicolor
│ │ ├── 128x128
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 160x160
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 16x16
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 192x192
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 256x256
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 32x32
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 384x384
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 512x512
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ ├── 64x64
│ │ │ └── apps
│ │ │ │ └── AppImageLauncher.png
│ │ └── scalable
│ │ │ └── apps
│ │ │ └── AppImageLauncher.svg
│ ├── generate-icons.sh
│ └── AppImageLauncher_inkscape.svg
├── binfmt.d
│ └── appimage.conf.in
├── appimagelauncher-lite.desktop
├── appimagelauncherd.service.in
├── appimagelaunchersettings.desktop
├── appimagelauncher.desktop
├── appimagelauncherfs.service.in
├── install-scripts
│ ├── post-uninstall.in
│ └── post-install.in
├── AppImageLauncher.1.in
├── mime
│ └── packages
│ │ └── appimage.xml
├── CMakeLists.txt
└── appimagelauncher-lite-AppRun.sh
├── i18n
├── desktopfiles.zh_Hans.json
├── desktopfiles.en.json
├── desktopfiles.es.json
├── desktopfiles.pt.json
├── desktopfiles.ru.json
├── desktopfiles.de.json
├── desktopfiles.pt_PT.json
├── desktopfiles.fr.json
├── auto-translate.py
└── CMakeLists.txt
├── .gitignore
├── .idea
└── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── .gitmodules
├── cmake
├── modules
│ ├── FindINotify.cmake
│ └── FindFUSE.cmake
├── cpack_source.cmake
├── cpack_general.cmake
├── scripts.cmake
├── reproducible_builds.cmake
├── toolchains
│ └── i386-linux-gnu.cmake
├── cpack_rpm.cmake
├── versioning.cmake
├── cpack_deb.cmake
└── install.cmake
├── travis
├── Dockerfile.build-bionic
├── Dockerfile.build-cosmic
├── Dockerfile.build-xenial
├── travis-docker.sh
├── Dockerfile.build-cosmic-i386-cross
├── Dockerfile.build-bionic-i386-cross
├── Dockerfile.build-xenial-i386-cross
├── travis-build.sh
└── build-lite.sh
├── LICENSE.txt
├── lib
└── CMakeLists.txt
├── .travis.yml
├── CMakeLists.txt
└── README.md
/src/ui/first-run.h:
--------------------------------------------------------------------------------
1 | void showFirstRunDialog();
2 |
--------------------------------------------------------------------------------
/resources/doc/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/doc/screenshot.png
--------------------------------------------------------------------------------
/i18n/desktopfiles.zh_Hans.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "从系统中移除 AppImage",
3 | "Desktop Action update/Name": "更新 AppImage"
4 | }
5 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.en.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "Remove AppImage from system",
3 | "Desktop Action update/Name": "Update AppImage"
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | cmake-build-debug*/
2 | build*/
3 | *.AppImage*
4 | *.deb*
5 | *.tar*
6 | cmake/GIT_COMMIT
7 | squashfs-root/
8 | *.qm
9 | resources/l10n/*
10 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.es.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "Eliminar Appimage del Sistema",
3 | "Desktop Action update/Name": "Actualizar Appimage"
4 | }
5 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.pt.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "Remover AppImage do sistema",
3 | "Desktop Action update/Name": "Actualizar AppImage"
4 | }
5 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.ru.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "Удалить AppImage из системы",
3 | "Desktop Action update/Name": "Обновить AppImage"
4 | }
5 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.de.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "AppImage vom System entfernen",
3 | "Desktop Action update/Name": "AppImage aktualisieren"
4 | }
5 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.pt_PT.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "Remover AppImage do sistema",
3 | "Desktop Action update/Name": "Actualizar AppImage"
4 | }
5 |
--------------------------------------------------------------------------------
/src/cli/logging/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(cli_logging INTERFACE)
2 | set_property(TARGET cli_logging PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
3 |
--------------------------------------------------------------------------------
/i18n/desktopfiles.fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "Desktop Action remove/Name": "Supprimer l'AppImage du système",
3 | "Desktop Action update/Name": "Mettre à jour l'AppImage"
4 | }
5 |
--------------------------------------------------------------------------------
/resources/icons/hicolor/128x128/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/128x128/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/160x160/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/160x160/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/16x16/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/16x16/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/192x192/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/192x192/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/256x256/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/256x256/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/32x32/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/32x32/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/384x384/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/384x384/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/512x512/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/512x512/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/resources/icons/hicolor/64x64/apps/AppImageLauncher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/probonopd/AppImageLauncher/master/resources/icons/hicolor/64x64/apps/AppImageLauncher.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/binfmt.d/appimage.conf.in:
--------------------------------------------------------------------------------
1 | # Launch AppImages with AppImageLauncher
2 | :appimage-type1:M:8:AI\x01::@CMAKE_INSTALL_PREFIX@/bin/AppImageLauncher:
3 | :appimage-type2:M:8:AI\x02::@CMAKE_INSTALL_PREFIX@/bin/AppImageLauncher:
4 |
--------------------------------------------------------------------------------
/src/ui/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ../../resources/icons/hicolor/scalable/apps/AppImageLauncher.svg
5 |
6 |
7 |
--------------------------------------------------------------------------------
/resources/appimagelauncher-lite.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=appimagelauncher-lite
3 | Exec=appimagelauncher-lite
4 | Icon=AppImageLauncher
5 | Type=Application
6 | X-AppImage-Integrate=false
7 | NoDisplay=true
8 | Categories=Utility;
9 |
--------------------------------------------------------------------------------
/src/trashbin/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(trashbin STATIC trashbin.cpp trashbin.h)
2 | target_link_libraries(trashbin PUBLIC Qt5::Core libappimage shared)
3 | target_include_directories(translationmanager PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
4 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/AppImageUpdate"]
2 | path = lib/AppImageUpdate
3 | url = https://github.com/AppImage/AppImageUpdate.git
4 | [submodule "lib/libappimage"]
5 | path = lib/libappimage
6 | url = https://github.com/AppImage/libappimage.git
7 |
--------------------------------------------------------------------------------
/src/fswatcher/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(filesystemwatcher STATIC filesystemwatcher.cpp filesystemwatcher.h)
2 | target_link_libraries(filesystemwatcher PUBLIC Qt5::Core)
3 | target_include_directories(filesystemwatcher PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
4 |
--------------------------------------------------------------------------------
/resources/appimagelauncherd.service.in:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=AppImageLauncher daemon
3 |
4 | [Service]
5 | ExecStart=@CMAKE_INSTALL_PREFIX@/bin/appimagelauncherd
6 | Restart=on-failure
7 | RestartSec=10
8 |
9 | [Install]
10 | WantedBy=default.target
11 |
--------------------------------------------------------------------------------
/src/ui/settings_main.cpp:
--------------------------------------------------------------------------------
1 | // libraries
2 | #include
3 |
4 | // local
5 | #include "settings_dialog.h"
6 |
7 | int main(int argc, char** argv) {
8 | QApplication app(argc, argv);
9 | SettingsDialog dialog;
10 | dialog.show();
11 |
12 | return app.exec();
13 | }
14 |
--------------------------------------------------------------------------------
/src/i18n/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(translationmanager translationmanager.cpp translationmanager.h)
2 | target_link_libraries(translationmanager PUBLIC Qt5::Core Qt5::Widgets)
3 | target_include_directories(translationmanager PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
4 | add_dependencies(translationmanager l10n)
5 |
--------------------------------------------------------------------------------
/resources/appimagelaunchersettings.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=1.0
3 | Type=Application
4 | Exec=AppImageLauncherSettings %f
5 | Name=AppImageLauncher Settings
6 | Icon=AppImageLauncher
7 | Terminal=false
8 | Categories=Utility;
9 | X-AppImage-Integrate=false
10 | StartupWMClass=AppImageLauncher
11 |
--------------------------------------------------------------------------------
/src/cli/commands/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(cli_commands STATIC Command.h CommandFactory.cpp CommandFactory.h IntegrateCommand.cpp IntegrateCommand.h exceptions.h)
2 | target_link_libraries(cli_commands PUBLIC Qt5::Core shared cli_logging)
3 | target_include_directories(cli_commands PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
4 |
--------------------------------------------------------------------------------
/src/cli/logging/logging.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system headers
4 | #include
5 |
6 | // library headers
7 | #include
8 | #include
9 |
10 | // wrapper for stdout
11 | #define qout() QTextStream(stdout, QIODevice::WriteOnly)
12 |
13 | // wrapper for stderr
14 | #define qerr() QTextStream(stderr, QIODevice::WriteOnly)
15 |
--------------------------------------------------------------------------------
/resources/appimagelauncher.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=1.0
3 | Type=Application
4 | Exec=AppImageLauncher %f
5 | Name=AppImageLauncher
6 | Icon=AppImageLauncher
7 | Terminal=false
8 | Categories=Utility;
9 | MimeType=application/x-iso9660-appimage;application/x-appimage;application/vnd.appimage;
10 | NoDisplay=true
11 | X-AppImage-Integrate=false
12 | StartupWMClass=AppImageLauncher
13 |
--------------------------------------------------------------------------------
/src/cli/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(logging)
2 |
3 | add_subdirectory(commands)
4 |
5 | add_executable(ail-cli cli_main.cpp)
6 | target_link_libraries(ail-cli PUBLIC cli_commands cli_logging)
7 |
8 | set_property(
9 | TARGET ail-cli
10 | PROPERTY INSTALL_RPATH ${_rpath}
11 | )
12 |
13 | install(
14 | TARGETS ail-cli
15 | DESTINATION ${_bindir} COMPONENT APPIMAGELAUNCHER_CLI
16 | )
17 |
--------------------------------------------------------------------------------
/src/daemon/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # daemon binary
2 | add_executable(appimagelauncherd main.cpp worker.cpp worker.h)
3 | target_link_libraries(appimagelauncherd shared filesystemwatcher PkgConfig::glib libappimage)
4 | set_target_properties(appimagelauncherd PROPERTIES INSTALL_RPATH ${_rpath})
5 |
6 | install(
7 | TARGETS
8 | appimagelauncherd
9 | RUNTIME DESTINATION ${_bindir} COMPONENT APPIMAGELAUNCHER
10 | LIBRARY DESTINATION ${_libdir} COMPONENT APPIMAGELAUNCHER
11 | )
12 |
--------------------------------------------------------------------------------
/src/cli/commands/IntegrateCommand.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // local headers
4 | #include "Command.h"
5 |
6 | namespace appimagelauncher {
7 | namespace cli {
8 | namespace commands {
9 | /**
10 | * Integrates AppImages passed as arguments on the commandline.
11 | */
12 | class IntegrateCommand : public Command {
13 | void exec(QList arguments) final;
14 | };
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/cmake/modules/FindINotify.cmake:
--------------------------------------------------------------------------------
1 | find_path(INOTIFY_INCLUDE_DIR sys/inotify.h PATH_SUFFIXES inotify)
2 | find_library(INOTIFY_LIBRARY inotify)
3 |
4 | include(FindPackageHandleStandardArgs)
5 | find_package_handle_standard_args(INotify DEFAULT_MSG INOTIFY_INCLUDE_DIR)
6 |
7 | IF(INOTIFY_FOUND)
8 | set(INotify_INCLUDE_DIRS ${INOTIFY_INCLUDE_DIR})
9 |
10 | add_library(inotify IMPORTED INTERFACE)
11 | set_property(TARGET inotify PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INOTIFY_INCLUDE_DIRS})
12 | ENDIF(INOTIFY_FOUND)
13 |
--------------------------------------------------------------------------------
/src/shared/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(shared STATIC shared.h shared.cpp)
2 | target_link_libraries(shared PUBLIC PkgConfig::glib Qt5::Core Qt5::Widgets Qt5::DBus libappimage translationmanager trashbin)
3 | if(ENABLE_UPDATE_HELPER)
4 | target_link_libraries(shared PUBLIC libappimageupdate)
5 | endif()
6 | target_compile_definitions(shared
7 | PRIVATE -DPRIVATE_LIBDIR="${_private_libdir}"
8 | PRIVATE -DCMAKE_PROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}"
9 | )
10 | target_include_directories(shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
11 |
--------------------------------------------------------------------------------
/src/cli/commands/CommandFactory.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system headers
4 | #include
5 |
6 | // library headers
7 | #include
8 |
9 | // local headers
10 | #include
11 |
12 | /**
13 | * Creates Commands.
14 | */
15 |
16 | namespace appimagelauncher {
17 | namespace cli {
18 | namespace commands {
19 | class CommandFactory {
20 | public:
21 | static std::shared_ptr getCommandByName(const QString&);
22 | };
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/resources/appimagelauncherfs.service.in:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=AppImageLauncherFS daemon
3 | Before=display-manager.service
4 |
5 | [Service]
6 | Type=exec
7 | ExecStart=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/appimagelauncherfs
8 | Restart=always
9 | RestartSec=2
10 |
11 | [Install]
12 | # multi-user.target etc. seem to be buggy on some systems, it may not even exist on some systems
13 | # can be checked with systemctl --user list-units --type target
14 | # default seems to work better -- thanks @smac89 for the hint
15 | WantedBy=default.target
16 |
--------------------------------------------------------------------------------
/src/cli/commands/Command.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system headers
4 | #include
5 |
6 | // library headers
7 | #include
8 | #include
9 |
10 | namespace appimagelauncher {
11 | namespace cli {
12 | namespace commands {
13 | /**
14 | * Base class for CLI command implementations.
15 | */
16 | class Command {
17 | public:
18 | // Run the command.
19 | virtual void exec(QList arguments) = 0;
20 | };
21 | }
22 | }
23 | }
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/cli/commands/CommandFactory.cpp:
--------------------------------------------------------------------------------
1 | // local headers
2 | #include "CommandFactory.h"
3 | #include "IntegrateCommand.h"
4 | #include "exceptions.h"
5 |
6 |
7 | namespace appimagelauncher {
8 | namespace cli {
9 | namespace commands {
10 | std::shared_ptr CommandFactory::getCommandByName(const QString& commandName) {
11 | if (commandName == "integrate")
12 | return std::shared_ptr(new IntegrateCommand);
13 |
14 | throw CommandNotFoundError(commandName);
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/daemon/worker.h:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 |
4 | // library includes
5 | #include
6 |
7 | #pragma once
8 |
9 | class Worker : public QObject {
10 | Q_OBJECT
11 |
12 | private:
13 | class PrivateData;
14 | std::shared_ptr d = nullptr;
15 |
16 | public:
17 | Worker();
18 |
19 | signals:
20 | void startTimer();
21 |
22 | public slots:
23 | void scheduleForIntegration(const QString& path);
24 | void scheduleForUnintegration(const QString& path);
25 |
26 | public slots:
27 | void executeDeferredOperations();
28 |
29 | private slots:
30 | void startTimerIfNecessary();
31 | };
32 |
--------------------------------------------------------------------------------
/src/i18n/translationmanager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // library includes
4 | #include
5 | #include
6 | #include
7 |
8 | /*
9 | * Installs translations for AppImageLauncher UIs in a Qt application.
10 | *
11 | * You need to keep instances of this alive until the application is terminated.
12 | */
13 | class TranslationManager {
14 | private:
15 | const QCoreApplication& app;
16 | QList installedTranslators;
17 |
18 | public:
19 | explicit TranslationManager(QCoreApplication& app);
20 | ~TranslationManager();
21 |
22 | public:
23 | // get translation dir
24 | static QString getTranslationDir();
25 | };
26 |
--------------------------------------------------------------------------------
/src/trashbin/trashbin.h:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 |
4 | #pragma once
5 |
6 | class TrashBin {
7 | private:
8 | class PrivateData;
9 | PrivateData* d;
10 |
11 | public:
12 | TrashBin();
13 |
14 | public:
15 | QString path();
16 |
17 | public:
18 | // move AppImage into trash bin directory
19 | bool disposeAppImage(const QString& pathToAppImage);
20 |
21 | // check all AppImages in trash bin whether they can be removed
22 | // this function should be called regularly to make sure the files in the trash bin are cleaned up as soon
23 | // as possible
24 | bool cleanUp();
25 | };
26 |
--------------------------------------------------------------------------------
/cmake/modules/FindFUSE.cmake:
--------------------------------------------------------------------------------
1 | find_path(FUSE_INCLUDE_DIR fuse.h
2 | /usr/include
3 | /usr/include/x86_64-linux-gnu
4 | /usr/include/i386-linux-gnu
5 | )
6 |
7 | find_library(FUSE_LIBRARY fuse)
8 |
9 | include(FindPackageHandleStandardArgs)
10 | find_package_handle_standard_args("FUSE" DEFAULT_MSG FUSE_INCLUDE_DIR FUSE_LIBRARY)
11 |
12 | mark_as_advanced(FUSE_INCLUDE_DIR FUSE_LIBRARY)
13 |
14 | message(STATUS "Found FUSE: ${FUSE_LIBRARY} (include dirs: ${FUSE_INCLUDE_DIR})")
15 |
16 | add_library(libfuse IMPORTED SHARED)
17 | set_property(TARGET libfuse PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${FUSE_INCLUDE_DIR}")
18 | set_property(TARGET libfuse PROPERTY IMPORTED_LOCATION "${FUSE_LIBRARY}")
19 |
--------------------------------------------------------------------------------
/src/ui/settings_dialog.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system
4 | #include
5 |
6 | // libraries
7 | #include
8 | #include
9 |
10 |
11 | namespace Ui {
12 | class SettingsDialog;
13 | }
14 |
15 | class SettingsDialog : public QDialog {
16 | Q_OBJECT
17 |
18 | public:
19 | explicit SettingsDialog(QWidget* parent = nullptr);
20 |
21 | ~SettingsDialog() override;
22 |
23 | protected slots:
24 | void onChooseAppsDirClicked();
25 |
26 | void onDialogAccepted();
27 |
28 | private:
29 | void loadSettings();
30 |
31 | void saveSettings();
32 |
33 | void toggleDaemon();
34 |
35 | Ui::SettingsDialog* ui;
36 | std::shared_ptr settingsFile;
37 | };
38 |
--------------------------------------------------------------------------------
/src/fusefs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # use latest FUSE API
2 | add_definitions(-DFUSE_USE_VERSION=26)
3 | # required by FUSE
4 | add_definitions(-D_FILE_OFFSET_BITS=64)
5 |
6 | if(NOT TARGET libfuse)
7 | find_package(FUSE REQUIRED)
8 | endif()
9 |
10 | set(Boost_USE_STATIC_LIBS ON)
11 | find_package(Boost REQUIRED COMPONENTS filesystem)
12 |
13 | add_executable(appimagelauncherfs main.cpp fs.cpp fs.h error.h)
14 | target_link_libraries(appimagelauncherfs PUBLIC libfuse Boost::filesystem)
15 |
16 | # ISO C++ spawns annoying warnings about string literals
17 | target_compile_options(appimagelauncherfs PRIVATE -Wno-write-strings)
18 |
19 | install(
20 | TARGETS appimagelauncherfs COMPONENT APPIMAGELAUNCHERFS
21 | RUNTIME DESTINATION ${_bindir}
22 | )
23 |
--------------------------------------------------------------------------------
/resources/install-scripts/post-uninstall.in:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo "Removing AppImageLauncher as interpreter for AppImages"
4 |
5 | UPDATE_BINFMTS=update-binfmts
6 |
7 | if ! (type "$UPDATE_BINFMTS" &>/dev/null) && ! (which "$UPDATE_BINFMTS" &>/dev/null); then
8 | UPDATE_BINFMTS=@CMAKE_INSTALL_PREFIX@/lib/appimagelauncher/update-binfmts
9 |
10 | if [ ! -f "$UPDATE_BINFMTS" ]; then
11 | UPDATE_BINFMTS=
12 | fi
13 | fi
14 |
15 | if [ "$UPDATE_BINFMTS" != "" ]; then
16 | (set -x; "$UPDATE_BINFMTS" --package appimage --remove appimage-type1 @CMAKE_INSTALL_PREFIX@/bin/AppImageLauncher)
17 | (set -x; "$UPDATE_BINFMTS" --package appimage --remove appimage-type2 @CMAKE_INSTALL_PREFIX@/bin/AppImageLauncher)
18 | else
19 | (set -x; systemctl restart systemd-binfmt)
20 | fi
21 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/resources/icons/generate-icons.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | set -e
4 |
5 | if ! (which inkscape &>/dev/null); then
6 | echo "Error: this tool requires inkscape" >&2
7 | exit 1
8 | fi
9 |
10 | cd $(dirname "$0")
11 |
12 | # create directory structure
13 | mkdir -p hicolor/scalable/apps
14 | inkscape --export-plain-svg=hicolor/scalable/apps/AppImageLauncher.svg AppImageLauncher_inkscape.svg
15 |
16 | for res in 16 32 64 128 160 192 256 384 512; do
17 | fullres="${res}x${res}"
18 | echo "Generating PNG for resolution $fullres"
19 |
20 | mkdir -p hicolor/"$fullres"/apps
21 |
22 | inkscape -w "$res" -h "$res" -e hicolor/"$fullres"/apps/AppImageLauncher.png AppImageLauncher_inkscape.svg
23 | # rsvg-convert -w "$res" -h "$res" AppImageLauncher_inkscape.svg > hicolor/"$fullres"/apps/AppImageLauncher.png
24 | done
25 |
--------------------------------------------------------------------------------
/cmake/cpack_source.cmake:
--------------------------------------------------------------------------------
1 | # source package options
2 |
3 | # ignore files
4 | # requires four backslashes to escape dots etc., probably because the values are evaluated twice,
5 | # once by CMake and then by CPack
6 | set(CPACK_SOURCE_IGNORE_FILES
7 | # warning: the following pattern requires at least 6 characters before the "build" part to work as intended
8 | "([^t][^r][^a][^v][^i][^s])/.*build.*/"
9 | "/.*-prefix/"
10 | "\\\\..*AppImage$"
11 | "\\\\..*AppImage\\\\..*$"
12 | "\\\\..*zs-old.*$"
13 | "\\\\..*tar.*$"
14 | "\\\\..*deb.*$"
15 | "/.git/"
16 | "/.idea/"
17 | )
18 |
19 | # source tarball filename (without extension)
20 | set(CPACK_SOURCE_PACKAGE_FILE_NAME appimagelauncher-git${APPIMAGELAUNCHER_GIT_COMMIT_DATE_SHORT}.${APPIMAGELAUNCHER_GIT_COMMIT}.source)
21 |
22 | # build .tar.xz archives to get the maximum amount of compression and produce small tarballs
23 | set(CPACK_SOURCE_GENERATOR TXZ)
24 |
--------------------------------------------------------------------------------
/i18n/auto-translate.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 |
3 | import sys
4 |
5 | from xml.etree import ElementTree as ET
6 |
7 |
8 | def copy_sources_to_translations(root: ET.Element):
9 | for context in root.findall("context"):
10 | for message in context.findall("message"):
11 | source = message.find("source")
12 | translation = message.find("translation")
13 |
14 | translation.text = source.text
15 |
16 | if "type" in translation.attrib:
17 | if translation.attrib["type"] in ("", "unfinished"):
18 | del translation.attrib["type"]
19 |
20 |
21 | def main():
22 | with open(sys.argv[1]) as f:
23 | et = ET.parse(f)
24 |
25 | root = et.getroot()
26 |
27 | copy_sources_to_translations(root)
28 |
29 | with open(sys.argv[1], "wb") as f:
30 | f.write(ET.tostring(root))
31 |
32 |
33 | if __name__ == "__main__":
34 | main()
35 |
--------------------------------------------------------------------------------
/travis/Dockerfile.build-bionic:
--------------------------------------------------------------------------------
1 | # used to cache installed dependencies for bionic builds
2 | # this speeds up builds during development, as the dependencies are just installed _once_
3 |
4 | FROM ubuntu:bionic
5 |
6 | RUN apt-get update && \
7 | apt-get -y --no-install-recommends install qt5-default \
8 | qtbase5-dev \
9 | qt5-qmake \
10 | libcurl4-openssl-dev \
11 | libfuse-dev \
12 | desktop-file-utils \
13 | libglib2.0-dev \
14 | libcairo2-dev \
15 | libssl-dev \
16 | ca-certificates \
17 | libbsd-dev \
18 | qttools5-dev-tools \
19 | \
20 | gcc \
21 | g++ \
22 | cmake \
23 | make \
24 | git \
25 | automake \
26 | autoconf \
27 | libtool \
28 | patch \
29 | wget \
30 | vim-common \
31 | desktop-file-utils \
32 | pkg-config \
33 | libarchive-dev \
34 | libboost-filesystem-dev
35 |
--------------------------------------------------------------------------------
/travis/Dockerfile.build-cosmic:
--------------------------------------------------------------------------------
1 | # used to cache installed dependencies for bionic builds
2 | # this speeds up builds during development, as the dependencies are just installed _once_
3 |
4 | FROM ubuntu:cosmic
5 |
6 | RUN apt-get update && \
7 | apt-get -y --no-install-recommends install qt5-default \
8 | qtbase5-dev \
9 | qt5-qmake \
10 | libcurl4-openssl-dev \
11 | libfuse-dev \
12 | desktop-file-utils \
13 | libglib2.0-dev \
14 | libcairo2-dev \
15 | libssl-dev \
16 | ca-certificates \
17 | libbsd-dev \
18 | qttools5-dev-tools \
19 | \
20 | gcc \
21 | g++ \
22 | cmake \
23 | make \
24 | git \
25 | automake \
26 | autoconf \
27 | libtool \
28 | patch \
29 | wget \
30 | vim-common \
31 | desktop-file-utils \
32 | pkg-config \
33 | libarchive-dev \
34 | libboost-filesystem-dev
35 |
--------------------------------------------------------------------------------
/src/fswatcher/filesystemwatcher.h:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 |
4 | // library includes
5 | #include
6 | #include
7 | #include
8 |
9 | #pragma once
10 |
11 | class FileSystemWatcherError : public std::runtime_error {
12 | public:
13 | FileSystemWatcherError(const QString& message) : std::runtime_error(message.toStdString().c_str()) {};
14 | };
15 |
16 | class FileSystemWatcher : public QObject {
17 | Q_OBJECT
18 |
19 | private:
20 | class PrivateData;
21 | std::shared_ptr d;
22 |
23 | public:
24 | explicit FileSystemWatcher(const QString& path);
25 | explicit FileSystemWatcher(const QStringList& paths);
26 | FileSystemWatcher();
27 |
28 | public:
29 | bool startWatching();
30 | bool stopWatching();
31 |
32 | public slots:
33 | void readEvents();
34 |
35 | public:
36 | QStringList directories();
37 |
38 | signals:
39 | void fileChanged(QString path);
40 | void fileRemoved(QString path);
41 | };
42 |
--------------------------------------------------------------------------------
/travis/Dockerfile.build-xenial:
--------------------------------------------------------------------------------
1 | # used to cache installed dependencies for bionic builds
2 | # this speeds up builds during development, as the dependencies are just installed _once_
3 |
4 | FROM ubuntu:bionic
5 |
6 | RUN apt-get update && \
7 | apt-get -y --no-install-recommends install qt5-default \
8 | qtbase5-dev \
9 | qt5-qmake \
10 | libcurl4-openssl-dev \
11 | libfuse-dev \
12 | desktop-file-utils \
13 | libglib2.0-dev \
14 | libcairo2-dev \
15 | libssl-dev \
16 | ca-certificates \
17 | libbsd-dev \
18 | qttools5-dev-tools \
19 | \
20 | rpm \
21 | gcc \
22 | g++ \
23 | cmake \
24 | make \
25 | git \
26 | automake \
27 | autoconf \
28 | libtool \
29 | patch \
30 | wget \
31 | vim-common \
32 | desktop-file-utils \
33 | pkg-config \
34 | libarchive-dev \
35 | libboost-filesystem-dev
36 |
--------------------------------------------------------------------------------
/travis/travis-docker.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | if [ "$1" == "" ]; then
4 | echo "Usage: $0 "
5 | exit 1
6 | fi
7 |
8 | set -x
9 | set -e
10 |
11 | export DOCKER_DIST="$1"
12 |
13 | cd $(readlink -f $(dirname "$0"))
14 |
15 | IMAGE=appimagelauncher-build:"$DOCKER_DIST"
16 | DOCKERFILE=Dockerfile.build-"$DOCKER_DIST"
17 |
18 | if [ ! -f "$DOCKERFILE" ]; then
19 | echo "Error: $DOCKERFILE could not be found"
20 | exit 1
21 | fi
22 |
23 | if [ "$ARCH" == "i386" ]; then
24 | IMAGE=appimagelauncher-build:"$DOCKER_DIST"-i386-cross
25 | DOCKERFILE=Dockerfile.build-"$DOCKER_DIST"-i386-cross
26 | fi
27 |
28 | docker build -t "$IMAGE" -f "$DOCKERFILE" .
29 |
30 | if [[ "$BUILD_LITE" == "" ]]; then
31 | build_script=travis-build.sh
32 | else
33 | build_script=build-lite.sh
34 | fi
35 |
36 | docker run -e ARCH -e TRAVIS_BUILD_NUMBER --rm -it -v $(readlink -f ..):/ws "$IMAGE" \
37 | bash -xc "export CI=1 && export DEBIAN_DIST=\"$DOCKER_DIST\" && cd /ws && source travis/$build_script"
38 |
--------------------------------------------------------------------------------
/resources/install-scripts/post-install.in:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo "Installing AppImageLauncher as interpreter for AppImages"
4 |
5 | # as there's no _real_ package that we could use as a dependency to take care of the kernel module,
6 | # we need to make sure that the kernel module is loaded manually
7 | modprobe -v binfmt_misc
8 |
9 | UPDATE_BINFMTS=update-binfmts
10 |
11 | if ! (type "$UPDATE_BINFMTS" &>/dev/null) && ! (which "$UPDATE_BINFMTS" &>/dev/null); then
12 | UPDATE_BINFMTS=@CMAKE_INSTALL_PREFIX@/lib/appimagelauncher/update-binfmts
13 |
14 | if [ ! -f "$UPDATE_BINFMTS" ]; then
15 | UPDATE_BINFMTS=
16 | fi
17 | fi
18 |
19 | if [ "$UPDATE_BINFMTS" != "" ]; then
20 | mkdir -p /var/lib/binfmts
21 |
22 | (set -x; "$UPDATE_BINFMTS" --package appimage --install appimage-type1 @CMAKE_INSTALL_PREFIX@/bin/AppImageLauncher --magic 'AI\x01' --offset 8)
23 | (set -x; "$UPDATE_BINFMTS" --package appimage --install appimage-type2 @CMAKE_INSTALL_PREFIX@/bin/AppImageLauncher --magic 'AI\x02' --offset 8)
24 | else
25 | (set -x; systemctl restart systemd-binfmt)
26 | fi
27 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018-2019 TheAssassin
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/src/fusefs/fs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system includes
4 | #include
5 | #include
6 |
7 | // library includes
8 | #include
9 |
10 | class AppImageLauncherFS {
11 | private:
12 | class PrivateData;
13 | std::shared_ptr d;
14 |
15 | static std::shared_ptr instance;
16 |
17 | // this class is a singleton
18 | // therefore, no public constructor, no copying, and no public constructor, but a getInstance() method
19 | private:
20 | // constructor doesn't take any arguments
21 | AppImageLauncherFS();
22 |
23 | // private copy constructor = no copies
24 | AppImageLauncherFS(const AppImageLauncherFS&);
25 | // same goes for the assignment operator
26 | AppImageLauncherFS& operator=(const AppImageLauncherFS&);
27 |
28 | public:
29 | static std::shared_ptr getInstance();
30 |
31 | public:
32 | // returns calculated mountpoint directory path
33 | std::string mountpoint();
34 |
35 | // returns a FUSE style list of operations that can be passed to fuse_main etc.
36 | // you should prefer using run()
37 | std::shared_ptr operations() const;
38 |
39 | // runs filesystem with FUSE
40 | // returns exit code received from FUSE
41 | int run();
42 | };
43 |
--------------------------------------------------------------------------------
/src/cli/commands/exceptions.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system headers
4 | #include
5 |
6 | // library headers
7 | #include
8 |
9 | namespace appimagelauncher {
10 | namespace cli {
11 | namespace commands {
12 | class CliError : public std::runtime_error {
13 | public:
14 | explicit CliError(const QString& message) : std::runtime_error(message.toStdString()) {}
15 | };
16 |
17 | class CommandNotFoundError : public std::runtime_error {
18 | private:
19 | QString commandName;
20 |
21 | public:
22 | explicit CommandNotFoundError(const QString& commandName) : std::runtime_error(
23 | "No such command available: " + commandName.toStdString()), commandName(commandName) {}
24 |
25 | QString getCommandName() const {
26 | return commandName;
27 | }
28 | };
29 |
30 | class UsageError : public CliError {
31 | public:
32 | using CliError::CliError;
33 | };
34 |
35 | class InvalidArgumentsError : public UsageError {
36 | public:
37 | using UsageError::UsageError;
38 | };
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/cmake/cpack_general.cmake:
--------------------------------------------------------------------------------
1 | # general CPack options
2 |
3 | set(PROJECT_VERSION ${APPIMAGELAUNCHER_VERSION})
4 | set(CPACK_GENERATOR "DEB")
5 |
6 | # make sure to only package APPIMAGELAUNCHER and APPIMAGELAUNCHERFS components
7 | set(CPACK_COMPONENTS_ALL APPIMAGELAUNCHER APPIMAGELAUNCHER_CLI)
8 | if(NOT USE_SYSTEM_APPIMAGELAUNCHERFS)
9 | list(APPEND CPACK_COMPONENTS_ALL APPIMAGELAUNCHERFS)
10 | endif()
11 | # package them all in a single package, otherwise cpack would generate one package per component by default
12 | # https://cmake.org/cmake/help/v3.0/module/CPackComponent.html#variable:CPACK_COMPONENTS_GROUPING
13 | set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE)
14 |
15 | # global options
16 | set(CPACK_PACKAGE_CONTACT "TheAssassin")
17 | set(CPACK_PACKAGE_HOMEPAGE "https://github.com/TheAssassin/AppImageLauncher")
18 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
19 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE.txt")
20 |
21 | # versioning
22 | # it appears setting CPACK_DEBIAN_PACKAGE_VERSION doesn't work, hence setting CPACK_PACKAGE_VERSION
23 | set(CPACK_PACKAGE_VERSION ${APPIMAGELAUNCHER_VERSION})
24 |
25 | # TODO: insert some useful description
26 | set(CPACK_COMPONENT_APPIMAGELAUNCHER_PACKAGE_DESCRIPTION "AppImageLauncher")
27 |
28 | # find more suitable section for package
29 | set(CPACK_COMPONENT_APPIMAGELAUNCHER_PACKAGE_SECTION misc)
30 |
--------------------------------------------------------------------------------
/lib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # required for pkg-config module's imported target feature
2 | cmake_minimum_required(VERSION 3.6)
3 |
4 | # note for self: include libappimage before AppImageUpdate to use the version here, not the one shipped with AppImageUpdate
5 | # the AppImageUpdate submodule tends to be out of date
6 | if(NOT USE_SYSTEM_LIBAPPIMAGE)
7 | add_subdirectory(libappimage EXCLUDE_FROM_ALL)
8 | endif()
9 |
10 | # used by the update helper
11 | if(ENABLE_UPDATE_HELPER)
12 | add_subdirectory(AppImageUpdate EXCLUDE_FROM_ALL)
13 | endif()
14 |
15 | if(TRAVIS_BUILD)
16 | # TODO: use latest version of CMake once it contains the following change:
17 | # https://gitlab.kitware.com/cmake/cmake/commit/00a9d133fb2838ebb756d684659c5d51f577ede3
18 | # when this is available, the workaround here isn't necessary any more, instead install(TARGETS ...) can be used
19 | # and the BUILD_WITH_INSTALL_RPATH property doesn't need to be set any more
20 | message(WARNING "TRAVIS_BUILD is set to ON, binaries can only be tested after installation!")
21 | set(DEPS_RPATH "\$ORIGIN")
22 | set_property(TARGET libappimageupdate PROPERTY INSTALL_RPATH ${DEPS_RPATH})
23 | set_property(TARGET libappimageupdate PROPERTY BUILD_WITH_INSTALL_RPATH ON)
24 | set_property(TARGET libappimageupdate-qt PROPERTY INSTALL_RPATH ${DEPS_RPATH})
25 | set_property(TARGET libappimageupdate-qt PROPERTY BUILD_WITH_INSTALL_RPATH ON)
26 | endif()
27 |
--------------------------------------------------------------------------------
/cmake/scripts.cmake:
--------------------------------------------------------------------------------
1 | # borrowed from libappimage
2 | if(NOT COMMAND check_program)
3 | function(check_program)
4 | set(keywords FORCE_PREFIX)
5 | set(oneValueArgs NAME)
6 | cmake_parse_arguments(ARG "${keywords}" "${oneValueArgs}" "" "${ARGN}")
7 |
8 | if(NOT ARG_NAME)
9 | message(FATAL_ERROR "NAME argument required for check_program")
10 | endif()
11 |
12 | if(TOOLS_PREFIX)
13 | set(prefix ${TOOLS_PREFIX})
14 | endif()
15 |
16 | message(STATUS "Checking for program ${ARG_NAME}")
17 |
18 | string(TOUPPER ${ARG_NAME} name_upper)
19 |
20 | if(prefix)
21 | # try prefixed version first
22 | find_program(${name_upper} ${prefix}${ARG_NAME})
23 | endif()
24 |
25 | # try non-prefixed version
26 | if(NOT ${name_upper})
27 | if(TOOLS_PREFIX AND ARG_FORCE_PREFIX)
28 | message(FATAL_ERROR "TOOLS_PREFIX set, but could not find program with prefix in PATH (FORCE_PREFIX is set)")
29 | endif()
30 |
31 | find_program(${name_upper} ${ARG_NAME})
32 |
33 | if(NOT ${name_upper})
34 | message(FATAL_ERROR "Could not find required program ${ARG_NAME}.")
35 | endif()
36 | endif()
37 |
38 | message(STATUS "Found program ${ARG_NAME}: ${${name_upper}}")
39 |
40 | mark_as_advanced(${name_upper})
41 | endfunction()
42 | endif()
43 |
--------------------------------------------------------------------------------
/cmake/reproducible_builds.cmake:
--------------------------------------------------------------------------------
1 | # this little snippet makes sure that no absolute paths end up in the binaries built by CMake
2 | # it will replace such paths with relative ones
3 | # see https://reproducible-builds.org/docs/build-path/ for more information
4 |
5 | cmake_minimum_required(VERSION 3.4)
6 |
7 | include(CheckCCompilerFlag)
8 |
9 | if(CMAKE_BUILD_TYPE STREQUAL Release)
10 | message(STATUS "Release build detected, enabling reproducible builds mode")
11 | get_filename_component(abs_source_path ${PROJECT_SOURCE_DIR} ABSOLUTE)
12 | file(RELATIVE_PATH rel_source_path ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR})
13 |
14 | set(map_fix ${abs_source_path}=${rel_source_path})
15 |
16 | # can only add flags when the compiler supports them
17 | # known working compilers: GCC >= 8
18 | foreach(type debug macro)
19 | set(flag_name -f${type}-prefix-map)
20 | set(flags ${flag_name}=${map_fix})
21 |
22 | check_c_compiler_flag(${flags} ${type}_prefix_map_flag_available)
23 |
24 | if(${type}_prefix_map_flag_available)
25 | set(extra_flags "${extra_flags} ${flags}")
26 | else()
27 | message(WARNING "${flag_name} not available, cannot enable full reproducible builds mode")
28 | endif()
29 | endforeach()
30 |
31 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${extra_flags}")
32 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${extra_flags}")
33 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${extra_flags}")
34 | endif()
35 |
--------------------------------------------------------------------------------
/travis/Dockerfile.build-cosmic-i386-cross:
--------------------------------------------------------------------------------
1 | # used to cache installed dependencies for bionic builds
2 | # this speeds up builds during development, as the dependencies are just installed _once_
3 |
4 | FROM ubuntu:cosmic
5 |
6 | RUN dpkg --add-architecture i386 && \
7 | apt-get update && \
8 | apt-get -y --no-install-recommends install \
9 | libfuse2:i386 \
10 | qtbase5-dev:i386 \
11 | qt5-qmake:i386 \
12 | qtbase5-dev-tools:i386 \
13 | libqt5core5a:i386 \
14 | libqt5gui5:i386 \
15 | libcurl4-openssl-dev:i386 \
16 | libssl-dev:i386 \
17 | libqt5widgets5:i386 \
18 | librsvg2-bin:i386 \
19 | libfuse-dev:i386 \
20 | libcurl4:i386 \
21 | libcurl4 \
22 | libbsd-dev:i386 \
23 | libglib2.0-dev:i386 \
24 | liblzma-dev:i386 \
25 | libgtest-dev \
26 | libcairo-dev:i386 \
27 | libgl1-mesa-dev:i386 \
28 | libglu1-mesa-dev:i386 \
29 | \
30 | rpm \
31 | gcc-multilib \
32 | g++-multilib \
33 | cmake \
34 | make \
35 | git \
36 | ca-certificates \
37 | automake \
38 | autoconf \
39 | libtool \
40 | patch \
41 | wget \
42 | vim-common \
43 | desktop-file-utils \
44 | pkg-config \
45 | qttools5-dev-tools:i386 \
46 | qt5-qmake-bin:i386 \
47 | libarchive-dev:i386 \
48 | libboost-filesystem-dev:i386 \
49 | zlib1g:i386
50 |
--------------------------------------------------------------------------------
/travis/Dockerfile.build-bionic-i386-cross:
--------------------------------------------------------------------------------
1 | # used to cache installed dependencies for bionic builds
2 | # this speeds up builds during development, as the dependencies are just installed _once_
3 |
4 | FROM i386/ubuntu:bionic
5 |
6 | RUN dpkg --add-architecture i386 && \
7 | apt-get update && \
8 | apt-get -y --no-install-recommends install \
9 | libfuse2:i386 \
10 | qtbase5-dev:i386 \
11 | qt5-qmake:i386 \
12 | qtbase5-dev-tools:i386 \
13 | libqt5core5a:i386 \
14 | libqt5gui5:i386 \
15 | libcurl4-openssl-dev:i386 \
16 | libssl-dev:i386 \
17 | libqt5widgets5:i386 \
18 | librsvg2-bin:i386 \
19 | libfuse-dev:i386 \
20 | libcurl4:i386 \
21 | libcurl4 \
22 | libbsd-dev:i386 \
23 | libglib2.0-dev:i386 \
24 | liblzma-dev:i386 \
25 | libgtest-dev \
26 | libcairo-dev:i386 \
27 | libgl1-mesa-dev:i386 \
28 | libglu1-mesa-dev:i386 \
29 | \
30 | rpm \
31 | gcc-multilib \
32 | g++-multilib \
33 | cmake \
34 | make \
35 | git \
36 | ca-certificates \
37 | automake \
38 | autoconf \
39 | libtool \
40 | patch \
41 | wget \
42 | vim-common \
43 | desktop-file-utils \
44 | pkg-config \
45 | qttools5-dev-tools:i386 \
46 | qt5-qmake-bin:i386 \
47 | libarchive-dev:i386 \
48 | libboost-filesystem-dev:i386 \
49 | zlib1g:i386
50 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 |
3 | notifications:
4 | email: false
5 |
6 | services:
7 | - docker
8 |
9 | matrix:
10 | include:
11 | - env: DIST=bionic ARCH=x86_64
12 | name: Native packages for Ubuntu bionic, Debian testing and newer, x86_64
13 | - env: DIST=bionic ARCH=i386
14 | name: Native packages for Ubuntu bionic, Debian testing and newer, i386
15 | - env: DIST=xenial ARCH=x86_64
16 | name: Native packages for Ubuntu xenial, Debian stable etc., x86_64
17 | - env: DIST=xenial ARCH=i386
18 | name: Native packages for Ubuntu xenial, Debian stable etc., i386
19 | - env: DIST=xenial ARCH=x86_64 BUILD_LITE=1
20 | name: AppImageLauncher Lite AppImage x86_64
21 | - env: DIST=xenial ARCH=i386 BUILD_LITE=1
22 | name: AppImageLauncher Lite AppImage i386
23 |
24 | script:
25 | - bash -ex travis/travis-docker.sh "$DIST"
26 |
27 | after_success:
28 | - wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
29 | - if [ "$TRAVIS_BRANCH" != "master" ] && [ "$TRAVIS_TAG" == "" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
30 | - |2
31 | if [[ "$BUILD_LITE" != "" ]]; then
32 | bash upload.sh appimagelauncher-lite-*.AppImage*
33 | elif [[ "$DIST" == "xenial" ]]; then
34 | bash upload.sh appimagelauncher*.{deb,rpm}* appimagelauncher*.tar*
35 | else
36 | bash upload.sh appimagelauncher*.deb*
37 | fi
38 |
39 | branches:
40 | except:
41 | - # Do not build tags that we create when we upload to GitHub Releases
42 | - /^(?i:continuous)/
43 |
--------------------------------------------------------------------------------
/travis/Dockerfile.build-xenial-i386-cross:
--------------------------------------------------------------------------------
1 | # used to cache installed dependencies for bionic builds
2 | # this speeds up builds during development, as the dependencies are just installed _once_
3 |
4 | FROM i386/ubuntu:xenial
5 |
6 | RUN dpkg --add-architecture i386 && \
7 | apt-get update && \
8 | apt-get -y --no-install-recommends install \
9 | libfuse2:i386 \
10 | qtbase5-dev:i386 \
11 | qt5-qmake:i386 \
12 | qtbase5-dev-tools \
13 | libqt5core5a:i386 \
14 | libqt5gui5:i386 \
15 | libcurl4-openssl-dev:i386 \
16 | libssl-dev:i386 \
17 | libqt5widgets5:i386 \
18 | librsvg2-bin:i386 \
19 | libfuse-dev:i386 \
20 | libcurl3:i386 \
21 | libcurl3 \
22 | libbsd-dev:i386 \
23 | libglib2.0-dev:i386 \
24 | liblzma-dev:i386 \
25 | libgtest-dev \
26 | libcairo-dev:i386 \
27 | libgl1-mesa-dev:i386 \
28 | libglu1-mesa-dev:i386 \
29 | \
30 | rpm \
31 | gcc-multilib \
32 | g++-multilib \
33 | cmake \
34 | make \
35 | git \
36 | ca-certificates \
37 | automake \
38 | autoconf \
39 | libtool \
40 | patch \
41 | wget \
42 | vim-common \
43 | desktop-file-utils \
44 | pkg-config \
45 | qttools5-dev-tools:i386 \
46 | libfontconfig1-dev:i386 \
47 | libfreetype6-dev:i386 \
48 | libarchive-dev:i386 \
49 | libboost-filesystem-dev:i386 \
50 | zlib1g:i386
51 |
--------------------------------------------------------------------------------
/resources/AppImageLauncher.1.in:
--------------------------------------------------------------------------------
1 | .\" Manpage for AppImageLauncher.
2 | .\" Contact theassassin@assassinate-you.net to correct errors or typos.
3 | .TH man 1 "28 February 2019" "@APPIMAGELAUNCHER_VERSION@" "AppImageLauncher man page"
4 | .SH NAME
5 | AppImageLauncher \- Desktop integration helper for AppImages, for use by Linux distributions.
6 | .SH SYNOPSIS
7 | AppImageLauncher [PATH]
8 | .SH DESCRIPTION
9 | Helper application for Linux distributions serving as a
10 | kind of "entry point" for running and integrating AppImages.
11 |
12 | AppImage provides a way for upstream developers to provide
13 | “native” binaries for Linux users just the same way they could
14 | do for other operating systems. It allows for packaging applications
15 | for any common Linux based operating system, e.g., Debian.
16 | AppImages come with all dependencies that cannot be assumed
17 | to be part of each target system in a recent enough version and
18 | will run on most Linux distributions without further modifications.
19 |
20 | AppImageLauncher makes your Linux desktop AppImage ready™.
21 | You can integrate AppImages with a single mouse click, and manage
22 | them from your application launcher. Install AppImageLauncher today
23 | for your distribution and enjoy using AppImages as easy as never before!
24 | .SH OPTIONS
25 | .IP --appimagelauncher-help
26 | Display this help and exit
27 | .IP --appimagelauncher-version
28 | Display version and exit
29 | .SH ARGUMENTS
30 | Path to AppImage (mandatory)
31 | .SH BUGS
32 | No known bugs.
33 | .SH AUTHOR
34 | TheAssassin
35 |
36 |
--------------------------------------------------------------------------------
/resources/mime/packages/appimage.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <_comment>AppImage application bundle (Type 1)
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | <_comment>AppImage application bundle (Type 2)
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/fusefs/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // system includes
4 | #include
5 |
6 | // base class
7 | class AppImageLauncherFSError : public std::runtime_error {
8 | public:
9 | explicit AppImageLauncherFSError(const std::string& msg = "") : runtime_error(msg) {}
10 | };
11 |
12 | class AlreadyRunningError : public AppImageLauncherFSError { using AppImageLauncherFSError::AppImageLauncherFSError; };
13 | class CouldNotOpenFileError : public AppImageLauncherFSError { using AppImageLauncherFSError::AppImageLauncherFSError; };
14 | class FileNotFoundError : public AppImageLauncherFSError { using AppImageLauncherFSError::AppImageLauncherFSError; };
15 | class InvalidPathError : public AppImageLauncherFSError { using AppImageLauncherFSError::AppImageLauncherFSError; };
16 | class CouldNotFindRegisteredAppImageError : public AppImageLauncherFSError { using AppImageLauncherFSError::AppImageLauncherFSError; };
17 |
18 | class AppImageAlreadyRegisteredError : public AppImageLauncherFSError {
19 | private:
20 | const int _id;
21 |
22 | public:
23 | explicit AppImageAlreadyRegisteredError(int id) : _id(id) {};
24 |
25 | public:
26 | int id() {
27 | return _id;
28 | }
29 | };
30 |
31 | class DuplicateRegisteredAppImageError : public AppImageLauncherFSError {
32 | private:
33 | const int _firstId;
34 | const int _secondId;
35 |
36 | public:
37 | DuplicateRegisteredAppImageError(int firstId, int secondId) : _firstId(firstId), _secondId(secondId) {};
38 |
39 | public:
40 | int firstId() {
41 | return _firstId;
42 | }
43 |
44 | int secondId() {
45 | return _secondId;
46 | }
47 | };
48 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # in version 3.6 IMPORTED_TARGET has been added to pkg_*_modules
2 | cmake_minimum_required(VERSION 3.6)
3 |
4 | set(CMAKE_CXX_STANDARD 11)
5 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
6 |
7 | # Find includes in corresponding build directories
8 | set(CMAKE_INCLUDE_CURRENT_DIR ON)
9 | # Instruct CMake to run moc automatically when needed
10 | set(CMAKE_AUTOMOC ON)
11 | # Create code from a list of Qt designer ui files
12 | set(CMAKE_AUTOUIC ON)
13 | # Compile resource files
14 | set(CMAKE_AUTORCC ON)
15 |
16 | find_package(Qt5 REQUIRED COMPONENTS Core Widgets DBus)
17 |
18 | find_package(PkgConfig REQUIRED)
19 | pkg_check_modules(glib REQUIRED glib-2.0>=2.40 IMPORTED_TARGET)
20 |
21 | find_package(INotify REQUIRED)
22 |
23 | # disable Qt debug messages except for debug builds
24 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
25 | message(STATUS "CMake build type is ${CMAKE_BUILD_TYPE}, hence disabling debug messages in AppImageLauncher")
26 | add_definitions(-DQT_NO_DEBUG_OUTPUT)
27 | add_definitions(-DQT_NO_INFO_OUTPUT)
28 | add_definitions(-DQT_NO_WARNING_OUTPUT)
29 | endif()
30 |
31 | # this shall propagate to all targets built in the subdirs
32 | if(ENABLE_UPDATE_HELPER)
33 | add_definitions(-DENABLE_UPDATE_HELPER)
34 | endif()
35 |
36 | add_compile_options(-Wall -Wpedantic)
37 |
38 | if(BUILD_LITE)
39 | add_definitions(-DBUILD_LITE)
40 | endif()
41 |
42 | # utility libraries
43 | add_subdirectory(fswatcher)
44 | add_subdirectory(i18n)
45 | add_subdirectory(trashbin)
46 | add_subdirectory(shared)
47 |
48 | # appimagelauncherd
49 | add_subdirectory(daemon)
50 |
51 | # main application and helper tools
52 | add_subdirectory(ui)
53 |
54 | # FUSE filesystem AppImageLauncherFS
55 | if(NOT BUILD_LITE)
56 | add_subdirectory(fusefs)
57 | endif()
58 |
59 | # CLI helper allowing other tools to utilize AppImageLauncher's code for e.g., integrating AppImages
60 | add_subdirectory(cli)
61 |
--------------------------------------------------------------------------------
/resources/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # install configs for resource files
2 |
3 | install(
4 | DIRECTORY
5 | ${CMAKE_CURRENT_SOURCE_DIR}/icons
6 | ${CMAKE_CURRENT_SOURCE_DIR}/mime
7 | DESTINATION ${CMAKE_INSTALL_DATADIR} COMPONENT APPIMAGELAUNCHER
8 | )
9 |
10 | install(
11 | FILES
12 | ${CMAKE_CURRENT_SOURCE_DIR}/appimagelauncher.desktop
13 | ${CMAKE_CURRENT_SOURCE_DIR}/appimagelaunchersettings.desktop
14 | DESTINATION ${CMAKE_INSTALL_DATADIR}/applications COMPONENT APPIMAGELAUNCHER
15 | )
16 |
17 | set(INSTALL_MAINTAINER_SCRIPTS OFF CACHE BOOL "")
18 |
19 | # install maintainer scripts that distro packagers might find useful
20 | if (INSTALL_MAINTAINER_SCRIPTS)
21 | message(STATUS "Installing maintainer scripts")
22 |
23 | set(install_maintainer_scripts_dir ${PROJECT_BINARY_DIR}/cmake/install-maintainer-scripts/)
24 |
25 | configure_file(
26 | ${PROJECT_SOURCE_DIR}/resources/install-scripts/post-install.in
27 | ${install_maintainer_scripts_dir}/post-install
28 | @ONLY
29 | )
30 | configure_file(
31 | ${PROJECT_SOURCE_DIR}/resources/install-scripts/post-uninstall.in
32 | ${install_maintainer_scripts_dir}/post-uninstall
33 | @ONLY
34 | )
35 |
36 | install(
37 | FILES ${install_maintainer_scripts_dir}/post-install ${install_maintainer_scripts_dir}/post-uninstall
38 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/appimagelauncher/maintainer-scripts
39 | )
40 | endif()
41 |
42 |
43 | # install man page
44 | set(INSTALL_MAN_PAGE ON CACHE BOOL "")
45 |
46 | if(INSTALL_MAN_PAGE)
47 | set(configured_man_page_path ${PROJECT_BINARY_DIR}/cmake/man/AppImageLauncher.1)
48 |
49 | configure_file(
50 | ${PROJECT_SOURCE_DIR}/resources/AppImageLauncher.1.in
51 | ${configured_man_page_path}
52 | )
53 |
54 | install(
55 | FILES ${configured_man_page_path}
56 | DESTINATION share/man/man1 COMPONENT APPIMAGELAUNCHER
57 | )
58 | endif()
59 |
--------------------------------------------------------------------------------
/cmake/toolchains/i386-linux-gnu.cmake:
--------------------------------------------------------------------------------
1 | # this toolchain file works for cross compiling on Ubuntu when the following prerequisites are given:
2 | # - all dependencies that would be needed for a normal build must be installed as i386 versions
3 | # - building XZ/liblzma doesn't work yet, so one has to install liblzma-dev:i386 and set -DUSE_SYSTEM_XZ=ON
4 | # - building GTest doesn't work yet, so one has to install libgtest-dev:i386 and set -DUSE_SYSTEM_GTEST=ON
5 | # - building libarchive doesn't work yet, so one has to install liblzma-dev:i386 and set -DUSE_SYSTEM_LIBARCHIVE=ON (TODO: link system libarchive statically like liblzma)
6 | # some of the packets interfere with their x86_64 version (e.g., libfuse-dev:i386, libglib2-dev:i386), so building on a
7 | # normal system will most likely not work, but on systems like Travis it should work fine
8 |
9 | set(CMAKE_SYSTEM_NAME Linux CACHE STRING "" FORCE)
10 | set(CMAKE_SYSTEM_PROCESSOR i386 CACHE STRING "" FORCE)
11 |
12 | set(CMAKE_C_FLAGS "-m32" CACHE STRING "" FORCE)
13 | set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "" FORCE)
14 |
15 | # CMAKE_SHARED_LINKER_FLAGS, CMAKE_STATIC_LINKER_FLAGS etc. must not be set, but CMAKE_EXE_LINKER_FLAGS is necessary
16 | set(CMAKE_EXE_LINKER_FLAGS "-m32" CACHE STRING "" FORCE)
17 |
18 | set(DEPENDENCIES_CFLAGS "-m32" CACHE STRING "" FORCE)
19 | set(DEPENDENCIES_CPPFLAGS "-m32" CACHE STRING "" FORCE)
20 | set(DEPENDENCIES_LDFLAGS "-m32" CACHE STRING "" FORCE)
21 |
22 | # host = target system
23 | # build = build system
24 | # both must be specified
25 | set(EXTRA_CONFIGURE_FLAGS "--host=i686-pc-linux-gnu" "--build=x86_64-pc-linux-gnu" CACHE STRING "" FORCE)
26 |
27 | # may help with some rare issues
28 | set(CMAKE_PREFIX_PATH /usr/lib/i386-linux-gnu CACHE STRING "" FORCE)
29 |
30 | # makes sure that at least on Ubuntu pkg-config will search for the :i386 packages
31 | set(ENV{PKG_CONFIG_PATH} /usr/lib/i386-linux-gnu/pkgconfig/ CACHE STRING "" FORCE)
32 |
33 | # make qtchooser find qt5
34 | set(ENV{QT_SELECT} qt5 CACHE STRING "" FORCE)
35 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 |
3 | project(AppImageLauncher)
4 |
5 | # versioning
6 | include(cmake/versioning.cmake)
7 |
8 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake/modules)
9 |
10 | include(cmake/scripts.cmake)
11 |
12 | include(cmake/reproducible_builds.cmake)
13 |
14 | # support for ccache
15 | # call CMake with -DUSE_CCACHE=ON to make use of it
16 | set(USE_CCACHE OFF CACHE BOOL "")
17 | if(USE_CCACHE)
18 | find_program(CCACHE ccache)
19 | if(CCACHE)
20 | message(STATUS "Using ccache")
21 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
22 | set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
23 | else()
24 | message(WARNING "USE_CCACHE set, but could not find ccache")
25 | endif()
26 | endif()
27 |
28 | # used by Debian packaging infrastructure
29 | include(GNUInstallDirs)
30 |
31 | # if there's a system libappimage package on the system, we can use that directly
32 | set(USE_SYSTEM_LIBAPPIMAGE OFF CACHE BOOL "")
33 |
34 | # if the system version should be used, import globally _before_ including third-party stuff and own executables/libs
35 | if(USE_SYSTEM_LIBAPPIMAGE)
36 | find_package(libappimage REQUIRED)
37 | endif()
38 |
39 | # optional; if AppImageUpdate dependency is not viable, the update helper can be disabled
40 | set(ENABLE_UPDATE_HELPER ON CACHE BOOL "")
41 |
42 | # install resources, bundle libraries privately, etc.
43 | # initializes important installation destination variables, therefore must be included before adding subdirectories
44 | include(cmake/install.cmake)
45 |
46 | add_subdirectory(lib)
47 | add_subdirectory(src)
48 |
49 | # contains install configs for resource files
50 | add_subdirectory(resources)
51 |
52 | # translation management
53 | add_subdirectory(i18n)
54 |
55 | # packaging
56 | include(cmake/cpack_general.cmake)
57 | include(cmake/cpack_source.cmake)
58 | include(cmake/cpack_deb.cmake)
59 | include(cmake/cpack_rpm.cmake)
60 |
61 | # must be the last instruction
62 | include(CPack)
63 |
--------------------------------------------------------------------------------
/src/fusefs/main.cpp:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | // library includes
16 | #include
17 |
18 | // local includes
19 | #include "error.h"
20 | #include "fs.h"
21 |
22 |
23 | int main(int argc, char *argv[]) {
24 | // sanity check
25 | // the FS must be run by regular users only
26 | // running as root is likely to create security holes
27 | if ((getuid() == 0) || (geteuid() == 0)) {
28 | fprintf(stderr, "Must not be run as root\n");
29 | return 1;
30 | }
31 |
32 | // See which version of fuse we're running
33 | std::cerr << "FUSE version: " << FUSE_MAJOR_VERSION << "." << FUSE_MINOR_VERSION << std::endl;
34 |
35 | // Perform some sanity checking on the command line: make sure
36 | // there are enough arguments, and that neither of the last two
37 | // start with a hyphen (this will break if you actually have a
38 | // rootpoint or mountpoint whose name starts with a hyphen, but so
39 | // will a zillion other programs)
40 | if ((argc != 1)) {
41 | std::cerr << "Usage: " << argv[0] << std::endl;
42 | return 1;
43 | }
44 |
45 | std::shared_ptr fs;
46 |
47 | // create filesystem instance
48 | for (int i = 0; i < 2; i++) {
49 | try {
50 | fs = AppImageLauncherFS::getInstance();
51 | } catch (const AlreadyRunningError&) {
52 | std::cerr << "Another instance is running already" << std::endl;
53 | return 1;
54 | }
55 | }
56 |
57 | if (fs == nullptr) {
58 | std::cerr << "Failed to create filesystem instance" << std::endl;
59 | return 1;
60 | }
61 |
62 | std::cerr << "mountpoint: " << fs->mountpoint() << std::endl;
63 |
64 | std::cerr << "Starting FUSE filesystem" << std::endl;
65 | int fuse_stat = fs->run();
66 | std::cerr << "Shutting down FUSE filesystem" << std::endl;
67 |
68 | return fuse_stat;
69 | }
70 |
--------------------------------------------------------------------------------
/src/cli/cli_main.cpp:
--------------------------------------------------------------------------------
1 | // system headers
2 | #include
3 |
4 | // library headers
5 | #include
6 | #include
7 |
8 | // local headers
9 | #include "CommandFactory.h"
10 | #include "exceptions.h"
11 | #include "logging.h"
12 |
13 | using namespace appimagelauncher::cli;
14 | using namespace appimagelauncher::cli::commands;
15 |
16 | int main(int argc, char** argv) {
17 | // we don't have support for UI (and don't want that), so let's tell shared to not display dialogs
18 | setenv("_FORCE_HEADLESS", "1", 1);
19 |
20 | QCoreApplication app(argc, argv);
21 |
22 | std::ostringstream version;
23 | version << "version " << APPIMAGELAUNCHER_VERSION << " "
24 | << "(git commit " << APPIMAGELAUNCHER_GIT_COMMIT << "), built on "
25 | << APPIMAGELAUNCHER_BUILD_DATE;
26 | QCoreApplication::setApplicationVersion(QString::fromStdString(version.str()));
27 |
28 | QCommandLineParser parser;
29 |
30 | parser.addPositionalArgument("", "Command to run (see help for more information");
31 | parser.addPositionalArgument("[...]", "command-specific additional arguments");
32 | parser.addHelpOption();
33 | parser.addVersionOption();
34 |
35 | parser.process(app);
36 |
37 | auto posArgs = parser.positionalArguments();
38 |
39 | if (posArgs.isEmpty()) {
40 | qerr() << parser.helpText().toStdString().c_str() << endl;
41 |
42 | qerr() << "Available commands:" << endl;
43 | qerr() << " integrate Integrate AppImages passed as commandline arguments" << endl;
44 |
45 | return 2;
46 | }
47 |
48 | auto commandName = posArgs.front();
49 | posArgs.pop_front();
50 |
51 | try {
52 | auto command = CommandFactory::getCommandByName(commandName);
53 | command->exec(posArgs);
54 | } catch (const CommandNotFoundError& e) {
55 | qerr() << e.what() << endl;
56 | return 1;
57 | } catch (const InvalidArgumentsError& e) {
58 | qerr() << "Invalid arguments: " << e.what() << endl;
59 | return 3;
60 | } catch (const UsageError& e) {
61 | qerr() << "Usage error: " << e.what() << endl;
62 | return 3;
63 | }
64 |
65 | return 0;
66 | }
67 |
--------------------------------------------------------------------------------
/src/i18n/translationmanager.cpp:
--------------------------------------------------------------------------------
1 | // library headers
2 | #include
3 | #include
4 | #include
5 |
6 | // local headers
7 | #include "translationmanager.h"
8 |
9 | TranslationManager::TranslationManager(QCoreApplication& app) : app(app) {
10 | // set up translations
11 | auto qtTranslator = new QTranslator();
12 | qtTranslator->load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
13 | app.installTranslator(qtTranslator);
14 |
15 | const auto systemLocale = QLocale::system().name();
16 |
17 | // we're using primarily short names for translations, so we should load these translations as well
18 | const auto shortSystemLocale = systemLocale.split('_')[0];
19 |
20 | const auto translationDir = getTranslationDir();
21 |
22 | auto myappTranslator = new QTranslator();
23 | myappTranslator->load(translationDir + "/ui." + systemLocale + ".qm");
24 | myappTranslator->load(translationDir + "/ui." + shortSystemLocale + ".qm");
25 | app.installTranslator(myappTranslator);
26 |
27 | // store translators in list so they won't be deleted
28 | installedTranslators.push_back(qtTranslator);
29 | installedTranslators.push_back(myappTranslator);
30 | }
31 |
32 | TranslationManager::~TranslationManager() {
33 | for (auto& translator : installedTranslators) {
34 | delete translator;
35 | translator = nullptr;
36 | }
37 | }
38 |
39 | QString TranslationManager::getTranslationDir() {
40 | // first we need to find the translation directory
41 | // if this is run from the build tree, we try a path that can only work within the build directory
42 | // then, we try the expected install location relative to the main binary
43 | const auto binaryDirPath = QApplication::applicationDirPath();
44 |
45 | // previously the path to the repo root dir was embedded to allow for finding the compiled translations
46 | // this lead to irreproducible builds
47 | // therefore the files are now generated within the build dir, and we guess the path based on the binary location
48 | auto translationDir = binaryDirPath + "/../../i18n/generated/l10n";
49 |
50 | if (!QDir(translationDir).exists()) {
51 | translationDir = binaryDirPath + "/../share/appimagelauncher/l10n";
52 | }
53 |
54 | return translationDir;
55 | }
56 |
--------------------------------------------------------------------------------
/src/ui/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if(NOT BUILD_LITE)
2 | # main AppImageLauncher application
3 | add_executable(AppImageLauncher main.cpp resources.qrc first-run.cpp first-run.h first-run.ui)
4 | target_link_libraries(AppImageLauncher shared PkgConfig::glib libappimage shared)
5 |
6 | # set binary runtime rpath to make sure the libappimage.so built and installed by this project is going to be used
7 | # by the installed binaries (be it the .deb, the AppImage, or whatever)
8 | # in order to make the whole install tree relocatable, a relative path is used
9 | set_target_properties(AppImageLauncher PROPERTIES INSTALL_RPATH ${_rpath})
10 |
11 | install(
12 | TARGETS
13 | AppImageLauncher
14 | RUNTIME DESTINATION ${_bindir} COMPONENT APPIMAGELAUNCHER
15 | LIBRARY DESTINATION ${_libdir} COMPONENT APPIMAGELAUNCHER
16 | )
17 | endif()
18 |
19 | # AppImageLauncherSettings application
20 | add_executable(AppImageLauncherSettings settings_main.cpp settings_dialog.ui settings_dialog.cpp)
21 | target_link_libraries(AppImageLauncherSettings shared)
22 |
23 | # set binary runtime rpath to make sure the libappimage.so built and installed by this project is going to be used
24 | # by the installed binaries (be it the .deb, the AppImage, or whatever)
25 | # in order to make the whole install tree relocatable, a relative path is used
26 | set_target_properties(AppImageLauncherSettings PROPERTIES INSTALL_RPATH ${_rpath})
27 |
28 | install(
29 | TARGETS
30 | AppImageLauncherSettings
31 | RUNTIME DESTINATION ${_bindir} COMPONENT APPIMAGELAUNCHER
32 | LIBRARY DESTINATION ${_libdir} COMPONENT APPIMAGELAUNCHER
33 | )
34 |
35 | # AppImage removal helper
36 | add_executable(remove remove_main.cpp remove.ui resources.qrc)
37 | target_link_libraries(remove shared translationmanager libappimage)
38 | # see AppImageLauncher for a description
39 | set_target_properties(remove PROPERTIES INSTALL_RPATH "\$ORIGIN")
40 |
41 | install(
42 | TARGETS remove
43 | RUNTIME DESTINATION ${_private_libdir} COMPONENT APPIMAGELAUNCHER
44 | )
45 |
46 |
47 | # AppImage update helper
48 | if(ENABLE_UPDATE_HELPER)
49 | add_executable(update update_main.cpp resources.qrc)
50 | target_link_libraries(update shared translationmanager libappimage libappimageupdate-qt)
51 | # see AppImageLauncher for a description
52 | set_target_properties(update PROPERTIES INSTALL_RPATH "\$ORIGIN")
53 |
54 | install(
55 | TARGETS update
56 | RUNTIME DESTINATION ${_private_libdir} COMPONENT APPIMAGELAUNCHER
57 | )
58 | endif()
59 |
--------------------------------------------------------------------------------
/travis/travis-build.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | set -x
4 | set -e
5 |
6 | # use RAM disk if possible
7 | if [ "$CI" == "" ] && [ -d /dev/shm ]; then
8 | TEMP_BASE=/dev/shm
9 | else
10 | TEMP_BASE=/tmp
11 | fi
12 |
13 | BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" AppImageLauncher-build-XXXXXX)
14 |
15 | cleanup () {
16 | if [ -d "$BUILD_DIR" ]; then
17 | rm -rf "$BUILD_DIR"
18 | fi
19 | }
20 |
21 | trap cleanup EXIT
22 |
23 | # store repo root as variable
24 | REPO_ROOT=$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)
25 | OLD_CWD=$(readlink -f .)
26 |
27 | pushd "$BUILD_DIR"
28 |
29 | # install more recent CMake version which fixes some linking issue in CMake < 3.10
30 | # Fixes https://github.com/TheAssassin/AppImageLauncher/issues/106
31 | # Upstream bug: https://gitlab.kitware.com/cmake/cmake/issues/17389
32 | wget https://cmake.org/files/v3.13/cmake-3.13.2-Linux-x86_64.tar.gz -qO- | tar xz --strip-components=1
33 | export PATH=$(readlink -f bin/):"$PATH"
34 | which cmake
35 | cmake --version
36 |
37 | if [ "$DEBIAN_DIST" != "" ]; then
38 | EXTRA_CMAKE_FLAGS=-DCPACK_DEBIAN_COMPATIBILITY_LEVEL="$DEBIAN_DIST"
39 | else
40 | echo "--- WARNING --- DEBIAN_DIST has not been set"
41 | fi
42 |
43 | if [ "$ARCH" == "i386" ]; then
44 | EXTRA_CMAKE_FLAGS="$EXTRA_CMAKE_FLAGS -DCMAKE_TOOLCHAIN_FILE=$REPO_ROOT/cmake/toolchains/i386-linux-gnu.cmake -DUSE_SYSTEM_XZ=ON -DUSE_SYSTEM_LIBARCHIVE=ON"
45 | if [ "$DEBIAN_DIST" != "bionic" ] && [ "$DEBIAN_DIST" != "cosmic" ]; then
46 | export QT_SELECT=qt5-i386-linux-gnu
47 | else
48 | export QT_SELECT=qt5
49 | fi
50 | fi
51 |
52 | cmake "$REPO_ROOT" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo $EXTRA_CMAKE_FLAGS -DTRAVIS_BUILD=ON -DBUILD_TESTING=OFF
53 |
54 | # now, compile
55 | make -j $(nproc)
56 |
57 | # re-run cmake to find built shared objects with the globs, and update the CPack files
58 | cmake .
59 |
60 | # build Debian package
61 | cpack -V -G DEB
62 |
63 | # skip RPM and source tarball build on bionic
64 | if [ "$DEBIAN_DIST" == "xenial" ]; then
65 | # build RPM package
66 | cpack -V -G RPM
67 |
68 | # build source tarball
69 | # generates a lot of output, therefore not run in verbose mode
70 | cpack --config CPackSourceConfig.cmake
71 |
72 | # generate log for debugging
73 | # CPack is very verbose, therefore we generate a file and upload it
74 | cpack --config CPackSourceConfig.cmake -V
75 | fi
76 |
77 | # move AppImages to old cwd
78 | if [ "$DEBIAN_DIST" == "xenial" ]; then
79 | mv appimagelauncher*.{deb,rpm}* appimagelauncher*.tar* "$OLD_CWD"/
80 | else
81 | mv appimagelauncher*.deb* "$OLD_CWD"/
82 | fi
83 |
84 | popd
85 |
--------------------------------------------------------------------------------
/i18n/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # lupdate must be installed and available
2 | check_program(NAME lupdate)
3 | check_program(NAME lrelease)
4 |
5 | # create target calling custom commands
6 | add_custom_target(i18n)
7 |
8 | # create/update AppImageLauncher strings
9 | function(ail_generate_translations)
10 | if(ARGC LESS 2)
11 | message(ERROR "ail_generate_translations called with wrong amount of arguments")
12 | endif()
13 |
14 | add_custom_command(
15 | TARGET i18n POST_BUILD
16 | COMMAND ${LUPDATE} "${ARGV0}" -ts "${ARGV1}" -locations relative
17 | MAIN_DEPENDENCY "${ARGV0}"
18 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
19 |
20 | )
21 | endfunction()
22 |
23 | ail_generate_translations(../src/ ui.en.ts)
24 |
25 | file(GLOB TS_FILES *.ts)
26 |
27 | foreach(TS_FILE IN LISTS TS_FILES)
28 | get_filename_component(TS_FILENAME ${TS_FILE} NAME)
29 | ail_generate_translations(../src/ ${TS_FILENAME})
30 | endforeach()
31 |
32 | add_custom_command(
33 | TARGET i18n POST_BUILD
34 | COMMAND ./auto-translate.py ui.en.ts
35 | MAIN_DEPENDENCY "${ARGV0}"
36 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
37 | )
38 |
39 |
40 | add_custom_target(l10n ALL)
41 |
42 | # generate Qt qm files from translation source files
43 | function(ail_generate_qm)
44 | if(ARGC LESS 2)
45 | message(ERROR "ail_generate_translations called with wrong amount of arguments")
46 | endif()
47 |
48 | add_custom_command(
49 | TARGET l10n POST_BUILD
50 | COMMAND ${LRELEASE} "${ARGV0}" -qm "${ARGV1}"
51 | MAIN_DEPENDENCY "${ARGV0}"
52 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
53 |
54 | )
55 | endfunction()
56 |
57 | file(GLOB TS_FILES *.ts)
58 |
59 | set(target_dir ${CMAKE_CURRENT_BINARY_DIR}/generated/l10n)
60 |
61 | foreach(TS_FILE IN LISTS TS_FILES)
62 | get_filename_component(TS_FILENAME ${TS_FILE} NAME)
63 | string(REPLACE .ts .qm QM_FILENAME ${TS_FILENAME})
64 | ail_generate_qm(${TS_FILENAME} ${target_dir}/${QM_FILENAME})
65 | endforeach()
66 |
67 | # deploy JSON files
68 | file(GLOB JSON_FILES *.json)
69 |
70 | foreach(JSON_FILE IN LISTS JSON_FILES)
71 | get_filename_component(JSON_FILENAME ${JSON_FILE} NAME)
72 | add_custom_command(
73 | TARGET l10n POST_BUILD
74 | COMMAND ${CMAKE_COMMAND} -E copy ${JSON_FILENAME} ${target_dir}/${JSON_FILENAME}
75 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
76 | MAIN_DEPENDENCY ${JSON_FILE}
77 | )
78 | endforeach()
79 |
80 |
81 | # empty directories aren't tracked by Git
82 | # therefore the directory needs to be created by CMake
83 | file(MAKE_DIRECTORY ${target_dir})
84 |
85 | install(
86 | DIRECTORY ${target_dir}
87 | DESTINATION ${CMAKE_INSTALL_DATADIR}/appimagelauncher COMPONENT APPIMAGELAUNCHER
88 | )
89 |
--------------------------------------------------------------------------------
/cmake/cpack_rpm.cmake:
--------------------------------------------------------------------------------
1 | # required for RPM-DEFAULT to work as intended
2 | cmake_minimum_required(VERSION 3.6)
3 |
4 | # allow building RPM packages on non-RPM systems
5 | if(DEFINED ENV{ARCH})
6 | set(CPACK_RPM_PACKAGE_ARCHITECTURE $ENV{ARCH})
7 | if(CPACK_RPM_PACKAGE_ARCHITECTURE MATCHES "i686")
8 | set(CPACK_RPM_PACKAGE_ARCHITECTURE "i386")
9 | elseif(CPACK_RPM_PACKAGE_ARCHITECTURE MATCHES "amd64")
10 | set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64")
11 | endif()
12 | endif()
13 |
14 | # override default package naming
15 | set(CPACK_RPM_FILE_NAME RPM-DEFAULT)
16 |
17 | # make sure to package components separately
18 | #set(CPACK_DEB_PACKAGE_COMPONENT ON)
19 | set(CPACK_RPM_COMPONENT_INSTALL ON)
20 |
21 | # RPM packaging global options
22 | set(CPACK_RPM_COMPRESSION_TYPE xz)
23 |
24 | # use git hash as package release
25 | set(CPACK_RPM_PACKAGE_RELEASE "git${APPIMAGELAUNCHER_GIT_COMMIT_DATE_SHORT}.${APPIMAGELAUNCHER_GIT_COMMIT}")
26 |
27 | # append build ID, similar to AppImage naming
28 | if(DEFINED ENV{TRAVIS_BUILD_NUMBER})
29 | set(CPACK_RPM_PACKAGE_RELEASE "travis$ENV{TRAVIS_BUILD_NUMBER}~${CPACK_RPM_PACKAGE_RELEASE}")
30 | else()
31 | set(CPACK_RPM_PACKAGE_RELEASE "local~${CPACK_RPM_PACKAGE_RELEASE}")
32 | endif()
33 |
34 | # bash is required to run install hooks
35 | set(CPACK_RPM_APPIMAGELAUNCHER_REQUIRES_PRE "bash")
36 |
37 | # package name
38 | set(CPACK_RPM_APPIMAGELAUNCHER_PACKAGE_NAME "appimagelauncher")
39 |
40 | # TODO: packagers watch out: you should set this to depend on a libappimage package, and avoid installing the library
41 | # to a custom location in install.cmake
42 | set(CPACK_RPM_APPIMAGELAUNCHER_PACKAGE_DREQUIRES "pkgconfig(Qt5Widgets) (>= 5.2.1), pkgconfig(Qt5Gui) (>= 5.2.1), pkgconfig(Qt5Core) (>= 5.2.1), libcurl4")
43 | # deactivate automatic generation of dependency list
44 | # it wants to add libappimage.so to the list of dependencies, which is actually shipped by the package
45 | set(CPACK_RPM_PACKAGE_AUTOREQ OFF)
46 |
47 | # avoid conflicts with the filesystem package
48 | set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
49 | /usr/share/applications
50 | /usr/lib/binfmt.d
51 | /usr/lib/systemd
52 | /usr/lib/systemd/user
53 | /usr/share/man
54 | /usr/share/man/man1
55 | )
56 |
57 | # add postinst and prerm hooks to RPM package
58 | configure_file(
59 | ${PROJECT_SOURCE_DIR}/resources/install-scripts/post-install.in
60 | ${PROJECT_BINARY_DIR}/cmake/rpm/post-install
61 | @ONLY
62 | )
63 | configure_file(
64 | ${PROJECT_SOURCE_DIR}/resources/install-scripts/post-uninstall.in
65 | ${PROJECT_BINARY_DIR}/cmake/rpm/post-uninstall
66 | @ONLY
67 | )
68 |
69 | set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${PROJECT_BINARY_DIR}/cmake/rpm/post-install")
70 | set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${PROJECT_BINARY_DIR}/cmake/rpm/post-uninstall")
71 |
--------------------------------------------------------------------------------
/travis/build-lite.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | if [ "$ARCH" == "" ]; then
4 | echo "Error: you must set \$ARCH"
5 | exit 2
6 | fi
7 |
8 | set -x
9 | set -e
10 |
11 | # use RAM disk if possible
12 | if [ "$CI" == "" ] && [ -d /dev/shm ]; then
13 | TEMP_BASE=/dev/shm
14 | else
15 | TEMP_BASE=/tmp
16 | fi
17 |
18 | BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" AppImageLauncher-build-XXXXXX)
19 |
20 | cleanup () {
21 | if [ -d "$BUILD_DIR" ]; then
22 | rm -rf "$BUILD_DIR"
23 | fi
24 | }
25 |
26 | trap cleanup EXIT
27 |
28 | # store repo root as variable
29 | REPO_ROOT=$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)
30 | OLD_CWD=$(readlink -f .)
31 |
32 | pushd "$BUILD_DIR"
33 |
34 | # install more recent CMake version which fixes some linking issue in CMake < 3.10
35 | # Fixes https://github.com/TheAssassin/AppImageLauncher/issues/106
36 | # Upstream bug: https://gitlab.kitware.com/cmake/cmake/issues/17389
37 | wget https://cmake.org/files/v3.13/cmake-3.13.2-Linux-x86_64.tar.gz -qO- | tar xz --strip-components=1
38 | export PATH=$(readlink -f bin/):"$PATH"
39 | which cmake
40 | cmake --version
41 |
42 | EXTRA_CMAKE_FLAGS=
43 |
44 | if [ "$ARCH" == "i386" ]; then
45 | EXTRA_CMAKE_FLAGS="$EXTRA_CMAKE_FLAGS -DCMAKE_TOOLCHAIN_FILE=$REPO_ROOT/cmake/toolchains/i386-linux-gnu.cmake -DUSE_SYSTEM_XZ=ON -DUSE_SYSTEM_LIBARCHIVE=ON"
46 | # TODO check if this can be removed
47 | if [ "$DEBIAN_DIST" != "bionic" ] && [ "$DEBIAN_DIST" != "cosmic" ]; then
48 | export QT_SELECT=qt5-i386-linux-gnu
49 | else
50 | export QT_SELECT=qt5
51 | fi
52 | fi
53 |
54 | cmake "$REPO_ROOT" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo $EXTRA_CMAKE_FLAGS -DTRAVIS_BUILD=ON -DBUILD_TESTING=OFF -DBUILD_LITE=ON
55 |
56 | # compile dependencies
57 | make -j $(nproc) libappimage libappimageupdate libappimageupdate-qt
58 |
59 | # re-run cmake to update paths to dependencies
60 | cmake .
61 |
62 | # build rest
63 | make -j $(nproc)
64 |
65 | # prepare AppDir
66 | make install DESTDIR=AppDir
67 |
68 | # build AppImage
69 | wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-"$ARCH".AppImage
70 | wget https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-"$ARCH".AppImage
71 | wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-"$ARCH".AppImage
72 | chmod -v +x linuxdeploy*-"$ARCH".AppImage
73 |
74 | export VERSION=$(src/cli/ail-cli --version | awk '{print $3}')
75 | export OUTPUT=appimagelauncher-lite-"$VERSION"-"$ARCH".AppImage
76 | export APPIMAGE_EXTRACT_AND_RUN=1
77 |
78 | ./linuxdeploy-"$ARCH".AppImage --plugin qt --appdir $(readlink -f AppDir) --custom-apprun "$REPO_ROOT"/resources/appimagelauncher-lite-AppRun.sh --output appimage \
79 | -d "$REPO_ROOT"/resources/appimagelauncher-lite.desktop \
80 | -e $(find AppDir/usr/lib/{,*/}appimagelauncher/remove | head -n1) \
81 | -e $(find AppDir/usr/lib/{,*/}appimagelauncher/update | head -n1)
82 |
83 | mv "$OUTPUT" "$OLD_CWD"
84 |
--------------------------------------------------------------------------------
/src/trashbin/trashbin.cpp:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 | #include
4 |
5 | // library includes
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | // local includes
12 | #include "trashbin.h"
13 | #include "shared.h"
14 |
15 | class TrashBin::PrivateData {
16 | public:
17 | const QDir dir;
18 |
19 | public:
20 | PrivateData() : dir(integratedAppImagesDestination().path() + "/.trash") {
21 | // make sure trash directory exists
22 | QDir(integratedAppImagesDestination().path()).mkdir(".trash");
23 | }
24 |
25 | bool canBeCleanedUp(const QString& path) {
26 | return true;
27 | }
28 | };
29 |
30 | TrashBin::TrashBin() {
31 | d = new PrivateData();
32 | }
33 |
34 | QString TrashBin::path() {
35 | return d->dir.path();
36 | }
37 |
38 | bool TrashBin::disposeAppImage(const QString& pathToAppImage) {
39 | if (!QFile(pathToAppImage).exists()) {
40 | std::cerr << "No such file or directory: " << pathToAppImage.toStdString() << std::endl;
41 | return false;
42 | }
43 |
44 | // moving AppImages into the trash bin might fail if there's a file with the same filename
45 | // removing multiple files with the same filenames is a valid use case, though
46 | // therefore, a timestamp shall be prepended to the filename
47 | // it is very unlike that some user will remove more than a AppImage per second, but if that should be the case,
48 | // we could eventually increase the precision of the timestamp
49 | // for now, this is not necessary
50 | auto timestamp = QDateTime::currentDateTime().toString(Qt::ISODate);
51 | auto newPath = d->dir.path() + QString("/") + timestamp + "_" + QFileInfo(pathToAppImage).fileName();
52 |
53 | if (!QFile(pathToAppImage).rename(newPath))
54 | return false;
55 |
56 | if (!makeNonExecutable(newPath))
57 | return false;
58 |
59 | return true;
60 | }
61 |
62 | bool TrashBin::cleanUp() {
63 | for (QDirIterator iterator(d->dir, QDirIterator::FollowSymlinks); iterator.hasNext();) {
64 | auto currentPath = iterator.next();
65 |
66 | if (!QFileInfo(currentPath).isFile())
67 | continue;
68 |
69 | if (appimage_get_type(currentPath.toStdString().c_str(), false) <= 0)
70 | continue;
71 |
72 | if (!d->canBeCleanedUp(currentPath)) {
73 | std::cerr << "Cannot clean up AppImage yet: " << currentPath.toStdString() << std::endl;
74 | continue;
75 | }
76 |
77 | std::cerr << "Removing AppImage: " << currentPath.toStdString() << std::endl;
78 |
79 | // silently ignore if files can not be removed
80 | // they shall be removed on subsequent runs
81 | // if this won't happen and the trash directory will only get bigger at some point, we might need to
82 | // reconsider this decision
83 | if (!QFile(currentPath).remove())
84 | continue;
85 | }
86 |
87 | return true;
88 | }
89 |
--------------------------------------------------------------------------------
/cmake/versioning.cmake:
--------------------------------------------------------------------------------
1 | set(V_MAJOR 1)
2 | set(V_MINOR 3)
3 | set(V_PATCH 1)
4 | set(V_SUFFIX "")
5 |
6 | set(APPIMAGELAUNCHER_VERSION ${V_MAJOR}.${V_MINOR}.${V_PATCH}${V_SUFFIX})
7 |
8 | # check whether git is available
9 | find_program(GIT git)
10 | set(GIT_COMMIT_CACHE_FILE "${PROJECT_SOURCE_DIR}/cmake/GIT_COMMIT")
11 |
12 | if(NOT GIT STREQUAL "GIT-NOTFOUND")
13 | # read Git revision ID
14 | # WARNING: this value will be stored in the CMake cache
15 | # to update it, you will have to reset the CMake cache
16 | # (doesn't matter for CI builds like Travis for instance, where there's no permanent CMake cache)
17 | execute_process(
18 | COMMAND git rev-parse --short HEAD
19 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
20 | OUTPUT_VARIABLE APPIMAGELAUNCHER_GIT_COMMIT
21 | OUTPUT_STRIP_TRAILING_WHITESPACE
22 | ERROR_QUIET
23 | RESULT_VARIABLE GIT_RESULT
24 | )
25 |
26 | if(GIT_RESULT EQUAL 0)
27 | message(STATUS "Storing git commit ID in cache file")
28 | file(WRITE "${GIT_COMMIT_CACHE_FILE}" "${APPIMAGELAUNCHER_GIT_COMMIT}")
29 | endif()
30 | endif()
31 |
32 | if(NOT GIT_RESULT EQUAL 0)
33 | # git call failed or git hasn't been found, might happen when calling CMake in an extracted source tarball
34 | # therefore we try to find the git commit cache file
35 | # if it doesn't exist, refuse to configure
36 |
37 | message(WARNING "Failed to gather commit ID via git command, trying to read cache file")
38 | if(EXISTS "${GIT_COMMIT_CACHE_FILE}")
39 | file(READ "${GIT_COMMIT_CACHE_FILE}" APPIMAGELAUNCHER_CACHED_GIT_COMMIT)
40 | mark_as_advanced(FORCE APPIMAGELAUNCHER_CACHED_GIT_COMMIT)
41 | string(REPLACE "\n" "" APPIMAGELAUNCHER_GIT_COMMIT "${APPIMAGELAUNCHER_CACHED_GIT_COMMIT}")
42 | else()
43 | message(FATAL_ERROR "Could not find git commit cache file, git commit ID not available for versioning")
44 | endif()
45 | endif()
46 |
47 | if("${APPIMAGELAUNCHER_GIT_COMMIT}" STREQUAL "")
48 | message(FATAL_ERROR "Invalid git commit ID: ${APPIMAGELAUNCHER_GIT_COMMIT}")
49 | endif()
50 |
51 | message(STATUS "Git commit: ${APPIMAGELAUNCHER_GIT_COMMIT}")
52 | mark_as_advanced(FORCE APPIMAGELAUNCHER_GIT_COMMIT)
53 |
54 | # add build number based on Travis build number if possible
55 | if("$ENV{TRAVIS_BUILD_NUMBER}" STREQUAL "")
56 | set(APPIMAGELAUNCHER_BUILD_NUMBER "")
57 | else()
58 | set(APPIMAGELAUNCHER_BUILD_NUMBER "$ENV{TRAVIS_BUILD_NUMBER}")
59 | endif()
60 |
61 | # get current date
62 | execute_process(
63 | COMMAND env LC_ALL=C date -u "+%Y-%m-%d %H:%M:%S %Z"
64 | OUTPUT_VARIABLE APPIMAGELAUNCHER_BUILD_DATE
65 | OUTPUT_STRIP_TRAILING_WHITESPACE
66 | )
67 |
68 | # get current date, short form
69 | execute_process(
70 | COMMAND env LC_ALL=C git show -s --format=%ci ${APPIMAGELAUNCHER_GIT_COMMIT}
71 | OUTPUT_VARIABLE APPIMAGELAUNCHER_GIT_COMMIT_DATE
72 | OUTPUT_STRIP_TRAILING_WHITESPACE
73 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
74 | )
75 | execute_process(
76 | COMMAND env LC_ALL=C date -u "+%Y%m%d" -d ${APPIMAGELAUNCHER_GIT_COMMIT_DATE}
77 | OUTPUT_VARIABLE APPIMAGELAUNCHER_GIT_COMMIT_DATE_SHORT
78 | OUTPUT_STRIP_TRAILING_WHITESPACE
79 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
80 | )
81 |
82 | add_definitions(-DAPPIMAGELAUNCHER_VERSION="${APPIMAGELAUNCHER_VERSION}")
83 | add_definitions(-DAPPIMAGELAUNCHER_GIT_COMMIT="${APPIMAGELAUNCHER_GIT_COMMIT}")
84 | add_definitions(-DAPPIMAGELAUNCHER_BUILD_NUMBER="${APPIMAGELAUNCHER_BUILD_NUMBER}")
85 | add_definitions(-DAPPIMAGELAUNCHER_BUILD_DATE="${APPIMAGELAUNCHER_BUILD_DATE}")
86 |
--------------------------------------------------------------------------------
/src/ui/settings_dialog.cpp:
--------------------------------------------------------------------------------
1 | // libraries
2 | #include
3 |
4 | // local
5 | #include "settings_dialog.h"
6 | #include "ui_settings_dialog.h"
7 | #include "shared.h"
8 |
9 | SettingsDialog::SettingsDialog(QWidget* parent) :
10 | QDialog(parent),
11 | ui(new Ui::SettingsDialog) {
12 | ui->setupUi(this);
13 |
14 | loadSettings();
15 |
16 | // cosmetic changes in lite mode
17 | #ifndef BUILD_LITE
18 | ui->checkBoxEnableDaemon->setChecked(true);
19 | ui->checkBoxEnableDaemon->setEnabled(false);
20 |
21 | ui->checkBoxAskMove->setChecked(false);
22 | ui->checkBoxAskMove->setEnabled(false);
23 | #endif
24 |
25 | connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::onDialogAccepted);
26 | connect(ui->toolButtonChooseAppsDir, &QToolButton::released, this, &SettingsDialog::onChooseAppsDirClicked);
27 |
28 | QStringList availableFeatures;
29 |
30 | #ifdef ENABLE_UPDATE_HELPER
31 | availableFeatures << "✔ " + tr("updater available for AppImages supporting AppImageUpdate");
32 | #else
33 | availableFeatures << "🞬 " + tr("updater unavailable");
34 | #endif
35 |
36 | #ifndef BUILD_LITE
37 | availableFeatures << "
"
38 | << tr("Note: this is an AppImageLauncher Lite build, only supports a limited set of features
"
39 | "Please install the full version via the provided native packages to enjoy the full AppImageLauncher experience");
40 | #endif
41 |
42 | ui->featuresLabel->setText(availableFeatures.join('\n'));
43 | }
44 |
45 | SettingsDialog::~SettingsDialog() {
46 | delete ui;
47 | }
48 |
49 | void SettingsDialog::loadSettings() {
50 | settingsFile = getConfig();
51 |
52 | if (settingsFile) {
53 | ui->checkBoxEnableDaemon->setChecked(settingsFile->value("AppImageLauncher/enable_daemon", false).toBool());
54 | ui->checkBoxAskMove->setChecked(settingsFile->value("AppImageLauncher/ask_to_move", false).toBool());
55 | ui->lineEditApplicationsDir->setText(settingsFile->value("AppImageLauncher/destination").toString());
56 | }
57 | }
58 |
59 | void SettingsDialog::onDialogAccepted() {
60 | saveSettings();
61 | toggleDaemon();
62 | }
63 |
64 | void SettingsDialog::saveSettings() {
65 | createConfigFile(ui->checkBoxAskMove->isChecked(),
66 | ui->lineEditApplicationsDir->text(),
67 | ui->checkBoxEnableDaemon->isChecked());
68 |
69 | settingsFile = getConfig();
70 | }
71 |
72 | void SettingsDialog::toggleDaemon() {
73 | // assumes defaults if config doesn't exist or lacks the related key(s)
74 | if (settingsFile) {
75 | if (settingsFile->value("AppImageLauncher/enable_daemon", false).toBool()) {
76 | system("systemctl --user enable appimagelauncherd.service");
77 | system("systemctl --user start appimagelauncherd.service");
78 | } else {
79 | system("systemctl --user disable appimagelauncherd.service");
80 | system("systemctl --user stop appimagelauncherd.service");
81 | }
82 | }
83 | }
84 |
85 | void SettingsDialog::onChooseAppsDirClicked() {
86 | QFileDialog fileDialog(this);
87 | fileDialog.setFileMode(QFileDialog::DirectoryOnly);
88 | fileDialog.setWindowTitle(tr("Select Applications directory"));
89 | fileDialog.setDirectory(QDir::home());
90 | if (fileDialog.exec()) {
91 | QString dirPath = fileDialog.selectedFiles().first();
92 | ui->lineEditApplicationsDir->setText(dirPath);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/ui/remove.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | RemoveDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 431
10 | 151
11 |
12 |
13 |
14 | Please confirm
15 |
16 |
17 |
18 |
19 | 20
20 | 20
21 | 391
22 | 111
23 |
24 |
25 |
26 |
27 | QLayout::SetMinimumSize
28 |
29 | -
30 |
31 |
32 | <html><head/><body><p>Are you sure you want to remove this AppImage?</body></html>
33 |
34 |
35 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
36 |
37 |
38 |
39 | -
40 |
41 |
42 |
43 | 0
44 | 0
45 |
46 |
47 |
48 |
49 | 389
50 | 0
51 |
52 |
53 |
54 | %1
55 |
56 |
57 |
58 | -
59 |
60 |
61 | <html><head/><body><p>Uncheck to only remove the desktop integration, but leave the file on the system.</p></body></html>
62 |
63 |
64 | Remove AppImage file from system
65 |
66 |
67 | true
68 |
69 |
70 |
71 | -
72 |
73 |
74 | Qt::Horizontal
75 |
76 |
77 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | buttonBox
88 | accepted()
89 | RemoveDialog
90 | accept()
91 |
92 |
93 | 248
94 | 254
95 |
96 |
97 | 157
98 | 274
99 |
100 |
101 |
102 |
103 | buttonBox
104 | rejected()
105 | RemoveDialog
106 | reject()
107 |
108 |
109 | 316
110 | 260
111 |
112 |
113 | 286
114 | 274
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/cmake/cpack_deb.cmake:
--------------------------------------------------------------------------------
1 | # required for DEB-DEFAULT to work as intended
2 | cmake_minimum_required(VERSION 3.6)
3 |
4 | # Fix for https://github.com/TheAssassin/AppImageLauncher/issues/28
5 | execute_process(
6 | COMMAND lsb_release -c
7 | OUTPUT_VARIABLE _lsb_release_output
8 | )
9 |
10 | if(_lsb_release_output MATCHES bionic)
11 | message(STATUS "platform is bionic, enabling compatibility mode for CPack Debian packaging")
12 | set(_compatibility_level bionic)
13 | elseif(_lsb_release_output MATCHES cosmic)
14 | message(STATUS "platform is cosmic, enabling compatibility mode for CPack Debian packaging")
15 | set(_compatibility_level cosmic)
16 | else()
17 | set(_compatibility_level "")
18 | endif()
19 |
20 | set(CPACK_DEBIAN_COMPATIBILITY_LEVEL ${_compatibility_level} CACHE STRING "Available values: bionic (Ubuntu 18.04 LTS), cosmic (Ubuntu 18.10)")
21 |
22 | unset(_lsb_release_output)
23 | unset(_compatibility_level)
24 |
25 | # allow building Debian packages on non-Debian systems
26 | if(DEFINED ENV{ARCH})
27 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE $ENV{ARCH})
28 | if(CPACK_DEBIAN_PACKAGE_ARCHITECTURE MATCHES "i686")
29 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "i386")
30 | elseif(CPACK_DEBIAN_PACKAGE_ARCHITECTURE MATCHES "x86_64")
31 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
32 | endif()
33 | endif()
34 |
35 | # make sure to package components separately
36 | #set(CPACK_DEB_PACKAGE_COMPONENT ON)
37 | set(CPACK_DEB_COMPONENT_INSTALL ON)
38 |
39 | # override default package naming
40 | set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
41 |
42 | # Debian packaging global options
43 | set(CPACK_DEBIAN_COMPRESSION_TYPE xz)
44 |
45 | # use git hash as package release
46 | set(CPACK_DEBIAN_PACKAGE_RELEASE "git${APPIMAGELAUNCHER_GIT_COMMIT_DATE_SHORT}.${APPIMAGELAUNCHER_GIT_COMMIT}")
47 |
48 | # append build ID, similar to AppImage naming
49 | if(DEFINED ENV{TRAVIS_BUILD_NUMBER})
50 | set(CPACK_DEBIAN_PACKAGE_RELEASE "travis$ENV{TRAVIS_BUILD_NUMBER}~${CPACK_DEBIAN_PACKAGE_RELEASE}")
51 | else()
52 | set(CPACK_DEBIAN_PACKAGE_RELEASE "local~${CPACK_DEBIAN_PACKAGE_RELEASE}")
53 | endif()
54 |
55 | if(CPACK_DEBIAN_COMPATIBILITY_LEVEL)
56 | set(CPACK_DEBIAN_PACKAGE_RELEASE "${CPACK_DEBIAN_PACKAGE_RELEASE}+${CPACK_DEBIAN_COMPATIBILITY_LEVEL}")
57 | endif()
58 |
59 | # bash is required to run install hooks
60 | set(CPACK_DEBIAN_APPIMAGELAUNCHER_PACKAGE_PREDEPENDS bash)
61 |
62 | # package name
63 | set(CPACK_DEBIAN_APPIMAGELAUNCHER_PACKAGE_NAME "appimagelauncher")
64 |
65 | # TODO: packagers watch out: you should set this to depend on a libappimage package, and avoid installing the library
66 | # to a custom location in install.cmake
67 |
68 | if(CPACK_DEBIAN_COMPATIBILITY_LEVEL STREQUAL "bionic" OR CPACK_DEBIAN_COMPATIBILITY_LEVEL STREQUAL "cosmic")
69 | set(CPACK_DEBIAN_APPIMAGELAUNCHER_PACKAGE_DEPENDS "libqt5widgets5 (>= 5.2.1), libqt5gui5 (>= 5.2.1), libqt5core5a (>= 5.2.1), binfmt-support (>= 2.0), libcurl4")
70 | else()
71 | set(CPACK_DEBIAN_APPIMAGELAUNCHER_PACKAGE_DEPENDS "libqt5widgets5 (>= 5.2.1), libqt5gui5 (>= 5.2.1), libqt5core5a (>= 5.2.1), binfmt-support (>= 2.0), libcurl3")
72 | endif()
73 |
74 | # improve dependency list
75 | set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
76 |
77 | # add postinst and prerm hooks to Debian package
78 | configure_file(
79 | ${PROJECT_SOURCE_DIR}/resources/install-scripts/post-install.in
80 | ${PROJECT_BINARY_DIR}/cmake/debian/postinst
81 | @ONLY
82 | )
83 | configure_file(
84 | ${PROJECT_SOURCE_DIR}//resources/install-scripts/post-uninstall.in
85 | ${PROJECT_BINARY_DIR}/cmake/debian/postrm
86 | @ONLY
87 | )
88 |
89 | set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
90 | "${PROJECT_BINARY_DIR}/cmake/debian/postinst"
91 | "${PROJECT_BINARY_DIR}/cmake/debian/postrm"
92 | )
93 |
--------------------------------------------------------------------------------
/src/cli/commands/IntegrateCommand.cpp:
--------------------------------------------------------------------------------
1 | // library headers
2 | #include
3 |
4 | // local headers
5 | #include "IntegrateCommand.h"
6 | #include "exceptions.h"
7 | #include "shared.h"
8 | #include "logging.h"
9 |
10 | namespace appimagelauncher {
11 | namespace cli {
12 | namespace commands {
13 | void IntegrateCommand::exec(QList arguments) {
14 | if (arguments.empty()) {
15 | throw InvalidArgumentsError("No AppImages passed on commandline");
16 | }
17 |
18 | // make sure all AppImages exist on disk before further processing
19 | for (auto& path : arguments) {
20 | if (!QFileInfo(path).exists()) {
21 | throw UsageError("could not find file " + path);
22 | }
23 |
24 | // make path absolute
25 | // that will just prevent mistakes in libappimage and shared etc.
26 | // (stuff like TryExec keys etc. being set to paths relative to CWD when running the command , ...)
27 | path = QFileInfo(path).absoluteFilePath();
28 | }
29 |
30 | for (const auto& pathToAppImage : arguments) {
31 | qout() << "Processing " << pathToAppImage << endl;
32 |
33 | if (!QFileInfo(pathToAppImage).isFile()) {
34 | qerr() << "Warning: Not a file, skipping: " << pathToAppImage << endl;
35 | continue;
36 | }
37 |
38 | if (!isAppImage(pathToAppImage)) {
39 | qerr() << "Warning: Not an AppImage, skipping: " << pathToAppImage << endl;
40 | continue;
41 | }
42 |
43 | if (hasAlreadyBeenIntegrated(pathToAppImage)) {
44 | if (desktopFileHasBeenUpdatedSinceLastUpdate(pathToAppImage)) {
45 | qout() << "AppImage has been integrated already and doesn't need to be re-integrated, skipping" << endl;
46 | continue;
47 | }
48 |
49 | qout() << "AppImage has already been integrated, but needs to be reintegrated" << endl;
50 | }
51 |
52 | auto pathToIntegratedAppImage = buildPathToIntegratedAppImage(pathToAppImage);
53 |
54 | // check if it's already in the right place
55 | if (QFileInfo(pathToAppImage).absoluteFilePath() != QFileInfo(pathToIntegratedAppImage).absoluteFilePath()) {
56 | qout() << "Moving AppImage to integration directory" << endl;
57 |
58 | if (QFile::exists(pathToIntegratedAppImage) && !QFile(pathToIntegratedAppImage).remove()) {
59 | qerr() << "Could not move AppImage into integration directory (error: failed to overwrite existing file)" << endl;
60 | continue;
61 | }
62 |
63 | if (!QFile(pathToAppImage).rename(pathToIntegratedAppImage)) {
64 | qerr() << "Cannot move AppImage to integration directory (permission problem?), attempting to copy instead" << endl;
65 |
66 | if (!QFile(pathToAppImage).copy(pathToIntegratedAppImage)) {
67 | throw CliError("Failed to copy AppImage, giving up");
68 | }
69 | }
70 | } else {
71 | qout() << "AppImage already in integration directory" << endl;
72 | }
73 |
74 | installDesktopFileAndIcons(pathToAppImage);
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/daemon/main.cpp:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 | #include
4 | #include
5 |
6 | // library includes
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | // local includes
14 | #include "shared.h"
15 | #include "filesystemwatcher.h"
16 | #include "worker.h"
17 |
18 | int main(int argc, char* argv[]) {
19 | // make sure shared won't try to use the UI
20 | setenv("_FORCE_HEADLESS", "1", 1);
21 |
22 | QCoreApplication app(argc, argv);
23 |
24 | // by default, watch configured/default destination directory only
25 | const auto defaultDestination = integratedAppImagesDestination();
26 | FileSystemWatcher watcher(defaultDestination.absolutePath());
27 |
28 | // create a daemon worker instance
29 | // it is used to integrate all AppImages initially, and to integrate files found via inotify
30 | Worker worker;
31 |
32 | // initial search for AppImages; if AppImages are found, they will be integrated, unless they already are
33 | std::cout << "Searching for existing AppImages" << std::endl;
34 | for (const auto& dir : watcher.directories()) {
35 | for (QDirIterator it(dir); it.hasNext();) {
36 | const auto& path = it.next();
37 | if (QFileInfo(path).isFile()) {
38 | const auto appImageType = appimage_get_type(path.toStdString().c_str(), false);
39 | const auto isAppImage = 0 < appImageType && appImageType <= 2;
40 | if (isAppImage) {
41 | // at application startup, we don't want to integrate AppImages that have been integrated already,
42 | // as that it slows down very much
43 | // the integration will be updated as soon as any of these AppImages is run with AppImageLauncher
44 | std::cout << "Found AppImage: " << path.toStdString() << std::endl;
45 | if (!appimage_is_registered_in_system(path.toStdString().c_str())) {
46 | std::cout << "AppImage is not integrated yet, integrating" << std::endl;
47 | worker.scheduleForIntegration(path);
48 | } else if (!desktopFileHasBeenUpdatedSinceLastUpdate(path)) {
49 | std::cout << "AppImage has been integrated already but needs to be reintegrated" << std::endl;
50 | worker.scheduleForIntegration(path);
51 | } else {
52 | std::cout << "AppImage integrated already, skipping" << std::endl;
53 | }
54 | }
55 | }
56 | }
57 | }
58 | // (re-)integrate all AppImages at once
59 | worker.executeDeferredOperations();
60 |
61 | // after (re-)integrating all AppImages, clean up old desktop integration resources before start
62 | if (!cleanUpOldDesktopIntegrationResources()) {
63 | std::cout << "Failed to clean up old desktop integration resources" << std::endl;
64 | }
65 |
66 | std::cout << "Watching directories: ";
67 | for (const auto& dir : watcher.directories()) {
68 | std::cout << dir.toStdString().c_str();
69 | }
70 | std::cout << std::endl;
71 |
72 | FileSystemWatcher::connect(&watcher, &FileSystemWatcher::fileChanged, &worker, &Worker::scheduleForIntegration, Qt::QueuedConnection);
73 | FileSystemWatcher::connect(&watcher, &FileSystemWatcher::fileRemoved, &worker, &Worker::scheduleForUnintegration, Qt::QueuedConnection);
74 |
75 | if (!watcher.startWatching()) {
76 | std::cerr << "Could not start watching directories" << std::endl;
77 | return 1;
78 | }
79 |
80 | watcher.startWatching();
81 | QObject::connect(&app, &QCoreApplication::aboutToQuit, &watcher, &FileSystemWatcher::stopWatching);
82 |
83 | return QCoreApplication::exec();
84 | }
85 |
--------------------------------------------------------------------------------
/resources/icons/hicolor/scalable/apps/AppImageLauncher.svg:
--------------------------------------------------------------------------------
1 |
2 |
79 |
--------------------------------------------------------------------------------
/src/shared/shared.h:
--------------------------------------------------------------------------------
1 | /* central file for utility functions */
2 |
3 | #pragma once
4 |
5 | // system headers
6 | #include
7 | #include
8 |
9 | // library headers
10 | #include
11 | #include
12 | #include
13 |
14 | enum IntegrationState {
15 | INTEGRATION_FAILED = 0,
16 | INTEGRATION_SUCCESSFUL,
17 | INTEGRATION_ABORTED
18 | };
19 |
20 | // standard location for integrated AppImages
21 | // currently hardcoded, can not be changed by users
22 | static const auto DEFAULT_INTEGRATION_DESTINATION = QString(getenv("HOME")) + "/Applications/";
23 |
24 | // little convenience method to display warnings
25 | void displayWarning(const QString& message);
26 |
27 | // little convenience method to display errors
28 | void displayError(const QString& message);
29 |
30 | // reliable way to check if the current session is graphical or not
31 | bool isHeadless();
32 |
33 | // makes an existing file executable
34 | bool makeExecutable(const QString& path);
35 |
36 | // removes executable bits from file's permissions
37 | bool makeNonExecutable(const QString& path);
38 |
39 | // installs desktop file for given AppImage, including AppImageLauncher specific modifications
40 | // set resolveCollisions to false in order to leave the Name entries as-is
41 | bool installDesktopFileAndIcons(const QString& pathToAppImage, bool resolveCollisions = true);
42 |
43 | // update AppImage's existing desktop file with AppImageLauncher specific entries
44 | // this alias for installDesktopFileAndIcons does not perform any collision detection and resolving
45 | bool updateDesktopFileAndIcons(const QString& pathToAppImage);
46 |
47 | // update desktop database and icon caches of desktop environments
48 | // this makes sure that:
49 | // - outdated entries are removed from the launcher
50 | // - icons of freshly integrated AppImages are displayed in the launcher
51 | bool updateDesktopDatabaseAndIconCaches();
52 |
53 | // integrates an AppImage using a standard workflow used across all AppImageLauncher applications
54 | IntegrationState integrateAppImage(const QString& pathToAppImage, const QString& pathToIntegratedAppImage);
55 |
56 | // write config file to standard location with given configuration values
57 | // askToMove and enableDaemon both are bools but represented as int to add some sort of "unset" state
58 | // < 0: unset; 0 = false; > 0 = true
59 | // destination is a string that, when empty, will be interpreted as "use default"
60 | void createConfigFile(int askToMove, QString destination, int enableDaemon);
61 |
62 | // load config file and return it
63 | std::shared_ptr getConfig();
64 |
65 | // return directory into which the integrated AppImages will be moved
66 | QDir integratedAppImagesDestination();
67 |
68 | // build path to standard location for integrated AppImages
69 | QString buildPathToIntegratedAppImage(const QString& pathToAppImage);
70 |
71 | // get AppImage MD5 digest
72 | // extracts the digest embedded in the file
73 | // if no such digest has been embedded, it calculates it using libappimage
74 | QString getAppImageDigestMd5(const QString& path);
75 |
76 | // checks whether AppImage has been integrated already
77 | bool hasAlreadyBeenIntegrated(const QString& pathToAppImage);
78 |
79 | // checks whether file is in a given directory
80 | bool isInDirectory(const QString& pathToAppImage, const QDir& directory);
81 |
82 | // clean up old desktop files (and related resources, such as icons)
83 | bool cleanUpOldDesktopIntegrationResources(bool verbose = false);
84 |
85 | // returns absolute path to currently running binary
86 | std::shared_ptr getOwnBinaryPath();
87 |
88 | // returns true if AppImageLauncher was updated since the desktop file for a given AppImage has been updated last
89 | bool desktopFileHasBeenUpdatedSinceLastUpdate(const QString& pathToAppImage);
90 |
91 | // returns true if the AppImageLauncherFS service was restarted since the last AppImageLauncher update
92 | bool fsDaemonHasBeenRestartedSinceLastUpdate();
93 |
94 | // checks whether a file is an AppImage
95 | bool isAppImage(const QString& path);
96 |
--------------------------------------------------------------------------------
/cmake/install.cmake:
--------------------------------------------------------------------------------
1 | # define private libraries install destionation
2 | if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_LIBDIR})
3 | set(_libdir ${CMAKE_INSTALL_LIBDIR})
4 | else()
5 | file(RELATIVE_PATH _libdir ${CMAKE_INSTALL_LIBDIR} ${CMAKE_INSTALL_PREFIX})
6 | endif()
7 |
8 | set(_private_libdir ${_libdir}/appimagelauncher)
9 |
10 | # calculate relative path from binary install destination to private library install dir
11 | if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_BINDIR})
12 | set(_bindir ${CMAKE_INSTALL_BINDIR})
13 | else()
14 | file(RELATIVE_PATH _bindir ${CMAKE_INSTALL_BINDIR} ${CMAKE_INSTALL_PREFIX})
15 | #set(_bindir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
16 | endif()
17 |
18 | set(_abs_bindir ${CMAKE_INSTALL_PREFIX}/${_bindir})
19 | set(_abs_private_libdir ${CMAKE_INSTALL_PREFIX}/${_private_libdir})
20 |
21 | file(RELATIVE_PATH _rpath ${_abs_bindir} ${_abs_private_libdir})
22 | set(_rpath "\$ORIGIN/${_rpath}")
23 |
24 |
25 | # install libappimage.so into lib/appimagekit to avoid overwriting a libappimage potentially installed into /usr/lib
26 | # or /usr/lib/x86_64-... or wherever the OS puts its libraries
27 | # for some reason, using TARGETS ... doesn't work here, therefore using the absolute file path
28 | file(GLOB libappimage_files ${PROJECT_BINARY_DIR}/lib/libappimage/src/libappimage/libappimage.so*)
29 | file(GLOB libappimageupdate_files ${PROJECT_BINARY_DIR}/lib/AppImageUpdate/src/libappimageupdate.so*)
30 | file(GLOB libappimageupdate-qt_files ${PROJECT_BINARY_DIR}/lib/AppImageUpdate/src/qt-ui/libappimageupdate-qt.so*)
31 | message(STATUS ${PROJECT_BINARY_DIR}/lib/libappimage/src/libappimage/libappimage.so*)
32 | foreach(i libappimage libappimageupdate libappimageupdate-qt)
33 | # prevent unnecessary messages
34 | if(NOT i STREQUAL libappimage OR NOT USE_SYSTEM_LIBAPPIMAGE)
35 | if(NOT ${i}_files)
36 | message(WARNING "Could not find ${i} library files, cannot bundle; if you want to bundle the files, please re-run cmake before calling make install")
37 | else()
38 | install(
39 | FILES
40 | ${${i}_files}
41 | DESTINATION ${_private_libdir} COMPONENT APPIMAGELAUNCHER
42 | )
43 | endif()
44 | endif()
45 | endforeach()
46 |
47 | if(NOT BUILD_LITE)
48 | # TODO: find alternative to the following "workaround" (a pretty dirty hack, actually...)
49 | # bundle update-binfmts as a fallback for distros which don't have it installed
50 | find_program(UPDATE_BINFMTS
51 | NAMES update-binfmts
52 | PATHS /usr/sbin
53 | )
54 |
55 | if(NOT UPDATE_BINFMTS STREQUAL UPDATE_BINFMTS-NOTFOUND AND EXISTS ${UPDATE_BINFMTS})
56 | message(STATUS "Found update-binfmts, bundling: ${UPDATE_BINFMTS}")
57 | install(
58 | FILES /usr/sbin/update-binfmts
59 | PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
60 | DESTINATION ${_private_libdir} COMPONENT APPIMAGELAUNCHER
61 | )
62 | else()
63 | message(WARNING "update-binfmts could not be found. Please install the binfmt-support package if you intend to build RPM packages.")
64 | endif()
65 |
66 | # binfmt.d config file -- used as a fallback, if update-binfmts is not available
67 | configure_file(
68 | ${PROJECT_SOURCE_DIR}/resources/binfmt.d/appimage.conf.in
69 | ${PROJECT_BINARY_DIR}/resources/binfmt.d/appimage.conf
70 | @ONLY
71 | )
72 | # caution: don't use ${CMAKE_INSTALL_LIBDIR} here, it's really just lib/binfmt.d
73 | install(
74 | FILES ${PROJECT_BINARY_DIR}/resources/binfmt.d/appimage.conf
75 | DESTINATION lib/binfmt.d COMPONENT APPIMAGELAUNCHER
76 | )
77 |
78 | # install systemd service configuration for appimagelauncherfs
79 | configure_file(
80 | ${PROJECT_SOURCE_DIR}/resources/appimagelauncherfs.service.in
81 | ${PROJECT_BINARY_DIR}/resources/appimagelauncherfs.service
82 | @ONLY
83 | )
84 | # caution: don't use ${CMAKE_INSTALL_LIBDIR} here, it's really just lib/systemd/user
85 | install(
86 | FILES ${PROJECT_BINARY_DIR}/resources/appimagelauncherfs.service
87 | DESTINATION lib/systemd/user/ COMPONENT APPIMAGELAUNCHERFS
88 | )
89 | endif()
90 |
91 | # install systemd service configuration for appimagelauncherd
92 | configure_file(
93 | ${PROJECT_SOURCE_DIR}/resources/appimagelauncherd.service.in
94 | ${PROJECT_BINARY_DIR}/resources/appimagelauncherd.service
95 | @ONLY
96 | )
97 | # caution: don't use ${CMAKE_INSTALL_LIBDIR} here, it's really just lib/systemd/user
98 | install(
99 | FILES ${PROJECT_BINARY_DIR}/resources/appimagelauncherd.service
100 | DESTINATION lib/systemd/user/ COMPONENT APPIMAGELAUNCHER
101 | )
102 |
--------------------------------------------------------------------------------
/src/ui/remove_main.cpp:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 | #include
4 |
5 | // library includes
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | extern "C" {
18 | #include
19 | }
20 |
21 | // local includes
22 | #include "shared.h"
23 | #include "translationmanager.h"
24 | #include "trashbin.h"
25 | #include "ui_remove.h"
26 |
27 | bool unregisterAppImage(const QString& pathToAppImage) {
28 | auto rv = appimage_unregister_in_system(pathToAppImage.toStdString().c_str(), false);
29 |
30 | if (rv != 0)
31 | return false;
32 |
33 | return true;
34 | }
35 |
36 | int main(int argc, char** argv) {
37 | QCommandLineParser parser;
38 | parser.setApplicationDescription(QObject::tr("Removes AppImages after desktop integration, for use by Linux distributions"));
39 | QApplication app(argc, argv);
40 | QApplication::setApplicationDisplayName(QObject::tr("AppImageLauncher remove", "remove helper app name"));
41 | QApplication::setWindowIcon(QIcon(":/AppImageLauncher.svg"));
42 |
43 | std::ostringstream version;
44 | version << "version " << APPIMAGELAUNCHER_VERSION << " "
45 | << "(git commit " << APPIMAGELAUNCHER_GIT_COMMIT << "), built on "
46 | << APPIMAGELAUNCHER_BUILD_DATE;
47 | QApplication::setApplicationVersion(QString::fromStdString(version.str()));
48 |
49 | // install translations
50 | TranslationManager translationManager(app);
51 |
52 | parser.addHelpOption();
53 | parser.addVersionOption();
54 |
55 | parser.process(app);
56 |
57 | parser.addPositionalArgument("path", QObject::tr("Path to AppImage"), QObject::tr(""));
58 |
59 | if (parser.positionalArguments().empty()) {
60 | parser.showHelp(1);
61 | }
62 |
63 | const auto pathToAppImage = parser.positionalArguments().first();
64 |
65 | if (!QFile(pathToAppImage).exists()) {
66 | QMessageBox::critical(nullptr, "Error", QObject::tr("Error: no such file or directory: %1").arg(pathToAppImage));
67 | return 1;
68 | }
69 |
70 | const auto type = appimage_get_type(pathToAppImage.toStdString().c_str(), false);
71 |
72 | if (type <= 0 || type > 2) {
73 | QMessageBox::critical(
74 | nullptr,
75 | QObject::tr("AppImage remove helper error"),
76 | QObject::tr("Not an AppImage:\n\n%1").arg(pathToAppImage)
77 | );
78 | return 1;
79 | }
80 |
81 | // this tool should not do anything if the file isn't integrated
82 | // the file is only supposed to work on integrated AppImages and _nothing else_
83 | if (!hasAlreadyBeenIntegrated(pathToAppImage)) {
84 | QMessageBox::critical(
85 | nullptr,
86 | QObject::tr("AppImage remove helper error"),
87 | QObject::tr("Refusing to work on non-integrated AppImage:\n\n%1").arg(pathToAppImage)
88 | );
89 | return 1;
90 | }
91 |
92 | QDialog dialog;
93 | Ui::RemoveDialog ui;
94 | ui.setupUi(&dialog);
95 | ui.pathLabel->setText(pathToAppImage);
96 |
97 | auto rv = dialog.exec();
98 |
99 | switch (rv) {
100 | case 1: {
101 | // first, unregister AppImage
102 | if (!unregisterAppImage(pathToAppImage)) {
103 | QMessageBox::critical(
104 | nullptr,
105 | QObject::tr("Error"),
106 | QObject::tr("Failed to unregister AppImage: %1").arg(pathToAppImage)
107 | );
108 | return 1;
109 | }
110 |
111 | if (ui.checkBox->checkState() == Qt::Checked) {
112 | TrashBin bin;
113 |
114 | // now, move AppImage into trash bin
115 | if (!bin.disposeAppImage(pathToAppImage)) {
116 | QMessageBox::critical(
117 | nullptr,
118 | QObject::tr("Error"),
119 | QObject::tr("Failed to move AppImage into trash bin directory")
120 | );
121 | return 1;
122 | }
123 |
124 | // run clean up cycle for trash bin
125 | // if the current AppImage is ready to be deleted, this call will immediately remove it from the system
126 | // otherwise, it'll be cleaned up at some subsequent run of AppImageLauncher or the removal tool
127 | if (!bin.cleanUp()) {
128 | QMessageBox::critical(
129 | nullptr,
130 | QObject::tr("Error"),
131 | QObject::tr("Failed to clean up AppImage trash bin: %1").arg(bin.path())
132 | );
133 | return 1;
134 | }
135 |
136 | // update desktop database and icon caches
137 | if (!updateDesktopDatabaseAndIconCaches())
138 | return 1;
139 | }
140 |
141 | return 0;
142 | }
143 | default: {
144 | // exit without any actions
145 | return 0;
146 | }
147 | }
148 |
149 | // sanity check: this line _should_ be unreachable
150 | throw std::runtime_error("This line shouldn't have been reachable...");
151 | }
152 |
153 |
--------------------------------------------------------------------------------
/src/ui/settings_dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | SettingsDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 472
10 | 376
11 |
12 |
13 |
14 | AppImageLauncher Settings
15 |
16 |
17 | -
18 |
19 |
20 | Launcher Dialog
21 |
22 |
23 |
-
24 |
25 |
26 | Ask whether to move AppImage files into the applications directory
27 |
28 |
29 |
30 |
31 |
32 |
33 | -
34 |
35 |
36 | Applications directory
37 |
38 |
39 |
-
40 |
41 |
42 |
43 |
44 |
45 |
46 | ..
47 |
48 |
49 |
50 | -
51 |
52 |
53 | Location where to store your AppImage files to ease their management
54 |
55 |
56 | true
57 |
58 |
59 |
60 | -
61 |
62 |
63 | /path
64 |
65 |
66 |
67 | -
68 |
69 |
70 | Enable auto-integration daemon
71 |
72 |
73 |
74 |
75 |
76 |
77 | -
78 |
79 |
80 |
81 | 0
82 | 0
83 |
84 |
85 |
86 |
87 |
88 |
89 | Available Features
90 |
91 |
92 |
93 |
94 | 10
95 | 30
96 | 431
97 | 430
98 |
99 |
100 |
101 |
102 | 0
103 | 0
104 |
105 |
106 |
107 |
108 | 0
109 | 430
110 |
111 |
112 |
113 | Qt::LeftToRight
114 |
115 |
116 | TextLabel
117 |
118 |
119 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
120 |
121 |
122 | true
123 |
124 |
125 |
126 |
127 | -
128 |
129 |
130 | Qt::Horizontal
131 |
132 |
133 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | buttonBox
143 | accepted()
144 | SettingsDialog
145 | accept()
146 |
147 |
148 | 248
149 | 254
150 |
151 |
152 | 157
153 | 274
154 |
155 |
156 |
157 |
158 | buttonBox
159 | rejected()
160 | SettingsDialog
161 | reject()
162 |
163 |
164 | 316
165 | 260
166 |
167 |
168 | 286
169 | 274
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/src/fswatcher/filesystemwatcher.cpp:
--------------------------------------------------------------------------------
1 | // system includes
2 | #include
3 | #include