├── AUTHORS ├── CHANGELOG ├── CMakeLists.txt ├── COPYING ├── Digia-Qt-LGPL-Exception-1.1 ├── README.md ├── cmake ├── cmake_uninstall.cmake.in ├── compiler_settings.cmake ├── qt6xdg-config.cmake.in └── qt6xdgiconloader-config.cmake.in ├── config ├── lxqt-qtxdg.conf └── qtxdg.conf ├── examples └── use-qtxdg │ ├── CMakeLists.txt │ ├── README │ └── main.cpp ├── src ├── CMakeLists.txt ├── qtxdg │ ├── CMakeLists.txt │ ├── dbus │ │ └── org.freedesktop.Application.xml │ ├── qtxdglogging.cpp │ ├── qtxdglogging.h │ ├── xdgaction.cpp │ ├── xdgaction.h │ ├── xdgautostart.cpp │ ├── xdgautostart.h │ ├── xdgdefaultapps.cpp │ ├── xdgdefaultapps.h │ ├── xdgdesktopfile.cpp │ ├── xdgdesktopfile.h │ ├── xdgdesktopfile_p.h │ ├── xdgdirs.cpp │ ├── xdgdirs.h │ ├── xdgicon.cpp │ ├── xdgicon.h │ ├── xdgmacros.h │ ├── xdgmenu.cpp │ ├── xdgmenu.h │ ├── xdgmenu_p.h │ ├── xdgmenuapplinkprocessor.cpp │ ├── xdgmenuapplinkprocessor.h │ ├── xdgmenulayoutprocessor.cpp │ ├── xdgmenulayoutprocessor.h │ ├── xdgmenureader.cpp │ ├── xdgmenureader.h │ ├── xdgmenurules.cpp │ ├── xdgmenurules.h │ ├── xdgmenuwidget.cpp │ ├── xdgmenuwidget.h │ ├── xdgmimeapps.cpp │ ├── xdgmimeapps.h │ ├── xdgmimeapps_p.h │ ├── xdgmimeappsbackendinterface.cpp │ ├── xdgmimeappsbackendinterface.h │ ├── xdgmimeappsglibbackend.cpp │ ├── xdgmimeappsglibbackend.h │ ├── xdgmimetype.cpp │ ├── xdgmimetype.h │ ├── xmlhelper.cpp │ └── xmlhelper.h └── xdgiconloader │ ├── CMakeLists.txt │ ├── plugin │ ├── CMakeLists.txt │ ├── xdgiconengineplugin.cpp │ ├── xdgiconengineplugin.h │ └── xdgiconengineplugin.json │ ├── xdgiconloader.cpp │ └── xdgiconloader_p.h ├── test ├── CMakeLists.txt ├── qtxdg_test.cpp ├── qtxdg_test.h ├── tst_xdgdesktopfile.cpp ├── tst_xdgdesktopfile.h └── tst_xdgdirs.cpp └── util ├── CMakeLists.txt ├── qtxdg-desktop-file-start.cpp └── qtxdg-iconfinder.cpp /AUTHORS: -------------------------------------------------------------------------------- 1 | Upstream Authors: 2 | LXQt team: https://lxqt-project.org/ 3 | Razor team: http://razor-qt.org 4 | 5 | Copyright: 6 | Copyright (c) 2010-2012 Razor team 7 | Copyright (c) 2012-2018 LXQt team 8 | 9 | License: LGPL-2.1+ and LGPL-2.1-or-3-with-Digia-1.1-exception 10 | The full text of the LGPL-2.1+ license can be found in the 'COPYING' file. 11 | The Digia-1.1 exception can be found in the 'Digia-Qt-LGPL-Exception-1.1' file. 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.0 FATAL_ERROR) 2 | # CMP0000: Call the cmake_minimum_required() command at the beginning of the top-level 3 | # CMakeLists.txt file even before calling the project() command. 4 | # The cmake_minimum_required(VERSION) command implicitly invokes the cmake_policy(VERSION) 5 | # command to specify that the current project code is written for the given range of CMake 6 | # versions. 7 | project(libqtxdg) 8 | 9 | option(BUILD_TESTS "Builds tests" OFF) 10 | option(BUILD_DEV_UTILS "Builds and install development utils" OFF) 11 | option(QTXDG_INSTALL_DEFAPPS_CONFIG "Install default app config files" ON) 12 | 13 | # additional cmake files 14 | set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 15 | 16 | set(QTXDG_MAJOR_VERSION 4) 17 | set(QTXDG_MINOR_VERSION 2) 18 | set(QTXDG_PATCH_VERSION 0) 19 | set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION}) 20 | 21 | set(LXQTBT_MINIMUM_VERSION "2.2.0") 22 | set(QT_MINIMUM_VERSION "6.6.0") 23 | set(GLIB_MINIMUM_VERSION "2.41.0") # Mime Apps new implementation 24 | 25 | find_package(lxqt2-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED) 26 | find_package(Qt6 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Widgets Svg Xml DBus) 27 | find_package(GLIB ${GLIB_MINIMUM_VERSION} REQUIRED COMPONENTS gobject gio gio-unix) 28 | find_package(XTerm) 29 | 30 | include(GNUInstallDirs) # Standard directories for installation 31 | include(CMakePackageConfigHelpers) 32 | include(GenerateExportHeader) 33 | 34 | include(LXQtConfigVars) 35 | include(LXQtPreventInSourceBuilds) 36 | include(LXQtCreatePkgConfigFile) 37 | include(LXQtCreatePortableHeaders) 38 | include(LXQtCompilerSettings NO_POLICY_SCOPE) 39 | 40 | # Add link optimizations. It make the .so around 33% smaller without any known 41 | # drawback. 42 | include(compiler_settings NO_POLICY_SCOPE) 43 | 44 | set(CMAKE_AUTOMOC ON) 45 | 46 | if (BUILD_TESTS) 47 | find_package(Qt6 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Test) 48 | endif() 49 | 50 | 51 | set(QTXDGX_LIBRARY_NAME "Qt6Xdg") 52 | set(QTXDGX_FILE_NAME "qt6xdg") 53 | 54 | set(QTXDGX_ICONLOADER_LIBRARY_NAME "Qt6XdgIconLoader") 55 | set(QTXDGX_ICONLOADER_FILE_NAME "qt6xdgiconloader") 56 | set(QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME "Qt6XdgIconPlugin") 57 | 58 | set(QTXDGX_PKG_CONFIG_DESCRIPTION "Qt6Xdg, a Qt6 implementation of XDG standards") 59 | set(QTXDGX_PKG_CONFIG_REQUIRES "Qt6Core >= ${QT_MINIMUM_VERSION}, Qt6Xml >= ${QT_MINIMUM_VERSION}, Qt6Widgets >= ${QT_MINIMUM_VERSION}, Qt6DBus >= ${QT_MINIMUM_VERSION}, Qt6XdgIconLoader = ${QTXDG_VERSION_STRING}") 60 | 61 | set(QTXDGX_ICONLOADER_PKG_CONFIG_DESCRIPTION "Qt6XdgIconLader, a Qt6 XDG Icon Loader") 62 | set(QTXDGX_ICONLOADER_PKG_CONFIG_REQUIRES "Qt6Gui >= ${QT_MINIMUM_VERSION}, Qt6Svg >= ${QT_MINIMUM_VERSION}") 63 | 64 | set(QTXDGX_INTREE_INCLUDEDIR "${CMAKE_CURRENT_BINARY_DIR}/InTreeBuild/include") 65 | 66 | message(STATUS "Building ${PROJECT_NAME} with Qt ${Qt6Core_VERSION}") 67 | 68 | if (QTXDG_INSTALL_DEFAPPS_CONFIG) 69 | file(GLOB QTXDG_CONFIG_FILES config/*.conf) 70 | set(QTXDG_DEFAPPS_CONF_INSTALL_DIR 71 | "${LXQT_ETC_XDG_DIR}" CACHE PATH "Path to qtxdg default apps conf files install dir") 72 | mark_as_advanced(QTXDG_DEFAPPS_CONF_INSTALL_DIR) 73 | endif() 74 | 75 | 76 | add_subdirectory(src) 77 | 78 | if(BUILD_TESTS) 79 | enable_testing() 80 | target_compile_definitions(${QTXDGX_LIBRARY_NAME} 81 | PRIVATE "QTXDG_TESTS=\"1\"" 82 | ) 83 | add_subdirectory(test) 84 | else() 85 | message(STATUS "") 86 | message(STATUS "For building tests use -DBUILD_TESTS=Yes option.") 87 | message(STATUS "") 88 | endif() 89 | 90 | if (BUILD_DEV_UTILS) 91 | add_subdirectory(util) 92 | endif() 93 | 94 | configure_package_config_file( 95 | "${PROJECT_SOURCE_DIR}/cmake/${QTXDGX_FILE_NAME}-config.cmake.in" 96 | "${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake" 97 | INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}" 98 | ) 99 | 100 | write_basic_package_version_file( 101 | "${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config-version.cmake" 102 | VERSION ${QTXDG_VERSION_STRING} 103 | COMPATIBILITY AnyNewerVersion 104 | ) 105 | 106 | configure_package_config_file( 107 | "${PROJECT_SOURCE_DIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}-config.cmake.in" 108 | "${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config.cmake" 109 | INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}" 110 | ) 111 | 112 | write_basic_package_version_file( 113 | "${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config-version.cmake" 114 | VERSION ${QTXDG_VERSION_STRING} 115 | COMPATIBILITY AnyNewerVersion 116 | ) 117 | 118 | lxqt_create_pkgconfig_file( 119 | PACKAGE_NAME ${QTXDGX_LIBRARY_NAME} 120 | DESCRIPTIVE_NAME ${QTXDGX_LIBRARY_NAME} 121 | DESCRIPTION ${QTXDGX_PKG_CONFIG_DESCRIPTION} 122 | INCLUDEDIRS ${QTXDGX_FILE_NAME} 123 | LIBS ${QTXDGX_LIBRARY_NAME} 124 | REQUIRES ${QTXDGX_PKG_CONFIG_REQUIRES} 125 | REQUIRES_PRIVATE ${QTXDGX_ICONLOADER_LIBRARY_NAME} 126 | VERSION ${QTXDG_VERSION_STRING} 127 | INSTALL 128 | ) 129 | 130 | lxqt_create_pkgconfig_file( 131 | PACKAGE_NAME ${QTXDGX_ICONLOADER_LIBRARY_NAME} 132 | DESCRIPTIVE_NAME ${QTXDGX_ICONLOADER_LIBRARY_NAME} 133 | DESCRIPTION ${QTXDGX_ICONLOADER_PKG_CONFIG_DESCRIPTION} 134 | INCLUDEDIRS ${QTXDGX_ICONLOADER_FILE_NAME} 135 | LIBS ${QTXDGX_ICONLOADER_LIBRARY_NAME} 136 | REQUIRES ${QTXDGX_ICONLOADER_PKG_CONFIG_REQUIRES} 137 | VERSION ${QTXDG_VERSION_STRING} 138 | INSTALL 139 | ) 140 | 141 | install(FILES 142 | "${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake" 143 | "${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config-version.cmake" 144 | DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}" 145 | COMPONENT Devel 146 | ) 147 | 148 | install(FILES 149 | "${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config.cmake" 150 | "${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config-version.cmake" 151 | DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}" 152 | COMPONENT Devel 153 | ) 154 | 155 | install(EXPORT 156 | "${QTXDGX_FILE_NAME}-targets" 157 | DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}" 158 | FILE "${QTXDGX_FILE_NAME}-targets.cmake" 159 | COMPONENT Devel 160 | ) 161 | 162 | install(EXPORT 163 | "${QTXDGX_ICONLOADER_FILE_NAME}-targets" 164 | DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}" 165 | FILE "${QTXDGX_ICONLOADER_FILE_NAME}-targets.cmake" 166 | COMPONENT Devel 167 | ) 168 | 169 | if (QTXDG_INSTALL_DEFAPPS_CONFIG) 170 | install(FILES ${QTXDG_CONFIG_FILES} 171 | DESTINATION "${QTXDG_DEFAPPS_CONF_INSTALL_DIR}" 172 | COMPONENT Runtime 173 | ) 174 | endif() 175 | 176 | # uninstall target 177 | configure_file( 178 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" 179 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 180 | IMMEDIATE @ONLY) 181 | 182 | #add_custom_target(uninstall 183 | # COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") 184 | -------------------------------------------------------------------------------- /Digia-Qt-LGPL-Exception-1.1: -------------------------------------------------------------------------------- 1 | Digia Qt LGPL Exception version 1.1 2 | 3 | As an additional permission to the GNU Lesser General Public License version 4 | 2.1, the object code form of a "work that uses the Library" may incorporate 5 | material from a header file that is part of the Library. You may distribute 6 | such object code under terms of your choice, provided that: 7 | (i) the header files of the Library have not been modified; and 8 | (ii) the incorporated material is limited to numerical parameters, data 9 | structure layouts, accessors, macros, inline functions and 10 | templates; and 11 | (iii) you comply with the terms of Section 6 of the GNU Lesser General 12 | Public License version 2.1. 13 | 14 | Moreover, you may apply this exception to a modified version of the Library, 15 | provided that such modification does not involve copying material from the 16 | Library into the modified Library's header files unless such material is 17 | limited to (i) numerical parameters; (ii) data structure layouts; 18 | (iii) accessors; and (iv) small macros, templates and inline functions of 19 | five lines or less in length. 20 | 21 | Furthermore, you are not required to apply this additional permission to a 22 | modified version of the Library. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libqtxdg 2 | 3 | ## Overview 4 | 5 | `libqtxdg` is a Qt implementation of freedesktop.org XDG specifications. 6 | 7 | It is maintained by the LXQt project and nearly all LXQt components are depending on it. Yet it can be used independently from this desktop environment, too. 8 | 9 | The library is able to use GTK+ icon theme caches for faster icon lookup. The cache file can be generated with utility `gtk-update-icon-cache` on a theme directory. If the cache is not present, corrupted, or outdated, the normal slow lookup is still run. 10 | 11 | ## Installation 12 | 13 | ### Sources 14 | 15 | At runtime qtbase is needed. gtk-update-icon-cache represents an optional runtime dependency for the reasons stated above. 16 | Additional build dependencies are CMake, qtsvg, qttools, [lxqt-build-tools](https://github.com/lxqt/lxqt-build-tools) and optionally Git to pull latest VCS checkouts. 17 | 18 | The code configuration is handled by CMake so all corresponding generic instructions apply. Specific CMake variables are 19 | * BUILD_TESTS to build tests. Disabled by default (`OFF`). 20 | * BUILD_DEV_UTILS which builds and installs development utils. Disabled by default as well. 21 | 22 | To build and install run `make` and `make install`respectively. 23 | 24 | ### Binary packages 25 | 26 | The library is provided by all major Linux distributions like Arch Linux, Debian, Fedora and openSUSE. 27 | Just use the distributions' package managers to search for string `libqtxdg`. 28 | 29 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach(file ${files}) 8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 9 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 10 | exec_program( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | if(NOT "${rm_retval}" STREQUAL 0) 16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 17 | endif(NOT "${rm_retval}" STREQUAL 0) 18 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 20 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 21 | endforeach(file) 22 | -------------------------------------------------------------------------------- /cmake/compiler_settings.cmake: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright 2015 Luís Pereira 3 | # Copyright 2013 Hong Jen Yee (PCMan) 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # 1. Redistributions of source code must retain the copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # 3. The name of the author may not be used to endorse or promote products 15 | # derived from this software without specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | #============================================================================= 28 | 29 | #----------------------------------------------------------------------------- 30 | # Honor visibility properties for all target types. 31 | # 32 | # The ``_VISIBILITY_PRESET`` and 33 | # ``VISIBILITY_INLINES_HIDDEN`` target properties affect visibility 34 | # of symbols during dynamic linking. When first introduced these properties 35 | # affected compilation of sources only in shared libraries, module libraries, 36 | # and executables with the ``ENABLE_EXPORTS`` property set. This 37 | # was sufficient for the basic use cases of shared libraries and executables 38 | # with plugins. However, some sources may be compiled as part of static 39 | # libraries or object libraries and then linked into a shared library later. 40 | # CMake 3.3 and above prefer to honor these properties for sources compiled 41 | # in all target types. This policy preserves compatibility for projects 42 | # expecting the properties to work only for some target types. 43 | # 44 | # The ``OLD`` behavior for this policy is to ignore the visibility properties 45 | # for static libraries, object libraries, and executables without exports. 46 | # The ``NEW`` behavior for this policy is to honor the visibility properties 47 | # for all target types. 48 | # 49 | # This policy was introduced in CMake version 3.3. CMake version 50 | # 3.3.0 warns when the policy is not set and uses ``OLD`` behavior. Use 51 | # the ``cmake_policy()`` command to set it to ``OLD`` or ``NEW`` 52 | # explicitly. 53 | #----------------------------------------------------------------------------- 54 | 55 | #----------------------------------------------------------------------------- 56 | # Turn on more aggrassive optimizations not supported by CMake 57 | # References: https://wiki.qt.io/Performance_Tip_Startup_Time 58 | #----------------------------------------------------------------------------- 59 | if (CMAKE_COMPILER_IS_GNUCXX OR LXQT_COMPILER_IS_CLANGCXX) 60 | # -flto: use link-time optimizations to generate more efficient code 61 | if (CMAKE_COMPILER_IS_GNUCXX) 62 | set(LTO_FLAGS "-flto -fuse-linker-plugin") 63 | # When building static libraries with LTO in gcc >= 4.9, 64 | # "gcc-ar" and "gcc-ranlib" should be used instead of "ar" and "ranlib". 65 | # references: 66 | # https://gcc.gnu.org/gcc-4.9/changes.html 67 | # http://hubicka.blogspot.tw/2014/04/linktime-optimization-in-gcc-2-firefox.html 68 | # https://github.com/monero-project/monero/pull/1065/commits/1855213c8fb8f8727f4107716aab8e7ba826462b 69 | if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0") # gcc >= 4.9 70 | set(CMAKE_AR "gcc-ar") 71 | set(CMAKE_RANLIB "gcc-ranlib") 72 | endif() 73 | elseif (LXQT_COMPILER_IS_CLANGCXX) 74 | # The link-time optimization of clang++/llvm seems to be too aggrassive. 75 | # After testing, it breaks the signal/slots of QObject sometimes. 76 | # So disable it for now until there is a solution. 77 | # set(LTO_FLAGS "-flto") 78 | endif() 79 | # apply these options to "Release" build type only 80 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${LTO_FLAGS}") 81 | endif() 82 | -------------------------------------------------------------------------------- /cmake/qt6xdg-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | if (NOT TARGET @QTXDGX_LIBRARY_NAME@) 4 | include(CMakeFindDependencyMacro) 5 | 6 | find_dependency(Qt6Widgets @QT_MINIMUM_VERSION@) 7 | find_dependency(Qt6Xml @QT_MINIMUM_VERSION@) 8 | find_dependency(Qt6DBus @QT_MINIMUM_VERSION@) 9 | find_dependency(Qt6XdgIconLoader @QTXDG_VERSION_STRING@ EXACT) 10 | 11 | if (CMAKE_VERSION VERSION_GREATER 2.8.12) 12 | cmake_policy(SET CMP0024 NEW) 13 | endif() 14 | include("${CMAKE_CURRENT_LIST_DIR}/qt6xdg-targets.cmake") 15 | endif() 16 | -------------------------------------------------------------------------------- /cmake/qt6xdgiconloader-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | if (NOT TARGET @QTXDGX_ICONLOADER_LIBRARY_NAME@) 4 | include(CMakeFindDependencyMacro) 5 | 6 | find_dependency(Qt6Gui @QT_MINIMUM_REQUIRED@) 7 | find_dependency(Qt6Svg @QT_MINIMUM_REQUIRED@) 8 | 9 | if (CMAKE_VERSION VERSION_GREATER 2.8.12) 10 | cmake_policy(SET CMP0024 NEW) 11 | endif() 12 | include("${CMAKE_CURRENT_LIST_DIR}/qt6xdgiconloader-targets.cmake") 13 | endif() 14 | -------------------------------------------------------------------------------- /config/lxqt-qtxdg.conf: -------------------------------------------------------------------------------- 1 | TerminalEmulator=qterminal.desktop 2 | -------------------------------------------------------------------------------- /config/qtxdg.conf: -------------------------------------------------------------------------------- 1 | TerminalEmulator=xterm.desktop 2 | -------------------------------------------------------------------------------- /examples/use-qtxdg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) 2 | # CMP0000: Call the cmake_minimum_required() command at the beginning of the top-level 3 | # CMakeLists.txt file even before calling the project() command. 4 | # The cmake_minimum_required(VERSION) command implicitly invokes the cmake_policy(VERSION) 5 | # command to specify that the current project code is written for the given range of CMake 6 | # versions. 7 | project(use-qtxdg) 8 | 9 | find_package(QT6XDG) 10 | add_executable(use-qtxdg main.cpp) 11 | target_link_libraries(use-qtxdg Qt6Xdg) 12 | -------------------------------------------------------------------------------- /examples/use-qtxdg/README: -------------------------------------------------------------------------------- 1 | An example of how to write an CMakeLists.txt to use libqtxdg. 2 | 3 | To build this example just use: 4 | cmake .. 5 | -------------------------------------------------------------------------------- /examples/use-qtxdg/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) 5 | { 6 | qDebug() << XdgDirs::dataDirs(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(xdgiconloader) 2 | add_subdirectory(qtxdg) 3 | -------------------------------------------------------------------------------- /src/qtxdg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 2 | 3 | set(QTX_LIBRARIES Qt6::Widgets Qt6::Xml Qt6::DBus) 4 | 5 | set(libqtxdg_PUBLIC_H_FILES 6 | xdgaction.h 7 | xdgdesktopfile.h 8 | xdgdirs.h 9 | xdgicon.h 10 | xdgmenu.h 11 | xdgmenuwidget.h 12 | xmlhelper.h 13 | xdgautostart.h 14 | xdgmacros.h 15 | xdgmimetype.h 16 | xdgmimeapps.h 17 | xdgdefaultapps.h 18 | ) 19 | 20 | set(libqtxdg_PUBLIC_CLASSES 21 | XdgAction 22 | XdgDesktopFile 23 | XdgDirs 24 | XdgIcon 25 | XdgMenu 26 | XdgMenuWidget 27 | XmlHelper 28 | XdgAutoStart 29 | XdgMimeType 30 | XdgMimeApps 31 | XdgDefaultApps 32 | ) 33 | 34 | set(libqtxdg_PRIVATE_H_FILES 35 | qtxdglogging.h 36 | xdgmenuapplinkprocessor.h 37 | xdgmenulayoutprocessor.h 38 | xdgmenu_p.h 39 | xdgmenureader.h 40 | xdgmenurules.h 41 | xdgdesktopfile_p.h 42 | xdgmimeapps_p.h 43 | ) 44 | 45 | set(libqtxdg_CPP_FILES 46 | qtxdglogging.cpp 47 | xdgaction.cpp 48 | xdgdesktopfile.cpp 49 | xdgdirs.cpp 50 | xdgicon.cpp 51 | xdgmenuapplinkprocessor.cpp 52 | xdgmenu.cpp 53 | xdgmenulayoutprocessor.cpp 54 | xdgmenureader.cpp 55 | xdgmenurules.cpp 56 | xdgmenuwidget.cpp 57 | xmlhelper.cpp 58 | xdgautostart.cpp 59 | xdgmimetype.cpp 60 | xdgmimeapps.cpp 61 | xdgmimeappsbackendinterface.cpp 62 | xdgmimeappsglibbackend.cpp 63 | xdgdefaultapps.cpp 64 | ) 65 | 66 | QT6_ADD_DBUS_INTERFACE(libqtxdg_DBUS_INTERFACE_SRCS 67 | dbus/org.freedesktop.Application.xml 68 | application_interface 69 | ) 70 | 71 | set_property(SOURCE ${libqtxdg_DBUS_INTERFACE_SRCS} PROPERTY SKIP_AUTOGEN ON) 72 | 73 | add_library(${QTXDGX_LIBRARY_NAME} SHARED 74 | ${libqtxdg_PUBLIC_H_FILES} 75 | ${libqtxdg_PRIVATE_H_FILES} 76 | ${libqtxdg_CPP_FILES} 77 | ${libqtxdg_DBUS_INTERFACE_SRCS} 78 | ) 79 | 80 | target_link_libraries(${QTXDGX_LIBRARY_NAME} 81 | PUBLIC 82 | ${QTX_LIBRARIES} 83 | ${QTXDGX_ICONLOADER_LIBRARY_NAME} 84 | ${GLIB_LIBRARIES} 85 | ${GLIB_GOBJECT_LIBRARIES} 86 | ${GLIB_GIO_LIBRARIES} 87 | ) 88 | 89 | set_target_properties(${QTXDGX_LIBRARY_NAME} PROPERTIES 90 | VERSION ${QTXDG_VERSION_STRING} 91 | SOVERSION ${QTXDG_MAJOR_VERSION} 92 | ) 93 | 94 | target_compile_definitions(${QTXDGX_LIBRARY_NAME} 95 | PRIVATE 96 | "QTXDG_COMPILATION=\"1\"" 97 | "QTXDG_VERSION=\"${QTXDG_VERSION_STRING}\"" 98 | "QT_NO_KEYWORDS" 99 | ) 100 | 101 | target_include_directories(${QTXDGX_LIBRARY_NAME} 102 | INTERFACE 103 | "$" 104 | "$" 105 | "$" 106 | "$" 107 | PRIVATE 108 | ${Qt6Gui_PRIVATE_INCLUDE_DIRS} 109 | ${GLIB_INCLUDE_DIRS} 110 | ${GLIB_GIO_UNIX_INCLUDE_DIR} 111 | ) 112 | 113 | # create the portble headers 114 | lxqt_create_portable_headers(libqtxdg_PORTABLE_HEADERS 115 | HEADER_NAMES ${libqtxdg_PUBLIC_CLASSES} 116 | OUTPUT_DIR "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}" 117 | ) 118 | 119 | # Copy public headers (in tree building) 120 | foreach(h ${libqtxdg_PUBLIC_H_FILES}) 121 | get_filename_component(bh ${h} NAME) 122 | configure_file(${h} "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}/${bh}" COPYONLY) 123 | endforeach() 124 | 125 | # Copy private headers (in tree building) 126 | foreach(h ${libqtxdg_PRIVATE_INSTALLABLE_H_FILES}) 127 | get_filename_component(bh ${h} NAME) 128 | configure_file(${h} "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}/${QTXDG_VERSION_STRING}/private/qtxdg/${bh}" COPYONLY) 129 | endforeach() 130 | 131 | install(TARGETS 132 | ${QTXDGX_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}" 133 | EXPORT "${QTXDGX_FILE_NAME}-targets" 134 | COMPONENT Runtime 135 | ) 136 | 137 | install(FILES 138 | ${libqtxdg_PUBLIC_H_FILES} 139 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}" 140 | COMPONENT Devel 141 | ) 142 | 143 | install(FILES 144 | ${libqtxdg_PRIVATE_INSTALLABLE_H_FILES} 145 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}/${QTXDG_VERSION_STRING}/private/qtxdg" 146 | COMPONENT Devel 147 | ) 148 | 149 | install(FILES 150 | ${libqtxdg_PORTABLE_HEADERS} 151 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}" 152 | COMPONENT Devel 153 | ) 154 | -------------------------------------------------------------------------------- /src/qtxdg/dbus/org.freedesktop.Application.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/qtxdg/qtxdglogging.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "qtxdglogging.h" 22 | 23 | #include 24 | 25 | #if defined(NDEBUG) 26 | Q_LOGGING_CATEGORY(QtXdgMimeApps, "qtxdg.mimeapps", QtInfoMsg) 27 | Q_LOGGING_CATEGORY(QtXdgMimeAppsGLib, "qtxdg.mimeapps.glib", QtInfoMsg) 28 | #else 29 | Q_LOGGING_CATEGORY(QtXdgMimeApps, "qtxdg.mimeapps") 30 | Q_LOGGING_CATEGORY(QtXdgMimeAppsGLib, "qtxdg.mimeapps.glib") 31 | #endif 32 | -------------------------------------------------------------------------------- /src/qtxdg/qtxdglogging.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef QTXDGLOGGING_H 22 | #define QTXDGLOGGING_H 23 | 24 | #include 25 | 26 | Q_DECLARE_LOGGING_CATEGORY(QtXdgMimeApps) 27 | Q_DECLARE_LOGGING_CATEGORY(QtXdgMimeAppsGLib) 28 | 29 | #endif // QTXDGLOGGING_H 30 | -------------------------------------------------------------------------------- /src/qtxdg/xdgaction.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgaction.h" 29 | #include "xdgicon.h" 30 | #include 31 | #include 32 | 33 | 34 | XdgAction::XdgAction(QObject *parent): 35 | QAction(parent) 36 | { 37 | } 38 | 39 | 40 | XdgAction::XdgAction(const XdgDesktopFile& desktopFile, QObject *parent): 41 | QAction(parent) 42 | { 43 | load(desktopFile); 44 | } 45 | 46 | 47 | XdgAction::XdgAction(const XdgDesktopFile* desktopFile, QObject *parent): 48 | QAction(parent) 49 | { 50 | load(*desktopFile); 51 | } 52 | 53 | 54 | XdgAction::XdgAction(const QString& desktopFileName, QObject *parent): 55 | QAction(parent) 56 | { 57 | XdgDesktopFile df; 58 | df.load(desktopFileName); 59 | load(df); 60 | } 61 | 62 | 63 | XdgAction::XdgAction(const XdgAction& other, QObject *parent): 64 | QAction(parent) 65 | { 66 | load(other.mDesktopFile); 67 | } 68 | 69 | 70 | XdgAction::~XdgAction() = default; 71 | 72 | 73 | XdgAction& XdgAction::operator=(const XdgAction& other) 74 | { 75 | load(other.mDesktopFile); 76 | return *this; 77 | } 78 | 79 | 80 | bool XdgAction::isValid() const 81 | { 82 | return mDesktopFile.isValid(); 83 | } 84 | 85 | 86 | void XdgAction::load(const XdgDesktopFile& desktopFile) 87 | { 88 | mDesktopFile = desktopFile; 89 | if (mDesktopFile.isValid()) 90 | { 91 | // & is reserved for mnemonics 92 | setText(mDesktopFile.name().replace(QLatin1Char('&'), QLatin1String("&&"))); 93 | setToolTip(mDesktopFile.comment()); 94 | 95 | connect(this, &XdgAction::triggered, this, &XdgAction::runConmmand); 96 | QMetaObject::invokeMethod(this, "updateIcon", Qt::QueuedConnection); 97 | } 98 | else 99 | { 100 | setText(QString()); 101 | setToolTip(QString()); 102 | setIcon(QIcon()); 103 | } 104 | } 105 | 106 | 107 | void XdgAction::runConmmand() const 108 | { 109 | if (mDesktopFile.isValid()) 110 | mDesktopFile.startDetached(); 111 | } 112 | 113 | 114 | void XdgAction::updateIcon() 115 | { 116 | if (icon().isNull()) 117 | { 118 | QIcon icon = mDesktopFile.icon().isNull() ? XdgIcon::fromTheme(QLatin1String("application-x-executable")) : mDesktopFile.icon(); 119 | 120 | // Some themes may lack the "application-x-executable" icon; checking null prevents 121 | // infinite recursion (setIcon->dataChanged->updateIcon->setIcon 122 | if (!icon.isNull()) 123 | setIcon(icon); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/qtxdg/xdgaction.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGACTION_H 29 | #define QTXDG_XDGACTION_H 30 | 31 | #include "xdgmacros.h" 32 | #include "xdgdesktopfile.h" 33 | 34 | #include 35 | #include 36 | 37 | 38 | /*******************************************************************/ /*! 39 | @brief The XdgAction class provides an QAction object based on XdgDesktopFile. 40 | 41 | The following properties of the action are set based on the desktopFile. 42 | Text - XdgDesktopFile localizeValue("Name") 43 | Icon - XdgDesktopFile icon() 44 | ToolTip - XdgDesktopFile localizeValue("Comment") 45 | 46 | Internally this function will create a copy of the desktopFile, so you 47 | can delete original XdgDesktopFile object. 48 | 49 | When an action is activated by the user; for example, when the user clicks 50 | a menu option, toolbar button or when trigger() was called, XdgAction start 51 | the application defined in XdgDesktopFile. @sa XdgDesktopFile::startDetached. 52 | ****************************************/ 53 | //******************************************************************* 54 | class QTXDG_API XdgAction : public QAction 55 | { 56 | Q_OBJECT 57 | public: 58 | explicit XdgAction(QObject *parent=nullptr); 59 | explicit XdgAction(const XdgDesktopFile& desktopFile, QObject *parent=nullptr); 60 | explicit XdgAction(const XdgDesktopFile* desktopFile, QObject *parent=nullptr); 61 | explicit XdgAction(const QString& desktopFileName, QObject *parent=nullptr); 62 | // Constructs a XdgAction that is a copy of the given XdgAction. 63 | explicit XdgAction(const XdgAction& other, QObject *parent=nullptr); 64 | 65 | /// Destroys the object and frees allocated resources. 66 | ~XdgAction() override; 67 | XdgAction& operator=(const XdgAction& other); 68 | 69 | //! Returns true if the XdgAction is valid; otherwise returns false. 70 | bool isValid() const; 71 | 72 | const XdgDesktopFile& desktopFile() const { return mDesktopFile; } 73 | 74 | public Q_SLOTS: 75 | void updateIcon(); 76 | 77 | private Q_SLOTS: 78 | void runConmmand() const; 79 | 80 | private: 81 | void load(const XdgDesktopFile& desktopFile); 82 | 83 | XdgDesktopFile mDesktopFile; 84 | }; 85 | 86 | #endif // QTXDG_XDGACTION_H 87 | -------------------------------------------------------------------------------- /src/qtxdg/xdgautostart.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2012 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgautostart.h" 29 | #include "xdgdirs.h" 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | /** 36 | * The Autostart Directories are $XDG_CONFIG_DIRS/autostart. If the same filename is 37 | * located under multiple Autostart Directories only the file under the most 38 | * important directory should be used. 39 | * 40 | * When multiple .desktop files with the same name exists in multiple directories 41 | * then only the Hidden key in the most important .desktop file must be considered: 42 | * If it is set to true all .desktop files with the same name in the other 43 | * directories MUST be ignored as well. 44 | */ 45 | 46 | XdgDesktopFileList XdgAutoStart::desktopFileList(bool excludeHidden) 47 | { 48 | QStringList dirs; 49 | dirs << XdgDirs::autostartHome(false) << XdgDirs::autostartDirs(); 50 | 51 | return desktopFileList(dirs, excludeHidden); 52 | } 53 | 54 | XdgDesktopFileList XdgAutoStart::desktopFileList(QStringList dirs, bool excludeHidden) 55 | { 56 | dirs.removeDuplicates(); 57 | 58 | QSet processed; 59 | XdgDesktopFileList ret; 60 | for (const QString &dirName : std::as_const(dirs)) 61 | { 62 | QDir dir(dirName); 63 | if (!dir.exists()) 64 | continue; 65 | 66 | const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files | QDir::Readable); 67 | for (const QFileInfo &fi : files) 68 | { 69 | if (processed.contains(fi.fileName())) 70 | continue; 71 | 72 | processed << fi.fileName(); 73 | 74 | XdgDesktopFile desktop; 75 | if (!desktop.load(fi.absoluteFilePath())) 76 | continue; 77 | 78 | if (!desktop.isSuitable(excludeHidden)) 79 | continue; 80 | 81 | ret << desktop; 82 | } 83 | } 84 | return ret; 85 | } 86 | 87 | 88 | QString XdgAutoStart::localPath(const XdgDesktopFile& file) 89 | { 90 | QFileInfo fi(file.fileName()); 91 | return QString::fromLatin1("%1/%2").arg(XdgDirs::autostartHome(), fi.fileName()); 92 | } 93 | -------------------------------------------------------------------------------- /src/qtxdg/xdgautostart.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2012 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGAUTOSTART_H 29 | #define QTXDG_XDGAUTOSTART_H 30 | 31 | #include "xdgmacros.h" 32 | #include "xdgdesktopfile.h" 33 | 34 | /*! @brief The XdgAutoStart class implements the "Desktop Application Autostart Specification" 35 | * from freedesktop.org. 36 | * This specification defines a method for automatically starting applications during the startup 37 | * of a desktop environment and after mounting a removable medium. 38 | * Now we impliment only startup. 39 | * 40 | * @sa http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html 41 | */ 42 | class QTXDG_API XdgAutoStart 43 | { 44 | public: 45 | /*! Returns a list of XdgDesktopFile objects for all the .desktop files in the Autostart directories 46 | When the .desktop file has the Hidden key set to true, the .desktop file must be ignored. But you 47 | can change this behavior by setting excludeHidden to false. */ 48 | static XdgDesktopFileList desktopFileList(bool excludeHidden=true); 49 | 50 | /*! Returns a list of XdgDesktopFile objects for .desktop files in the specified Autostart directories 51 | When the .desktop file has the Hidden key set to true, the .desktop file must be ignored. But you 52 | can change this behavior by setting excludeHidden to false. */ 53 | static XdgDesktopFileList desktopFileList(QStringList dirs, bool excludeHidden=true); 54 | 55 | /// For XdgDesktopFile returns the file path of the same name in users personal autostart directory. 56 | static QString localPath(const XdgDesktopFile& file); 57 | }; 58 | 59 | #endif // XDGAUTOSTART_H 60 | -------------------------------------------------------------------------------- /src/qtxdg/xdgdefaultapps.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2020 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "xdgdefaultapps.h" 22 | 23 | #include "xdgdesktopfile.h" 24 | #include "xdgdirs.h" 25 | #include "xdgmimeapps.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | 36 | static XdgDesktopFile *getTerminal(const QString &terminalName) 37 | { 38 | XdgDesktopFile *t = new XdgDesktopFile{}; 39 | if (t->load(terminalName) && t->isValid()) { 40 | const QStringList cats = t->value(QL1S("Categories"), QString()).toString().split(QL1C(';'), Qt::SkipEmptyParts); 41 | if (cats.contains(QL1S("TerminalEmulator"))) { 42 | if (t->contains(QL1S("TryExec"))) { 43 | if (t->tryExec()) { 44 | return t; 45 | } 46 | } else { 47 | return t; 48 | } 49 | } 50 | } 51 | 52 | delete t; 53 | return nullptr; 54 | } 55 | 56 | static QStringList getWebBrowserProtocolsGet() 57 | { 58 | // Protocols needed to quailify a application as the default browser 59 | static const QStringList webBrowserProtocolsGet = { 60 | QL1S("text/html"), 61 | QL1S("x-scheme-handler/http"), 62 | QL1S("x-scheme-handler/https") 63 | }; 64 | return webBrowserProtocolsGet; 65 | } 66 | 67 | static QStringList getWebBrowserProtocolsSet() 68 | { 69 | // When setting an application as the default browser xdg-settings also 70 | // sets these protocols. We simply follow it as good practice. 71 | static const QStringList webBrowserProtocolsSet { 72 | QL1S("x-scheme-handler/about"), 73 | QL1S("x-scheme-handler/unknown") 74 | }; 75 | return webBrowserProtocolsSet; 76 | } 77 | 78 | static QString qtxdgConfigFilename() 79 | { 80 | // first find the DE's qtxdg.conf file 81 | QByteArray qtxdgConfig("qtxdg"); 82 | QList desktopsList = qgetenv("XDG_CURRENT_DESKTOP").toLower().split(':'); 83 | if (!desktopsList.isEmpty() && !desktopsList.at(0).isEmpty()) { 84 | qtxdgConfig = desktopsList.at(0) + '-' + qtxdgConfig; 85 | } 86 | 87 | return QString::fromLocal8Bit(qtxdgConfig); 88 | } 89 | 90 | // returns the list of apps that are from category and support protocols 91 | static QList categoryAndMimeTypeApps(const QString &category, const QStringList &protocols) 92 | { 93 | XdgMimeApps db; 94 | QList apps = db.categoryApps(category); 95 | const QSet protocolsSet = QSet(protocols.begin(), protocols.end()); 96 | QList::iterator it = apps.begin(); 97 | while (it != apps.end()) { 98 | const auto list = (*it)->mimeTypes(); 99 | const QSet appSupportsSet = QSet(list.begin(), list.end()); 100 | if (appSupportsSet.contains(protocolsSet) && (*it)->isShown()) { 101 | ++it; 102 | } else { 103 | delete *it; 104 | it = apps.erase(it); 105 | } 106 | } 107 | return apps; 108 | } 109 | 110 | static XdgDesktopFile *defaultApp(const QString &protocol) 111 | { 112 | XdgMimeApps db; 113 | XdgDesktopFile *app = db.defaultApp(protocol); 114 | if (app && app->isValid()) { 115 | return app; 116 | } else { 117 | delete app; // it's fine to delete a nullptr 118 | return nullptr; 119 | } 120 | } 121 | 122 | static bool setDefaultApp(const QString &protocol, const XdgDesktopFile &app) 123 | { 124 | XdgMimeApps db; 125 | return db.setDefaultApp(protocol, app); 126 | } 127 | 128 | XdgDesktopFile *XdgDefaultApps::emailClient() 129 | { 130 | return defaultApp(QL1S("x-scheme-handler/mailto")); 131 | } 132 | 133 | QList XdgDefaultApps::emailClients() 134 | { 135 | return categoryAndMimeTypeApps(QSL("Email"), QStringList() << QL1S("x-scheme-handler/mailto")); 136 | } 137 | 138 | XdgDesktopFile *XdgDefaultApps::fileManager() 139 | { 140 | return defaultApp(QL1S("inode/directory")); 141 | } 142 | 143 | QList XdgDefaultApps::fileManagers() 144 | { 145 | return categoryAndMimeTypeApps(QSL("FileManager"), QStringList() << QL1S("inode/directory")); 146 | } 147 | 148 | bool XdgDefaultApps::setEmailClient(const XdgDesktopFile &app) 149 | { 150 | return setDefaultApp(QL1S("x-scheme-handler/mailto"), app); 151 | } 152 | 153 | bool XdgDefaultApps::setFileManager(const XdgDesktopFile &app) 154 | { 155 | return setDefaultApp(QL1S("inode/directory"), app); 156 | } 157 | 158 | bool XdgDefaultApps::setTerminal(const XdgDesktopFile &app) 159 | { 160 | if (!app.isValid()) 161 | return false; 162 | 163 | const QString configFile = qtxdgConfigFilename(); 164 | QSettings settings(QSettings::UserScope, configFile); 165 | settings.setValue(QL1S("TerminalEmulator"), XdgDesktopFile::id(app.fileName())); 166 | return true; 167 | } 168 | 169 | bool XdgDefaultApps::setWebBrowser(const XdgDesktopFile &app) 170 | { 171 | const QStringList protocols = 172 | QStringList() << getWebBrowserProtocolsGet() << getWebBrowserProtocolsSet(); 173 | 174 | for (const QString &protocol : protocols) { 175 | if (!setDefaultApp(protocol, app)) 176 | return false; 177 | } 178 | return true; 179 | } 180 | 181 | XdgDesktopFile *XdgDefaultApps::terminal() 182 | { 183 | const QString configFile = qtxdgConfigFilename(); 184 | QSettings settings(QSettings::UserScope, configFile); 185 | const QString terminalName = settings.value(QL1S("TerminalEmulator"), QString()).toString(); 186 | return getTerminal(terminalName); 187 | } 188 | 189 | QList XdgDefaultApps::terminals() 190 | { 191 | XdgMimeApps db; 192 | QList terminalList = db.categoryApps(QL1S("TerminalEmulator")); 193 | QList::iterator it = terminalList.begin(); 194 | while (it != terminalList.end()) { 195 | if ((*it)->isShown()) { 196 | ++it; 197 | } else { 198 | delete *it; 199 | it = terminalList.erase(it); 200 | } 201 | } 202 | return terminalList; 203 | } 204 | 205 | // To be qualified as the default browser all protocols must be set to the same 206 | // valid application 207 | XdgDesktopFile *XdgDefaultApps::webBrowser() 208 | { 209 | const QStringList webBrowserProtocolsGet = getWebBrowserProtocolsGet(); 210 | std::vector> apps; 211 | for (int i = 0; i < webBrowserProtocolsGet.count(); ++i) { 212 | auto a = std::unique_ptr(defaultApp(webBrowserProtocolsGet.at(i))); 213 | apps.push_back(std::move(a)); 214 | if (apps.at(i) && apps.at(i)->isValid()) 215 | continue; 216 | else 217 | return nullptr; 218 | } 219 | 220 | // At this point all apps are non null and valid 221 | for (int i = 1; i < webBrowserProtocolsGet.count(); ++i) { 222 | if (*apps.at(i - 1) != *apps.at(i)) 223 | return nullptr; 224 | } 225 | return new XdgDesktopFile(*apps.at(0).get()); 226 | } 227 | 228 | QList XdgDefaultApps::webBrowsers() 229 | { 230 | return categoryAndMimeTypeApps(QSL("WebBrowser"), getWebBrowserProtocolsGet()); 231 | } 232 | -------------------------------------------------------------------------------- /src/qtxdg/xdgdefaultapps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2020 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef XDGDEFAULTAPPS_H 22 | #define XDGDEFAULTAPPS_H 23 | 24 | #include "xdgmacros.h" 25 | 26 | class XdgDesktopFile; 27 | 28 | /*! 29 | * \brief Sets the default app for special case applications categories(web browser, etc) 30 | */ 31 | class QTXDG_API XdgDefaultApps { 32 | 33 | public: 34 | /*! 35 | * \brief Sets the default email client 36 | * \return The default email client. nullptr if it's not set or a error ocurred. 37 | */ 38 | static XdgDesktopFile *emailClient(); 39 | 40 | /*! 41 | * \brief Gets the installed email clients 42 | * \return A list of installed email clients 43 | */ 44 | static QList emailClients(); 45 | 46 | /*! 47 | * \brief Sets the default file manager 48 | * \return The default file manager. nullptr if it's not set or a error ocurred. 49 | */ 50 | static XdgDesktopFile *fileManager(); 51 | 52 | /*! 53 | * \brief Gets the installed file managers 54 | * \return A list of installed file managers 55 | */ 56 | static QList fileManagers(); 57 | 58 | /*! 59 | * \brief Sets the default email client 60 | * \param The app to be set as the default email client 61 | * \return True if successful, false otherwise 62 | */ 63 | static bool setEmailClient(const XdgDesktopFile &app); 64 | 65 | /*! 66 | * \brief Sets the default file manager 67 | * \param The app to be set as the default file manager 68 | * \return True if successful, false otherwise 69 | */ 70 | static bool setFileManager(const XdgDesktopFile &app); 71 | 72 | /*! 73 | * \brief Sets the default terminal emulator 74 | * \param The app to be set as the default terminal emulator 75 | * \return True if successful, false otherwise 76 | */ 77 | static bool setTerminal(const XdgDesktopFile &app); 78 | 79 | /*! 80 | * \brief Sets the default web browser 81 | * \param The app to be set as the default web browser 82 | * \return True if successful, false otherwise 83 | */ 84 | static bool setWebBrowser(const XdgDesktopFile &app); 85 | 86 | /*! 87 | * \brief Gets the default terminal emulator 88 | * \return The default terminal emulator. nullptr if it's not set or an error ocurred. 89 | */ 90 | static XdgDesktopFile *terminal(); 91 | 92 | /*! 93 | * \brief Gets the installed terminal emulators 94 | * \return A list of installed terminal emulators 95 | */ 96 | static QList terminals(); 97 | 98 | /*! 99 | * \brief Gets the default web browser 100 | * \return The default web browser. nullptr if it's not set or a error ocurred. 101 | */ 102 | static XdgDesktopFile *webBrowser(); 103 | 104 | /*! 105 | * \brief Gets the installed web browsers 106 | * \return A list of installed web browsers 107 | */ 108 | static QList webBrowsers(); 109 | }; 110 | 111 | #endif // XDGDEFAULTAPPS_H 112 | -------------------------------------------------------------------------------- /src/qtxdg/xdgdesktopfile.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGDESKTOPFILE_H 29 | #define QTXDG_XDGDESKTOPFILE_H 30 | 31 | #include "xdgmacros.h" 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | class XdgDesktopFileData; 41 | 42 | /** 43 | \brief Desktop files handling. 44 | XdgDesktopFile class gives the interface for reading the values from the XDG .desktop file. 45 | The interface of this class is similar on QSettings. XdgDesktopFile objects can be passed 46 | around by value since the XdgDesktopFile class uses implicit data sharing. 47 | 48 | The Desktop Entry Specification defines 3 types of desktop entries: Application, Link and 49 | Directory. The format of .desktop file is described on 50 | http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html 51 | 52 | Note that not all methods in this class make sense for all types of desktop files. 53 | \author Alexander Sokoloff 54 | */ 55 | 56 | class QTXDG_API XdgDesktopFile 57 | { 58 | public: 59 | /*! The Desktop Entry Specification defines 3 types of desktop entries: Application, Link and 60 | Directory. File type is determined by the "Type" tag. */ 61 | enum Type 62 | { 63 | UnknownType, //! Unknown desktop file type. Maybe is invalid. 64 | ApplicationType, //! The file describes application. 65 | LinkType, //! The file describes URL. 66 | DirectoryType //! The file describes directory settings. 67 | }; 68 | 69 | //! Constructs an empty XdgDesktopFile 70 | XdgDesktopFile(); 71 | 72 | /*! Constructs a copy of other. 73 | This operation takes constant time, because XdgDesktopFile is implicitly shared. This makes 74 | returning a XdgDesktopFile from a function very fast. If a shared instance is modified, 75 | it will be copied (copy-on-write), and that takes linear time. */ 76 | XdgDesktopFile(const XdgDesktopFile& other); 77 | 78 | /*! Constructs a new basic DesktopFile. If type is: 79 | - ApplicationType, "value" should be the Exec value; 80 | - LinkType, "value" should be the URL; 81 | - DirectoryType, "value" should be omitted */ 82 | XdgDesktopFile(XdgDesktopFile::Type type, const QString& name, const QString& value = QString()); 83 | 84 | //! Destroys the object. 85 | virtual ~XdgDesktopFile(); 86 | 87 | //! Assigns other to this DesktopFile and returns a reference to this DesktopFile. 88 | XdgDesktopFile& operator=(const XdgDesktopFile& other); 89 | 90 | //! Returns true if both files contain the identical key-value pairs 91 | bool operator==(const XdgDesktopFile &other) const; 92 | 93 | //! Returns false if both files contain the identical key-value pairs 94 | inline bool operator!=(const XdgDesktopFile &other) const 95 | { 96 | return !operator==(other); 97 | } 98 | 99 | //! Loads an DesktopFile from the file with the given fileName. 100 | virtual bool load(const QString& fileName); 101 | 102 | //! Saves the DesktopFile to the file with the given fileName. Returns true if successful; otherwise returns false. 103 | virtual bool save(const QString &fileName) const; 104 | 105 | /*! This is an overloaded function. 106 | This function writes a DesktopFile to the given device. */ 107 | virtual bool save(QIODevice *device) const; 108 | 109 | /*! Returns the value for key. If the key doesn't exist, returns defaultValue. 110 | If no default value is specified, a default QVariant is returned. */ 111 | QVariant value(const QString& key, const QVariant& defaultValue = QVariant()) const; 112 | 113 | /*! Returns the localized value for key. In the desktop file keys may be postfixed by [LOCALE]. If the 114 | localized value doesn't exist, returns non lokalized value. If non localized value doesn't exist, returns defaultValue. 115 | LOCALE must be of the form lang_COUNTRY.ENCODING@MODIFIER, where _COUNTRY, .ENCODING, and @MODIFIER may be omitted. 116 | 117 | If no default value is specified, a default QVariant is returned. */ 118 | QVariant localizedValue(const QString& key, const QVariant& defaultValue = QVariant()) const; 119 | 120 | //! Sets the value of setting key to value. If the key already exists, the previous value is overwritten. 121 | void setValue(const QString &key, const QVariant &value); 122 | 123 | /*! Sets the value of setting key to value. If a localized version of the key already exists, the previous value is 124 | overwritten. Otherwise, it overwrites the the un-localized version. */ 125 | void setLocalizedValue(const QString &key, const QVariant &value); 126 | 127 | //! Removes the entry with the specified key, if it exists. 128 | void removeEntry(const QString& key); 129 | 130 | //! Returns the entry Categories. It supports X-Categories extensions. 131 | QStringList categories() const; 132 | 133 | //! Returns list of values in entry Actions. 134 | QStringList actions() const; 135 | 136 | //! Returns true if there exists a setting called key; returns false otherwise. 137 | bool contains(const QString& key) const; 138 | 139 | //! Returns true if the XdgDesktopFile is valid; otherwise returns false. 140 | bool isValid() const; 141 | 142 | /*! Returns the file name of the desktop file. 143 | * Returns QString() if the file wasn't found when load was called. */ 144 | QString fileName() const; 145 | 146 | //! Returns an icon specified in this file. 147 | QIcon const icon(const QIcon& fallback = QIcon()) const; 148 | //! Returns an icon for application action \param action. 149 | QIcon const actionIcon(const QString & action, const QIcon& fallback = QIcon()) const; 150 | 151 | //! Returns an icon name specified in this file. 152 | QString const iconName() const; 153 | //! Returns an icon name for application action \param action. 154 | QString const actionIconName(const QString & action) const; 155 | 156 | //! Returns an list of mimetypes specified in this file. 157 | /*! @return Returns a list of the "MimeType=" entries. 158 | * If the file doens't contain the MimeType entry, an empty QStringList is 159 | * returned. Empty values are removed from the returned list. 160 | */ 161 | QStringList mimeTypes() const; 162 | 163 | //! This function is provided for convenience. It's equivalent to calling localizedValue("Name").toString(). 164 | QString name() const { return localizedValue(QLatin1String("Name")).toString(); } 165 | //! Returns an (localized) name for application action \param action. 166 | QString actionName(const QString & action) const; 167 | 168 | //! This function is provided for convenience. It's equivalent to calling localizedValue("Comment").toString(). 169 | QString comment() const { return localizedValue(QLatin1String("Comment")).toString(); } 170 | 171 | /*! Returns the desktop file type. 172 | @see XdgDesktopFile::Type */ 173 | Type type() const; 174 | 175 | /*! For file with Application type. Starts the program with the optional urls in a new process, and detaches from it. 176 | Returns true on success; otherwise returns false. 177 | @par urls - A list of files or URLS. Each file is passed as a separate argument to the executable program. 178 | 179 | For file with Link type. Opens URL in the associated application. Parametr urls is not used. 180 | 181 | For file with Directory type, do nothing. */ 182 | bool startDetached(const QStringList& urls) const; 183 | 184 | //! This function is provided for convenience. It's equivalent to calling startDetached(QStringList(url)). 185 | bool startDetached(const QString& url = QString()) const; 186 | 187 | /*! For file with Application type. Activates action defined by the \param action. Action is activated 188 | * either with the [Desktop Action %s]/Exec or by the D-Bus if the [Desktop Entry]/DBusActivatable is set. 189 | * \note Starting is done the same way as \sa startDetached() 190 | * 191 | * \return true on success; otherwise returns false. 192 | * \param urls - A list of files or URLS. Each file is passed as a separate argument to the executable program. 193 | * 194 | * For file with Link type, do nothing. 195 | * 196 | * For file with Directory type, do nothing. 197 | */ 198 | bool actionActivate(const QString & action, const QStringList & urls) const; 199 | 200 | /*! A Exec value consists of an executable program optionally followed by one or more arguments. 201 | This function expands this arguments and returns command line string parts. 202 | Note this method make sense only for Application type. 203 | @par urls - A list of files or URLS. Each file is passed as a separate argument to the result string program.*/ 204 | QStringList expandExecString(const QStringList& urls = QStringList()) const; 205 | 206 | /*! Returns the URL for the Link desktop file; otherwise an empty string is returned. */ 207 | QString url() const; 208 | 209 | /*! Computes the desktop file ID. It is the identifier of an installed 210 | * desktop entry file. 211 | * @par fileName - The desktop file complete name. 212 | * @par checkFileExists If true and the file doesn't exist the computed ID 213 | * will be an empty QString(). Defaults to true. 214 | * @return The computed ID. Returns an empty QString() if it's impossible to 215 | * compute the ID. Reference: 216 | * https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id 217 | */ 218 | static QString id(const QString &fileName, bool checkFileExists = true); 219 | 220 | /*! The desktop entry specification defines a number of fields to control 221 | the visibility of the application menu. Thisfunction checks whether 222 | to display a this application or not. 223 | @par environment - User supplied desktop environment name. If not 224 | supplied the desktop will be detected reading the 225 | XDG_CURRENT_DESKTOP environment variable. If not set, "UNKNOWN" 226 | will be used as the desktop name. All operations envolving the 227 | desktop environment name are case insensitive. 228 | */ 229 | bool isShown(const QString &environment = QString()) const; 230 | 231 | /*! This fuction returns true if the desktop file is applicable to the 232 | current environment. 233 | @par excludeHidden - if set to true (default), files with 234 | "Hidden=true" will be considered "not applicable". Setting this 235 | to false is be useful when the user wants to enable/disable items 236 | and wants to see those that are Hidden 237 | @par environment - User supplied desktop environment name. If not 238 | supplied the desktop will be detected reading the 239 | XDG_CURRENT_DESKTOP environment variable. If not set, "UNKNOWN" 240 | will be used as the desktop name. All operations envolving the 241 | desktop environment name are case insensitive. 242 | */ 243 | bool isSuitable(bool excludeHidden = true, const QString &environment = QString()) const; 244 | 245 | /*! Check if the executable file on disk used to determine if the program 246 | is actually installed. If the path is not an absolute path, the file 247 | is looked up in the $PATH environment variable. 248 | Check TryExec entry existence with contains(). 249 | @return false if the file is not present or if it is not executable. 250 | If the TryExec entry isn't present returns false 251 | */ 252 | bool tryExec() const; 253 | 254 | protected: 255 | virtual QString prefix() const { return QLatin1String("Desktop Entry"); } 256 | virtual bool check() const { return true; } 257 | private: 258 | /*! Returns the localized version of the key if the Desktop File already contains a localized version of it. 259 | If not, returns the same key back */ 260 | QString localizedKey(const QString& key) const; 261 | 262 | QSharedDataPointer d; 263 | }; 264 | 265 | 266 | /// Synonym for QList 267 | typedef QList XdgDesktopFileList; 268 | 269 | #endif // QTXDG_XDGDESKTOPFILE_H 270 | -------------------------------------------------------------------------------- /src/qtxdg/xdgdesktopfile_p.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2015 LXQt team 8 | * Authors: 9 | * Luís Pereira 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef XDGDESKTOPFILE_P_H 29 | #define XDGDESKTOPFILE_P_H 30 | 31 | QTXDG_AUTOTEST bool readDesktopFile(QIODevice & device, QSettings::SettingsMap & map); 32 | QTXDG_AUTOTEST bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map); 33 | 34 | #endif // XDGDESKTOPFILE_P_H 35 | -------------------------------------------------------------------------------- /src/qtxdg/xdgdirs.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | // clazy:excludeall=non-pod-global-static 29 | 30 | #include "xdgdirs.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | static const QString userDirectoryString[8] = 38 | { 39 | QLatin1String("Desktop"), 40 | QLatin1String("Download"), 41 | QLatin1String("Templates"), 42 | QLatin1String("Publicshare"), 43 | QLatin1String("Documents"), 44 | QLatin1String("Music"), 45 | QLatin1String("Pictures"), 46 | QLatin1String("Videos") 47 | }; 48 | 49 | // Helper functions prototypes 50 | void fixBashShortcuts(QString &s); 51 | void removeEndingSlash(QString &s); 52 | QString createDirectory(const QString &dir); 53 | 54 | void cleanAndAddPostfix(QStringList &dirs, const QString& postfix); 55 | QString userDirFallback(XdgDirs::UserDirectory dir); 56 | 57 | /************************************************ 58 | Helper func. 59 | ************************************************/ 60 | void fixBashShortcuts(QString &s) 61 | { 62 | if (s.startsWith(QLatin1Char('~'))) 63 | s = QFile::decodeName(qgetenv("HOME")) + (s).mid(1); 64 | } 65 | 66 | 67 | void removeEndingSlash(QString &s) 68 | { 69 | // We don't check for empty strings. Caller must check it. 70 | 71 | // Remove the ending slash, except for root dirs. 72 | if (s.length() > 1 && s.endsWith(QLatin1Char('/'))) 73 | s.chop(1); 74 | } 75 | 76 | 77 | QString createDirectory(const QString &dir) 78 | { 79 | QDir d(dir); 80 | if (!d.exists()) 81 | { 82 | if (!d.mkpath(QLatin1String("."))) 83 | { 84 | qWarning() << QString::fromLatin1("Can't create %1 directory.").arg(d.absolutePath()); 85 | } 86 | } 87 | QString r = d.absolutePath(); 88 | removeEndingSlash(r); 89 | return r; 90 | } 91 | 92 | 93 | void cleanAndAddPostfix(QStringList &dirs, const QString& postfix) 94 | { 95 | const int N = dirs.count(); 96 | for(int i = 0; i < N; ++i) 97 | { 98 | fixBashShortcuts(dirs[i]); 99 | removeEndingSlash(dirs[i]); 100 | dirs[i].append(postfix); 101 | } 102 | } 103 | 104 | 105 | QString userDirFallback(XdgDirs::UserDirectory dir) 106 | { 107 | QString fallback; 108 | const QString home = QFile::decodeName(qgetenv("HOME")); 109 | 110 | if (home.isEmpty()) 111 | return QString::fromLatin1("/tmp"); 112 | else if (dir == XdgDirs::Desktop) 113 | fallback = QString::fromLatin1("%1/%2").arg(home, QLatin1String("Desktop")); 114 | else 115 | fallback = home; 116 | 117 | return fallback; 118 | } 119 | 120 | 121 | QString XdgDirs::userDirDefault(XdgDirs::UserDirectory dir) 122 | { 123 | // possible values for UserDirectory 124 | Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos)); 125 | if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos) 126 | return QString(); 127 | 128 | return userDirFallback(dir); 129 | } 130 | 131 | 132 | QString XdgDirs::userDir(XdgDirs::UserDirectory dir) 133 | { 134 | // possible values for UserDirectory 135 | Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos)); 136 | if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos) 137 | return QString(); 138 | 139 | QString folderName = userDirectoryString[dir]; 140 | 141 | const QString fallback = userDirFallback(dir); 142 | 143 | QString configDir(configHome()); 144 | QFile configFile(configDir + QLatin1String("/user-dirs.dirs")); 145 | if (!configFile.exists()) 146 | return fallback; 147 | 148 | if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) 149 | return fallback; 150 | 151 | QString userDirVar(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR")); 152 | QTextStream in(&configFile); 153 | QString line; 154 | while (!in.atEnd()) 155 | { 156 | line = in.readLine(); 157 | if (line.contains(userDirVar)) 158 | { 159 | configFile.close(); 160 | 161 | // get path between quotes 162 | line = line.section(QLatin1Char('"'), 1, 1); 163 | if (line.isEmpty()) 164 | return fallback; 165 | line.replace(QLatin1String("$HOME"), QLatin1String("~")); 166 | fixBashShortcuts(line); 167 | return line; 168 | } 169 | } 170 | 171 | configFile.close(); 172 | return fallback; 173 | } 174 | 175 | 176 | bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool createDir) 177 | { 178 | // possible values for UserDirectory 179 | Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos)); 180 | if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos) 181 | return false; 182 | 183 | const QString home = QFile::decodeName(qgetenv("HOME")); 184 | if (!(value.startsWith(QLatin1String("$HOME")) 185 | || value.startsWith(QLatin1String("~/")) 186 | || value.startsWith(home) 187 | || value.startsWith(QDir(home).canonicalPath()))) 188 | return false; 189 | 190 | QString folderName = userDirectoryString[dir]; 191 | 192 | QString configDir(configHome()); 193 | QFile configFile(configDir + QLatin1String("/user-dirs.dirs")); 194 | 195 | // create the file if doesn't exist and opens it 196 | if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text)) 197 | return false; 198 | 199 | QTextStream stream(&configFile); 200 | QVector lines; 201 | QString line; 202 | bool foundVar = false; 203 | while (!stream.atEnd()) 204 | { 205 | line = stream.readLine(); 206 | if (line.indexOf(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR")) == 0) 207 | { 208 | foundVar = true; 209 | QString path = line.section(QLatin1Char('"'), 1, 1); 210 | line.replace(path, value); 211 | lines.append(line); 212 | } 213 | else if (line.indexOf(QLatin1String("XDG_")) == 0) 214 | { 215 | lines.append(line); 216 | } 217 | } 218 | 219 | stream.reset(); 220 | configFile.resize(0); 221 | if (!foundVar) 222 | stream << QString::fromLatin1("XDG_%1_DIR=\"%2\"\n").arg(folderName.toUpper(),(value)); 223 | 224 | for (QVector::iterator i = lines.begin(); i != lines.end(); ++i) 225 | stream << *i << QLatin1Char('\n'); 226 | 227 | configFile.close(); 228 | 229 | if (createDir) { 230 | QString path = QString(value).replace(QLatin1String("$HOME"), QLatin1String("~")); 231 | fixBashShortcuts(path); 232 | QDir().mkpath(path); 233 | } 234 | 235 | return true; 236 | } 237 | 238 | 239 | QString XdgDirs::dataHome(bool createDir) 240 | { 241 | QString s = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); 242 | fixBashShortcuts(s); 243 | if (createDir) 244 | return createDirectory(s); 245 | 246 | removeEndingSlash(s); 247 | return s; 248 | } 249 | 250 | 251 | QString XdgDirs::configHome(bool createDir) 252 | { 253 | QString s = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 254 | fixBashShortcuts(s); 255 | if (createDir) 256 | return createDirectory(s); 257 | 258 | removeEndingSlash(s); 259 | return s; 260 | } 261 | 262 | 263 | QStringList XdgDirs::dataDirs(const QString &postfix) 264 | { 265 | QString d = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); 266 | QStringList dirs = d.split(QLatin1Char(':'), Qt::SkipEmptyParts); 267 | 268 | if (dirs.isEmpty()) { 269 | dirs.append(QString::fromLatin1("/usr/local/share")); 270 | dirs.append(QString::fromLatin1("/usr/share")); 271 | } else { 272 | QMutableListIterator it(dirs); 273 | while (it.hasNext()) { 274 | const QString dir = it.next(); 275 | if (!dir.startsWith(QLatin1Char('/'))) 276 | it.remove(); 277 | } 278 | } 279 | 280 | dirs.removeDuplicates(); 281 | cleanAndAddPostfix(dirs, postfix); 282 | return dirs; 283 | 284 | } 285 | 286 | 287 | QStringList XdgDirs::configDirs(const QString &postfix) 288 | { 289 | QStringList dirs; 290 | const QString env = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS")); 291 | if (env.isEmpty()) 292 | dirs.append(QString::fromLatin1("/etc/xdg")); 293 | else 294 | dirs = env.split(QLatin1Char(':'), Qt::SkipEmptyParts); 295 | 296 | cleanAndAddPostfix(dirs, postfix); 297 | return dirs; 298 | } 299 | 300 | 301 | QString XdgDirs::cacheHome(bool createDir) 302 | { 303 | QString s = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); 304 | fixBashShortcuts(s); 305 | if (createDir) 306 | return createDirectory(s); 307 | 308 | removeEndingSlash(s); 309 | return s; 310 | } 311 | 312 | 313 | QString XdgDirs::runtimeDir() 314 | { 315 | QString result = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); 316 | fixBashShortcuts(result); 317 | removeEndingSlash(result); 318 | return result; 319 | } 320 | 321 | 322 | QString XdgDirs::autostartHome(bool createDir) 323 | { 324 | QString s = QString::fromLatin1("%1/autostart").arg(configHome(createDir)); 325 | fixBashShortcuts(s); 326 | 327 | if (createDir) 328 | return createDirectory(s); 329 | 330 | QDir d(s); 331 | QString r = d.absolutePath(); 332 | removeEndingSlash(r); 333 | return r; 334 | } 335 | 336 | 337 | QStringList XdgDirs::autostartDirs(const QString &postfix) 338 | { 339 | QStringList dirs; 340 | const QStringList s = configDirs(); 341 | for (const QString &dir : s) 342 | dirs << QString::fromLatin1("%1/autostart").arg(dir) + postfix; 343 | 344 | return dirs; 345 | } 346 | -------------------------------------------------------------------------------- /src/qtxdg/xdgdirs.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGDIRS_H 29 | #define QTXDG_XDGDIRS_H 30 | 31 | #include "xdgmacros.h" 32 | #include 33 | #include 34 | 35 | /*! @brief The XdgMenu class implements the "XDG Base Directory Specification" from freedesktop.org. 36 | * This specification defines where these files should be looked for by defining one or more base 37 | * directories relative to which files should be located. 38 | * 39 | * All postfix parameters should start with an '/' slash. 40 | * 41 | * @sa http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 42 | */ 43 | 44 | class QTXDG_API XdgDirs 45 | { 46 | public: 47 | enum UserDirectory 48 | { 49 | Desktop, 50 | Download, 51 | Templates, 52 | PublicShare, 53 | Documents, 54 | Music, 55 | Pictures, 56 | Videos 57 | }; 58 | 59 | /*! @brief Returns the path to the user folder passed as parameter dir defined in 60 | * $XDG_CONFIG_HOME/user-dirs.dirs. Returns /tmp if no $HOME defined, $HOME/Desktop if 61 | * dir equals XdgDirs::Desktop or $HOME othewise. 62 | */ 63 | static QString userDir(UserDirectory dir); 64 | 65 | 66 | /*! @brief Returns the default path to the user specified directory. 67 | * Returns /tmp if no $HOME defined, $HOME/Desktop if dir equals 68 | * XdgDirs::Desktop or $HOME othewise. If dir value is invalid, an empty 69 | * QString is returned. 70 | */ 71 | static QString userDirDefault(UserDirectory dir); 72 | 73 | /*! @brief Returns true if writing into configuration file $XDG_CONFIG_HOME/user-dirs.dirs 74 | * the path in value for the directory in dir is succesfull. Returns false otherwise. If 75 | * createDir is true, dir will be created if it doesn't exist. 76 | */ 77 | static bool setUserDir(UserDirectory dir, const QString &value, bool createDir); 78 | 79 | /*! @brief Returns the path to the directory that corresponds to the $XDG_DATA_HOME. 80 | * If @i createDir is true, the function will create the directory. 81 | * 82 | * $XDG_DATA_HOME defines the base directory relative to which user specific data files 83 | * should be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to 84 | * $HOME/.local/share should be used. 85 | */ 86 | static QString dataHome(bool createDir=true); 87 | 88 | 89 | /*! @brief Returns the path to the directory that corresponds to the $XDG_CONFIG_HOME. 90 | * If @i createDir is true, the function will create the directory. 91 | * 92 | * $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration 93 | * files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal 94 | * to $HOME/.config should be used. 95 | */ 96 | static QString configHome(bool createDir=true); 97 | 98 | 99 | /*! @brief Returns a list of all directories that corresponds to the $XDG_DATA_DIRS. 100 | * $XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data 101 | * files in addition to the $XDG_DATA_HOME base directory. If $XDG_DATA_DIRS is either not set 102 | * or empty, a value equal to /usr/local/share:/usr/share is used. 103 | * 104 | * If the postfix is not empty it will append to end of each returned directory. 105 | */ 106 | static QStringList dataDirs(const QString &postfix = QString()); 107 | 108 | 109 | /*! @brief Returns a list of all directories that corresponds to the $XDG_CONFIG_DIRS. 110 | * $XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for 111 | * configuration files in addition to the $XDG_CONFIG_HOME base directory. If $XDG_CONFIG_DIRS 112 | * is either not set or empty, a value equal to /etc/xdg should be used. 113 | * 114 | * If the postfix is not empty it will append to end of each returned directory. 115 | */ 116 | static QStringList configDirs(const QString &postfix = QString()); 117 | 118 | 119 | /*! @brief Returns the path to the directory that corresponds to the $XDG_CACHE_HOME. 120 | * If @i createDir is true, the function will create the directory. 121 | * 122 | * $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential 123 | * data files should be stored. If $XDG_CACHE_HOME is either not set or empty, 124 | * a default equal to $HOME/.cache should be used. 125 | */ 126 | static QString cacheHome(bool createDir=true); 127 | 128 | 129 | /*! @brief Returns the path to the directory that corresponds to the $XDG_RUNTIME_DIR. 130 | * $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential 131 | * runtime files and other file objects (such as sockets, named pipes, ...) should be stored. 132 | * The directory MUST be owned by the user, and he MUST be the only one having read and write 133 | * access to it. Its Unix access mode MUST be 0700. 134 | */ 135 | static QString runtimeDir(); 136 | 137 | /*! @brief Returns the path to the directory that corresponds to the $XDG_CONFIG_HOME/autostart 138 | * 139 | * If $XDG_CONFIG_HOME is not set, the Autostart Directory in the user's home directory is 140 | * ~/.config/autostart/ 141 | */ 142 | static QString autostartHome(bool createDir=true); 143 | 144 | /*! @brief Returns a list of all directories that correspond to $XDG_CONFIG_DIRS/autostart 145 | * If $XDG_CONFIG_DIRS is not set, the system wide Autostart Directory is /etc/xdg/autostart 146 | * 147 | * If the postfix is not empty it will append to end of each returned directory. 148 | * 149 | * Note: this does not include the user's autostart directory 150 | * @sa autostartHome() 151 | */ 152 | static QStringList autostartDirs(const QString &postfix = QString()); 153 | }; 154 | 155 | #endif // QTXDG_XDGDIRS_H 156 | -------------------------------------------------------------------------------- /src/qtxdg/xdgicon.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgicon.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "../xdgiconloader/xdgiconloader_p.h" 37 | #include 38 | 39 | static const QLatin1String DEFAULT_APP_ICON("application-x-executable"); 40 | 41 | static void qt_cleanup_icon_cache(); 42 | typedef QCache IconCache; 43 | 44 | namespace { 45 | struct QtIconCache: public IconCache 46 | { 47 | QtIconCache() 48 | { 49 | qAddPostRoutine(qt_cleanup_icon_cache); 50 | } 51 | }; 52 | } 53 | Q_GLOBAL_STATIC(IconCache, qtIconCache) 54 | 55 | static void qt_cleanup_icon_cache() 56 | { 57 | qtIconCache()->clear(); 58 | } 59 | 60 | 61 | XdgIcon::XdgIcon() = default; 62 | 63 | 64 | XdgIcon::~XdgIcon() = default; 65 | 66 | 67 | /************************************************ 68 | Returns the QIcon corresponding to name in the current icon theme. If no such icon 69 | is found in the current theme fallback is return instead. 70 | ************************************************/ 71 | QIcon XdgIcon::fromTheme(const QString& iconName, const QIcon& fallback) 72 | { 73 | if (iconName.isEmpty()) 74 | return fallback; 75 | 76 | bool isAbsolute = (iconName[0] == QLatin1Char('/')); 77 | 78 | QString name = QFileInfo(iconName).fileName(); 79 | if (name.endsWith(QLatin1String(".png"), Qt::CaseInsensitive) || 80 | name.endsWith(QLatin1String(".svg"), Qt::CaseInsensitive) || 81 | name.endsWith(QLatin1String(".xpm"), Qt::CaseInsensitive)) 82 | { 83 | name.truncate(name.length() - 4); 84 | } 85 | 86 | QIcon icon; 87 | 88 | if (!isAbsolute ? qtIconCache()->contains(name) : qtIconCache()->contains(iconName)) { 89 | icon = *qtIconCache()->object(!isAbsolute ? name : iconName); 90 | } else { 91 | QIcon *cachedIcon; 92 | if (!isAbsolute) { 93 | cachedIcon = new QIcon(new XdgIconLoaderEngine(name)); 94 | qtIconCache()->insert(name, cachedIcon); 95 | } else { 96 | cachedIcon = new QIcon(iconName); 97 | qtIconCache()->insert(iconName, cachedIcon); 98 | } 99 | icon = *cachedIcon; 100 | } 101 | 102 | // Note the qapp check is to allow lazy loading of static icons 103 | // Supporting fallbacks will not work for this case. 104 | if (qApp && !isAbsolute && icon.availableSizes().isEmpty()) 105 | { 106 | return fallback; 107 | } 108 | return icon; 109 | } 110 | 111 | 112 | /************************************************ 113 | Returns the QIcon corresponding to names in the current icon theme. If no such icon 114 | is found in the current theme fallback is return instead. 115 | ************************************************/ 116 | QIcon XdgIcon::fromTheme(const QStringList& iconNames, const QIcon& fallback) 117 | { 118 | for (const QString &iconName : iconNames) 119 | { 120 | QIcon icon = fromTheme(iconName); 121 | if (!icon.isNull()) 122 | return icon; 123 | } 124 | 125 | return fallback; 126 | } 127 | 128 | 129 | QIcon XdgIcon::fromTheme(const QString &iconName, 130 | const QString &fallbackIcon1, 131 | const QString &fallbackIcon2, 132 | const QString &fallbackIcon3, 133 | const QString &fallbackIcon4) 134 | { 135 | QStringList icons; 136 | icons << iconName; 137 | if (!fallbackIcon1.isEmpty()) icons << fallbackIcon1; 138 | if (!fallbackIcon2.isEmpty()) icons << fallbackIcon2; 139 | if (!fallbackIcon3.isEmpty()) icons << fallbackIcon3; 140 | if (!fallbackIcon4.isEmpty()) icons << fallbackIcon4; 141 | 142 | return fromTheme(icons); 143 | } 144 | 145 | bool XdgIcon::followColorScheme() 146 | { 147 | return XdgIconLoader::instance()->followColorScheme(); 148 | } 149 | 150 | 151 | void XdgIcon::setFollowColorScheme(bool enable) 152 | { 153 | XdgIconLoader::instance()->setFollowColorScheme(enable); 154 | } 155 | 156 | 157 | QIcon XdgIcon::defaultApplicationIcon() 158 | { 159 | return fromTheme(DEFAULT_APP_ICON); 160 | } 161 | 162 | 163 | QString XdgIcon::defaultApplicationIconName() 164 | { 165 | return DEFAULT_APP_ICON; 166 | } 167 | -------------------------------------------------------------------------------- /src/qtxdg/xdgicon.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGICON_H 29 | #define QTXDG_XDGICON_H 30 | 31 | #include "xdgmacros.h" 32 | #include 33 | #include 34 | #include 35 | 36 | class QTXDG_API XdgIcon 37 | { 38 | public: 39 | static QIcon fromTheme(const QString& iconName, const QIcon& fallback = QIcon()); 40 | static QIcon fromTheme(const QString& iconName, 41 | const QString &fallbackIcon1, 42 | const QString &fallbackIcon2 = QString(), 43 | const QString &fallbackIcon3 = QString(), 44 | const QString &fallbackIcon4 = QString()); 45 | static QIcon fromTheme(const QStringList& iconNames, const QIcon& fallback = QIcon()); 46 | 47 | /*! 48 | * Flag if the "FollowsColorScheme" hint (the KDE extension to XDG 49 | * themes) should be honored. If enabled and the icon theme supports 50 | * this, the icon engine "colorizes" icons based on the application's 51 | * palette. 52 | * 53 | * Default is true (use this extension). 54 | */ 55 | static bool followColorScheme(); 56 | static void setFollowColorScheme(bool enable); 57 | /* TODO: deprecate & remove all QIcon wrappers */ 58 | static QString themeName() { return QIcon::themeName(); } 59 | static void setThemeName(const QString& themeName) { QIcon::setThemeName(themeName); } 60 | 61 | static QIcon defaultApplicationIcon(); 62 | static QString defaultApplicationIconName(); 63 | 64 | protected: 65 | explicit XdgIcon(); 66 | virtual ~XdgIcon(); 67 | private: 68 | 69 | }; 70 | 71 | #endif // QTXDG_XDGICON_H 72 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmacros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2014 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef QTXDG_MACROS_H 22 | #define QTXDG_MACROS_H 23 | 24 | #ifdef __cplusplus 25 | # include 26 | # ifndef QTXDG_DEPRECATED 27 | # define QTXDG_DEPRECATED Q_DECL_DEPRECATED 28 | # endif 29 | #endif 30 | 31 | #ifdef QTXDG_COMPILATION 32 | #define QTXDG_API Q_DECL_EXPORT 33 | #else 34 | #define QTXDG_API Q_DECL_IMPORT 35 | #endif 36 | 37 | #if defined(QTXDG_COMPILATION) && defined(QTXDG_TESTS) 38 | # define QTXDG_AUTOTEST Q_DECL_EXPORT /* Build library,tests enabled */ 39 | #elif defined(QTXDG_BUILDING_TESTS) /* Build the tests */ 40 | # define QTXDG_AUTOTEST Q_DECL_IMPORT 41 | #else 42 | # define QTXDG_AUTOTEST /* Building library, tests disabled */ 43 | #endif 44 | 45 | #ifndef QL1S 46 | #define QL1S(x) QLatin1String(x) 47 | #endif 48 | 49 | #ifndef QL1C 50 | #define QL1C(x) QLatin1Char(x) 51 | #endif 52 | 53 | #ifndef QSL 54 | #define QSL(x) QStringLiteral(x) 55 | #endif 56 | 57 | #ifndef QBAL 58 | #define QBAL(x) QByteArrayLiteral(x) 59 | #endif 60 | 61 | #endif // QTXDG_MACROS_H 62 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenu.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGMENU_H 29 | #define QTXDG_XDGMENU_H 30 | 31 | #include "xdgmacros.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | class QDomDocument; 38 | class QDomElement; 39 | class XdgMenuPrivate; 40 | 41 | 42 | /*! @brief The XdgMenu class implements the "Desktop Menu Specification" from freedesktop.org. 43 | 44 | Freedesktop menu is a user-visible hierarchy of applications, typically displayed as a menu. 45 | 46 | Example usage: 47 | @code 48 | QString menuFile = XdgMenu::getMenuFileName(); 49 | XdgMenu xdgMenu(); 50 | 51 | bool res = xdgMenu.read(menuFile); 52 | if (!res) 53 | { 54 | QMessageBox::warning(this, "Parse error", xdgMenu.errorString()); 55 | } 56 | 57 | QDomElement rootElement = xdgMenu.xml().documentElement() 58 | @endcode 59 | 60 | @sa http://specifications.freedesktop.org/menu-spec/menu-spec-latest.html 61 | */ 62 | 63 | class QTXDG_API XdgMenu : public QObject 64 | { 65 | Q_OBJECT 66 | friend class XdgMenuReader; 67 | friend class XdgMenuApplinkProcessor; 68 | 69 | public: 70 | explicit XdgMenu(QObject *parent = nullptr); 71 | ~XdgMenu() override; 72 | 73 | bool read(const QString& menuFileName); 74 | void save(const QString& fileName); 75 | 76 | const QDomDocument xml() const; 77 | QString menuFileName() const; 78 | 79 | QDomElement findMenu(QDomElement& baseElement, const QString& path, bool createNonExisting); 80 | 81 | /*! Returns a list of strings identifying the environments that should 82 | * display a desktop entry. Internally all comparisons involving the 83 | * desktop environment names are made case insensitive. 84 | */ 85 | QStringList environments(); 86 | 87 | /*! 88 | * Set currently running environments. Example: RAZOR, KDE, or GNOME... 89 | * Internally all comparisons involving the desktop environment names 90 | * are made case insensitive. 91 | */ 92 | void setEnvironments(const QStringList &envs); 93 | void setEnvironments(const QString &env); 94 | 95 | /*! 96 | * Returns a string description of the last error that occurred if read() returns false. 97 | */ 98 | const QString errorString() const; 99 | 100 | /*! 101 | * @brief The name of the directory for the debug XML-files. 102 | */ 103 | const QString logDir() const; 104 | 105 | /*! 106 | * @brief The name of the directory for the debug XML-files. If a directory is specified, 107 | * then after you run the XdgMenu::read, you can see and check the results of the each step. 108 | */ 109 | void setLogDir(const QString& directory); 110 | 111 | static QString getMenuFileName(const QString& baseName = QLatin1String("applications.menu")); 112 | 113 | bool isOutDated() const; 114 | 115 | Q_SIGNALS: 116 | void changed(); 117 | 118 | protected: 119 | void addWatchPath(const QString& path); 120 | 121 | private: 122 | XdgMenuPrivate* const d_ptr; 123 | Q_DECLARE_PRIVATE(XdgMenu) 124 | }; 125 | 126 | 127 | #endif // QTXDG_XDGMENU_H 128 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenu_p.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgmenu.h" 29 | #include 30 | #include 31 | #include 32 | 33 | #define REBUILD_DELAY 3000 34 | 35 | class QDomElement; 36 | class QString; 37 | class QDomDocument; 38 | 39 | class XdgMenuPrivate : public QObject 40 | { 41 | Q_OBJECT 42 | public: 43 | XdgMenuPrivate(XdgMenu* parent); 44 | 45 | void simplify(QDomElement& element); 46 | void mergeMenus(QDomElement& element); 47 | void moveMenus(QDomElement& element); 48 | void deleteDeletedMenus(QDomElement& element); 49 | void processDirectoryEntries(QDomElement& element, const QStringList& parentDirs); 50 | void processApps(QDomElement& element); 51 | void deleteEmpty(QDomElement& element); 52 | void processLayouts(QDomElement& element); 53 | void fixSeparators(QDomElement& element); 54 | 55 | bool loadDirectoryFile(const QString& fileName, QDomElement& element); 56 | void prependChilds(QDomElement& srcElement, QDomElement& destElement); 57 | void appendChilds(QDomElement& srcElement, QDomElement& destElement); 58 | 59 | void saveLog(const QString& logFileName); 60 | void load(const QString& fileName); 61 | 62 | void clearWatcher(); 63 | 64 | QString mErrorString; 65 | QStringList mEnvironments; 66 | QString mMenuFileName; 67 | QString mLogDir; 68 | QDomDocument mXml; 69 | QByteArray mHash; 70 | QTimer mRebuildDelayTimer; 71 | 72 | QFileSystemWatcher mWatcher; 73 | bool mOutDated; 74 | 75 | public Q_SLOTS: 76 | void rebuild(); 77 | 78 | Q_SIGNALS: 79 | void changed(); 80 | 81 | 82 | private: 83 | XdgMenu* const q_ptr; 84 | Q_DECLARE_PUBLIC(XdgMenu) 85 | }; 86 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenuapplinkprocessor.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgmenu.h" 29 | #include "xdgmenuapplinkprocessor.h" 30 | #include "xmlhelper.h" 31 | #include "xdgdesktopfile.h" 32 | 33 | #include 34 | 35 | 36 | XdgMenuApplinkProcessor::XdgMenuApplinkProcessor(QDomElement& element, XdgMenu* menu, XdgMenuApplinkProcessor *parent) 37 | : QObject(parent), 38 | mParent(parent), 39 | mElement(element), 40 | mMenu(menu) 41 | { 42 | mOnlyUnallocated = element.attribute(QLatin1String("onlyUnallocated")) == QLatin1String("1"); 43 | 44 | MutableDomElementIterator i(element, QLatin1String("Menu")); 45 | while(i.hasNext()) 46 | { 47 | QDomElement e = i.next(); 48 | mChilds.push_back(new XdgMenuApplinkProcessor(e, mMenu, this)); 49 | } 50 | 51 | } 52 | 53 | 54 | XdgMenuApplinkProcessor::~XdgMenuApplinkProcessor() = default; 55 | 56 | 57 | void XdgMenuApplinkProcessor::run() 58 | { 59 | step1(); 60 | step2(); 61 | } 62 | 63 | 64 | void XdgMenuApplinkProcessor::step1() 65 | { 66 | fillAppFileInfoList(); 67 | createRules(); 68 | 69 | // Check Include rules & mark as allocated ............ 70 | XdgMenuAppFileInfoHashIterator i(mAppFileInfoHash); 71 | while(i.hasNext()) 72 | { 73 | i.next(); 74 | XdgDesktopFile* file = i.value()->desktopFile(); 75 | 76 | if (mRules.checkInclude(i.key(), *file)) 77 | { 78 | if (!mOnlyUnallocated) 79 | i.value()->setAllocated(true); 80 | 81 | if (!mRules.checkExclude(i.key(), *file)) 82 | { 83 | mSelected.push_back(i.value()); 84 | } 85 | 86 | } 87 | } 88 | 89 | // Process childs menus ............................... 90 | 91 | for (XdgMenuApplinkProcessor* child : std::as_const(mChilds)) 92 | child->step1(); 93 | } 94 | 95 | 96 | void XdgMenuApplinkProcessor::step2() 97 | { 98 | // Create AppLinks elements ........................... 99 | QDomDocument doc = mElement.ownerDocument(); 100 | 101 | for (XdgMenuAppFileInfo* fileInfo : std::as_const(mSelected)) 102 | { 103 | if (mOnlyUnallocated && fileInfo->allocated()) 104 | continue; 105 | 106 | XdgDesktopFile* file = fileInfo->desktopFile(); 107 | 108 | bool show = false; 109 | QStringList envs = mMenu->environments(); 110 | const int N = envs.size(); 111 | for (int i = 0; i < N; ++i) 112 | { 113 | if (file->isShown(envs.at(i))) 114 | { 115 | show = true; 116 | break; 117 | } 118 | } 119 | 120 | if (!show) 121 | continue; 122 | 123 | QDomElement appLink = doc.createElement(QLatin1String("AppLink")); 124 | 125 | appLink.setAttribute(QLatin1String("id"), fileInfo->id()); 126 | appLink.setAttribute(QLatin1String("title"), file->localizedValue(QLatin1String("Name")).toString()); 127 | appLink.setAttribute(QLatin1String("comment"), file->localizedValue(QLatin1String("Comment")).toString()); 128 | appLink.setAttribute(QLatin1String("genericName"), file->localizedValue(QLatin1String("GenericName")).toString()); 129 | appLink.setAttribute(QLatin1String("exec"), file->value(QLatin1String("Exec")).toString()); 130 | appLink.setAttribute(QLatin1String("terminal"), file->value(QLatin1String("Terminal")).toBool()); 131 | appLink.setAttribute(QLatin1String("startupNoify"), file->value(QLatin1String("StartupNotify")).toBool()); 132 | appLink.setAttribute(QLatin1String("path"), file->value(QLatin1String("Path")).toString()); 133 | appLink.setAttribute(QLatin1String("icon"), file->value(QLatin1String("Icon")).toString()); 134 | appLink.setAttribute(QLatin1String("desktopFile"), file->fileName()); 135 | 136 | mElement.appendChild(appLink); 137 | 138 | } 139 | 140 | 141 | // Process childs menus ............................... 142 | for (XdgMenuApplinkProcessor* child : std::as_const(mChilds)) 143 | child->step2(); 144 | } 145 | 146 | 147 | /************************************************ 148 | For each element, build a pool of desktop entries by collecting entries found 149 | in each for the menu element. If two entries have the same desktop-file id, 150 | the entry for the earlier (closer to the top of the file) must be discarded. 151 | 152 | Next, add to the pool the entries for any s specified by ancestor 153 | elements. If a parent menu has a duplicate entry (same desktop-file id), the entry 154 | for the child menu has priority. 155 | ************************************************/ 156 | void XdgMenuApplinkProcessor::fillAppFileInfoList() 157 | { 158 | // Build a pool by collecting entries found in 159 | { 160 | MutableDomElementIterator i(mElement, QLatin1String("AppDir")); 161 | i.toBack(); 162 | while(i.hasPrevious()) 163 | { 164 | QDomElement e = i.previous(); 165 | findDesktopFiles(e.text(), QString()); 166 | mElement.removeChild(e); 167 | } 168 | } 169 | 170 | // Add the entries for ancestor ................ 171 | if (mParent) 172 | { 173 | XdgMenuAppFileInfoHashIterator i(mParent->mAppFileInfoHash); 174 | while(i.hasNext()) 175 | { 176 | i.next(); 177 | //if (!mAppFileInfoHash.contains(i.key())) 178 | mAppFileInfoHash.insert(i.key(), i.value()); 179 | } 180 | } 181 | } 182 | 183 | 184 | void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QString& prefix) 185 | { 186 | QDir dir(dirName); 187 | mMenu->addWatchPath(dir.absolutePath()); 188 | const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files); 189 | 190 | for (const QFileInfo &file : files) 191 | { 192 | auto f = std::make_unique(); 193 | if (f->load(file.absoluteFilePath()) && f->isValid()) 194 | mAppFileInfoHash.insert(prefix + file.fileName(), new XdgMenuAppFileInfo(std::move(f), prefix + file.fileName(), this)); 195 | } 196 | 197 | 198 | // Working recursively ............ 199 | const QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); 200 | for (const QFileInfo &d : dirs) 201 | { 202 | QString dn = d.absoluteFilePath(); 203 | if (dn != dirName) 204 | { 205 | findDesktopFiles(dn, QString::fromLatin1("%1%2-").arg(prefix, d.fileName())); 206 | } 207 | } 208 | } 209 | 210 | 211 | void XdgMenuApplinkProcessor::createRules() 212 | { 213 | MutableDomElementIterator i(mElement, QString()); 214 | while(i.hasNext()) 215 | { 216 | QDomElement e = i.next(); 217 | if (e.tagName()== QLatin1String("Include")) 218 | { 219 | mRules.addInclude(e); 220 | mElement.removeChild(e); 221 | } 222 | 223 | else if (e.tagName()== QLatin1String("Exclude")) 224 | { 225 | mRules.addExclude(e); 226 | mElement.removeChild(e); 227 | } 228 | } 229 | 230 | } 231 | 232 | 233 | /************************************************ 234 | Check if the program is actually installed. 235 | ************************************************/ 236 | bool XdgMenuApplinkProcessor::checkTryExec(const QString& progName) 237 | { 238 | if (progName.startsWith(QDir::separator())) 239 | return QFileInfo(progName).isExecutable(); 240 | 241 | const QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':')); 242 | 243 | for (const QString &dir : dirs) 244 | { 245 | if (QFileInfo(QDir(dir), progName).isExecutable()) 246 | return true; 247 | } 248 | 249 | return false; 250 | } 251 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenuapplinkprocessor.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGMENUAPPLINKPROCESSOR_H 29 | #define QTXDG_XDGMENUAPPLINKPROCESSOR_H 30 | 31 | #include "xdgmenurules.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | class XdgMenu; 41 | class XdgMenuAppFileInfo; 42 | class XdgDesktopFile; 43 | 44 | typedef std::list XdgMenuAppFileInfoList; 45 | 46 | typedef QHash XdgMenuAppFileInfoHash; 47 | typedef QHashIterator XdgMenuAppFileInfoHashIterator; 48 | 49 | 50 | class XdgMenuApplinkProcessor : public QObject 51 | { 52 | Q_OBJECT 53 | public: 54 | explicit XdgMenuApplinkProcessor(QDomElement& element, XdgMenu* menu, XdgMenuApplinkProcessor *parent = nullptr); 55 | ~XdgMenuApplinkProcessor() override; 56 | void run(); 57 | 58 | protected: 59 | void step1(); 60 | void step2(); 61 | void fillAppFileInfoList(); 62 | void findDesktopFiles(const QString& dirName, const QString& prefix); 63 | 64 | //bool loadDirectoryFile(const QString& fileName, QDomElement& element); 65 | void createRules(); 66 | bool checkTryExec(const QString& progName); 67 | 68 | private: 69 | XdgMenuApplinkProcessor* mParent; 70 | std::list mChilds; 71 | XdgMenuAppFileInfoHash mAppFileInfoHash; 72 | XdgMenuAppFileInfoList mSelected; 73 | QDomElement mElement; 74 | bool mOnlyUnallocated; 75 | 76 | XdgMenu* mMenu; 77 | XdgMenuRules mRules; 78 | }; 79 | 80 | 81 | class XdgMenuAppFileInfo: public QObject 82 | { 83 | Q_OBJECT 84 | public: 85 | explicit XdgMenuAppFileInfo(std::unique_ptr desktopFile, const QString& id, QObject *parent) 86 | : QObject(parent), 87 | mDesktopFile{std::move(desktopFile)}, 88 | mAllocated(false), 89 | mId(id) 90 | { 91 | } 92 | 93 | XdgDesktopFile* desktopFile() const { return mDesktopFile.get(); } 94 | bool allocated() const { return mAllocated; } 95 | void setAllocated(bool value) { mAllocated = value; } 96 | QString id() const { return mId; } 97 | private: 98 | std::unique_ptr mDesktopFile; 99 | bool mAllocated; 100 | QString mId; 101 | }; 102 | 103 | #endif // QTXDG_XDGMENUAPPLINKPROCESSOR_H 104 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenulayoutprocessor.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGMENULAYOUTPROCESSOR_H 29 | #define QTXDG_XDGMENULAYOUTPROCESSOR_H 30 | 31 | #include 32 | #include 33 | 34 | struct LayoutItem 35 | { 36 | enum Type{ 37 | Filename, 38 | Menuname, 39 | Separator, 40 | MergeMenus, 41 | MergeFiles, 42 | MergeAll, 43 | }; 44 | 45 | Type type; 46 | bool showEmpty; 47 | bool isInline; 48 | bool inlineLimit; 49 | bool inlineHeader; 50 | bool inlineAlias; 51 | QString fileId; 52 | }; 53 | 54 | //class Layout: public QList 55 | //{ 56 | //public: 57 | /* Layout() {} 58 | 59 | 60 | bool showEmpty() { return mShowEmpty; } 61 | void setShowEmpty(bool value) { mShowEmpty = value; } 62 | 63 | bool isInline() { return mInline; } 64 | void setInline(bool value) { mInline = value; } 65 | 66 | int inlineLimit() { return mInlineLimit; } 67 | void setInlineLimit(int value) { mInlineLimit = value; } 68 | 69 | bool inlineHeader() {return mInlineHeader; } 70 | void setInlineHeader(bool value) { mInlineHeader = value; } 71 | 72 | bool inlineAlias() { return mInlineAlias; } 73 | void setInlineAlias(bool value) { mInlineAlias = value; } 74 | 75 | 76 | 77 | private: 78 | */ 79 | 80 | struct LayoutParams 81 | { 82 | bool mShowEmpty; 83 | bool mInline; 84 | int mInlineLimit; 85 | bool mInlineHeader; 86 | bool mInlineAlias; 87 | }; 88 | 89 | 90 | class XdgMenuLayoutProcessor 91 | { 92 | public: 93 | XdgMenuLayoutProcessor(QDomElement& element); 94 | void run(); 95 | 96 | protected: 97 | XdgMenuLayoutProcessor(QDomElement& element, XdgMenuLayoutProcessor *parent); 98 | 99 | private: 100 | void setParams(QDomElement defaultLayout, LayoutParams *result); 101 | QDomElement searchElement(const QString &tagName, const QString &attributeName, const QString &attributeValue) const; 102 | void processFilenameTag(const QDomElement &element); 103 | void processMenunameTag(const QDomElement &element); 104 | void processSeparatorTag(const QDomElement &element); 105 | void processMergeTag(const QDomElement &element); 106 | 107 | LayoutParams mDefaultParams; 108 | QDomElement& mElement; 109 | QDomElement mDefaultLayout; 110 | QDomElement mLayout; 111 | QDomElement mResult; 112 | }; 113 | 114 | #endif // QTXDG_XDGMENULAYOUTPROCESSOR_H 115 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenureader.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGMENUREADER_H 29 | #define QTXDG_XDGMENUREADER_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | class XdgMenu; 38 | class XdgMenuReader : public QObject 39 | { 40 | Q_OBJECT 41 | public: 42 | explicit XdgMenuReader(XdgMenu* menu, XdgMenuReader* parentReader = nullptr, QObject *parent = nullptr); 43 | ~XdgMenuReader() override; 44 | 45 | bool load(const QString& fileName, const QString& baseDir = QString()); 46 | QString fileName() const { return mFileName; } 47 | QString errorString() const { return mErrorStr; } 48 | QDomDocument& xml() { return mXml; } 49 | 50 | Q_SIGNALS: 51 | 52 | public Q_SLOTS: 53 | 54 | protected: 55 | void processMergeTags(QDomElement& element); 56 | void processMergeFileTag(QDomElement& element, QStringList* mergedFiles); 57 | void processMergeDirTag(QDomElement& element, QStringList* mergedFiles); 58 | void processDefaultMergeDirsTag(QDomElement& element, QStringList* mergedFiles); 59 | 60 | void processAppDirTag(QDomElement& element); 61 | void processDefaultAppDirsTag(QDomElement& element); 62 | 63 | void processDirectoryDirTag(QDomElement& element); 64 | void processDefaultDirectoryDirsTag(QDomElement& element); 65 | void addDirTag(QDomElement& previousElement, const QString& tagName, const QString& dir); 66 | 67 | void mergeFile(const QString& fileName, QDomElement& element, QStringList* mergedFiles); 68 | void mergeDir(const QString& dirName, QDomElement& element, QStringList* mergedFiles); 69 | 70 | private: 71 | QString mFileName; 72 | QString mDirName; 73 | QString mErrorStr; 74 | QDomDocument mXml; 75 | XdgMenuReader* mParentReader; 76 | QStringList mBranchFiles; 77 | XdgMenu* mMenu; 78 | }; 79 | 80 | #endif // QTXDG_XDGMENUREADER_H 81 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenurules.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgmenurules.h" 29 | #include "xmlhelper.h" 30 | 31 | #include 32 | #include 33 | 34 | 35 | /** 36 | * See: http://standards.freedesktop.org/desktop-entry-spec 37 | */ 38 | 39 | XdgMenuRule::XdgMenuRule(const QDomElement& element, QObject* parent) : 40 | QObject(parent) 41 | { 42 | Q_UNUSED(element) 43 | } 44 | 45 | 46 | XdgMenuRule::~XdgMenuRule() = default; 47 | 48 | 49 | /************************************************ 50 | The element contains a list of matching rules. If any of the matching rules 51 | inside the element match a desktop entry, then the entire rule matches 52 | the desktop entry. 53 | ************************************************/ 54 | XdgMenuRuleOr::XdgMenuRuleOr(const QDomElement& element, QObject* parent) : 55 | XdgMenuRule(element, parent) 56 | { 57 | //qDebug() << "Create OR rule"; 58 | DomElementIterator iter(element, QString()); 59 | 60 | while(iter.hasNext()) 61 | { 62 | QDomElement e = iter.next(); 63 | 64 | if (e.tagName() == QLatin1String("Or")) 65 | mChilds.push_back(new XdgMenuRuleOr(e, this)); 66 | 67 | else if (e.tagName() == QLatin1String("And")) 68 | mChilds.push_back(new XdgMenuRuleAnd(e, this)); 69 | 70 | else if (e.tagName() == QLatin1String("Not")) 71 | mChilds.push_back(new XdgMenuRuleNot(e, this)); 72 | 73 | else if (e.tagName() == QLatin1String("Filename")) 74 | mChilds.push_back(new XdgMenuRuleFileName(e, this)); 75 | 76 | else if (e.tagName() == QLatin1String("Category")) 77 | mChilds.push_back(new XdgMenuRuleCategory(e, this)); 78 | 79 | else if (e.tagName() == QLatin1String("All")) 80 | mChilds.push_back(new XdgMenuRuleAll(e, this)); 81 | 82 | else 83 | qWarning() << QString::fromLatin1("Unknown rule") << e.tagName(); 84 | } 85 | 86 | } 87 | 88 | 89 | bool XdgMenuRuleOr::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 90 | { 91 | for (std::list::const_iterator i=mChilds.cbegin(); i!=mChilds.cend(); ++i) 92 | if ((*i)->check(desktopFileId, desktopFile)) return true; 93 | 94 | return false; 95 | } 96 | 97 | 98 | /************************************************ 99 | The element contains a list of matching rules. If each of the matching rules 100 | inside the element match a desktop entry, then the entire rule matches 101 | the desktop entry. 102 | ************************************************/ 103 | XdgMenuRuleAnd::XdgMenuRuleAnd(const QDomElement& element, QObject *parent) : 104 | XdgMenuRuleOr(element, parent) 105 | { 106 | // qDebug() << "Create AND rule"; 107 | } 108 | 109 | 110 | bool XdgMenuRuleAnd::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 111 | { 112 | for (std::list::const_iterator i=mChilds.cbegin(); i!=mChilds.cend(); ++i) 113 | if (!(*i)->check(desktopFileId, desktopFile)) return false; 114 | 115 | return !mChilds.empty(); 116 | } 117 | 118 | 119 | /************************************************ 120 | The element contains a list of matching rules. If any of the matching rules 121 | inside the element matches a desktop entry, then the entire rule does 122 | not match the desktop entry. That is, matching rules below have a logical OR 123 | relationship. 124 | ************************************************/ 125 | XdgMenuRuleNot::XdgMenuRuleNot(const QDomElement& element, QObject *parent) : 126 | XdgMenuRuleOr(element, parent) 127 | { 128 | // qDebug() << "Create NOT rule"; 129 | } 130 | 131 | 132 | bool XdgMenuRuleNot::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 133 | { 134 | return ! XdgMenuRuleOr::check(desktopFileId, desktopFile); 135 | } 136 | 137 | 138 | /************************************************ 139 | The element is the most basic matching rule. It matches a desktop entry 140 | if the desktop entry has the given desktop-file id. See Desktop-File Id. 141 | ************************************************/ 142 | XdgMenuRuleFileName::XdgMenuRuleFileName(const QDomElement& element, QObject *parent) : 143 | XdgMenuRule(element, parent), 144 | mId(element.text()) 145 | { 146 | //qDebug() << "Create FILENAME rule"; 147 | } 148 | 149 | 150 | bool XdgMenuRuleFileName::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 151 | { 152 | Q_UNUSED(desktopFile) 153 | //qDebug() << "XdgMenuRuleFileName:" << desktopFileId << mId; 154 | return desktopFileId == mId; 155 | } 156 | 157 | 158 | /************************************************ 159 | The element is another basic matching predicate. It matches a desktop entry 160 | if the desktop entry has the given category in its Categories field. 161 | ************************************************/ 162 | XdgMenuRuleCategory::XdgMenuRuleCategory(const QDomElement& element, QObject *parent) : 163 | XdgMenuRule(element, parent), 164 | mCategory(element.text()) 165 | { 166 | } 167 | 168 | 169 | bool XdgMenuRuleCategory::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 170 | { 171 | Q_UNUSED(desktopFileId) 172 | QStringList cats = desktopFile.categories(); 173 | return cats.contains(mCategory); 174 | } 175 | 176 | 177 | /************************************************ 178 | The element is a matching rule that matches all desktop entries. 179 | ************************************************/ 180 | XdgMenuRuleAll::XdgMenuRuleAll(const QDomElement& element, QObject *parent) : 181 | XdgMenuRule(element, parent) 182 | { 183 | } 184 | 185 | 186 | bool XdgMenuRuleAll::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 187 | { 188 | Q_UNUSED(desktopFileId) 189 | Q_UNUSED(desktopFile) 190 | return true; 191 | } 192 | 193 | 194 | XdgMenuRules::XdgMenuRules(QObject* parent) : 195 | QObject(parent) 196 | { 197 | } 198 | 199 | 200 | XdgMenuRules::~XdgMenuRules() = default; 201 | 202 | 203 | void XdgMenuRules::addInclude(const QDomElement& element) 204 | { 205 | mIncludeRules.push_back(new XdgMenuRuleOr(element, this)); 206 | } 207 | 208 | 209 | void XdgMenuRules::addExclude(const QDomElement& element) 210 | { 211 | mExcludeRules.push_back(new XdgMenuRuleOr(element, this)); 212 | } 213 | 214 | 215 | bool XdgMenuRules::checkInclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 216 | { 217 | for (std::list::const_iterator i=mIncludeRules.cbegin(); i!=mIncludeRules.cend(); ++i) 218 | if ((*i)->check(desktopFileId, desktopFile)) return true; 219 | 220 | return false; 221 | } 222 | 223 | 224 | bool XdgMenuRules::checkExclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile) 225 | { 226 | for (std::list::const_iterator i=mExcludeRules.cbegin(); i!=mExcludeRules.cend(); ++i) 227 | if ((*i)->check(desktopFileId, desktopFile)) return true; 228 | 229 | return false; 230 | } 231 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenurules.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGMENURULES_H 29 | #define QTXDG_XDGMENURULES_H 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include "xdgdesktopfile.h" 37 | 38 | 39 | /** 40 | * See: http://standards.freedesktop.org/desktop-entry-spec 41 | */ 42 | 43 | class XdgMenuRule : public QObject 44 | { 45 | Q_OBJECT 46 | public: 47 | explicit XdgMenuRule(const QDomElement& element, QObject* parent = nullptr); 48 | ~XdgMenuRule() override; 49 | 50 | virtual bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) = 0; 51 | }; 52 | 53 | 54 | class XdgMenuRuleOr : public XdgMenuRule 55 | { 56 | Q_OBJECT 57 | public: 58 | explicit XdgMenuRuleOr(const QDomElement& element, QObject* parent = nullptr); 59 | 60 | bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) override; 61 | 62 | protected: 63 | std::list mChilds; 64 | }; 65 | 66 | 67 | class XdgMenuRuleAnd : public XdgMenuRuleOr 68 | { 69 | Q_OBJECT 70 | public: 71 | explicit XdgMenuRuleAnd(const QDomElement& element, QObject* parent = nullptr); 72 | bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) override; 73 | }; 74 | 75 | 76 | class XdgMenuRuleNot : public XdgMenuRuleOr 77 | { 78 | Q_OBJECT 79 | public: 80 | explicit XdgMenuRuleNot(const QDomElement& element, QObject* parent = nullptr); 81 | bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) override; 82 | }; 83 | 84 | 85 | class XdgMenuRuleFileName : public XdgMenuRule 86 | { 87 | Q_OBJECT 88 | public: 89 | explicit XdgMenuRuleFileName(const QDomElement& element, QObject* parent = nullptr); 90 | bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) override; 91 | private: 92 | QString mId; 93 | }; 94 | 95 | 96 | class XdgMenuRuleCategory : public XdgMenuRule 97 | { 98 | Q_OBJECT 99 | public: 100 | explicit XdgMenuRuleCategory(const QDomElement& element, QObject* parent = nullptr); 101 | bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) override; 102 | private: 103 | QString mCategory; 104 | }; 105 | 106 | 107 | class XdgMenuRuleAll : public XdgMenuRule 108 | { 109 | Q_OBJECT 110 | public: 111 | explicit XdgMenuRuleAll(const QDomElement& element, QObject* parent = nullptr); 112 | bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) override; 113 | }; 114 | 115 | 116 | 117 | class XdgMenuRules : public QObject 118 | { 119 | Q_OBJECT 120 | public: 121 | explicit XdgMenuRules(QObject* parent = nullptr); 122 | ~XdgMenuRules() override; 123 | 124 | void addInclude(const QDomElement& element); 125 | void addExclude(const QDomElement& element); 126 | 127 | bool checkInclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile); 128 | bool checkExclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile); 129 | 130 | protected: 131 | std::list mIncludeRules; 132 | std::list mExcludeRules; 133 | }; 134 | 135 | #endif // QTXDG_XDGMENURULES_H 136 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenuwidget.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgmenuwidget.h" 29 | #include "xdgicon.h" 30 | #include "xmlhelper.h" 31 | #include "xdgaction.h" 32 | #include "xdgmenu.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | 43 | class XdgMenuWidgetPrivate 44 | { 45 | private: 46 | XdgMenuWidget* const q_ptr; 47 | Q_DECLARE_PUBLIC(XdgMenuWidget) 48 | 49 | public: 50 | explicit XdgMenuWidgetPrivate(XdgMenuWidget* parent): 51 | q_ptr(parent) 52 | {} 53 | 54 | void init(const QDomElement& xml); 55 | void buildMenu(); 56 | 57 | QDomElement mXml; 58 | 59 | void mouseMoveEvent(QMouseEvent *event); 60 | 61 | QPoint mDragStartPosition; 62 | 63 | private: 64 | XdgAction* createAction(const QDomElement& xml); 65 | static QString escape(QString string); 66 | }; 67 | 68 | 69 | XdgMenuWidget::XdgMenuWidget(const XdgMenu& xdgMenu, const QString& title, QWidget* parent): 70 | QMenu(parent), 71 | d_ptr(new XdgMenuWidgetPrivate(this)) 72 | { 73 | d_ptr->init(xdgMenu.xml().documentElement()); 74 | setTitle(XdgMenuWidgetPrivate::escape(title)); 75 | } 76 | 77 | 78 | XdgMenuWidget::XdgMenuWidget(const QDomElement& menuElement, QWidget* parent): 79 | QMenu(parent), 80 | d_ptr(new XdgMenuWidgetPrivate(this)) 81 | { 82 | d_ptr->init(menuElement); 83 | } 84 | 85 | 86 | XdgMenuWidget::XdgMenuWidget(const XdgMenuWidget& other, QWidget* parent): 87 | QMenu(parent), 88 | d_ptr(new XdgMenuWidgetPrivate(this)) 89 | { 90 | d_ptr->init(other.d_ptr->mXml); 91 | } 92 | 93 | 94 | void XdgMenuWidgetPrivate::init(const QDomElement& xml) 95 | { 96 | Q_Q(XdgMenuWidget); 97 | mXml = xml; 98 | 99 | q->clear(); 100 | 101 | QString title; 102 | if (! xml.attribute(QLatin1String("title")).isEmpty()) 103 | title = xml.attribute(QLatin1String("title")); 104 | else 105 | title = xml.attribute(QLatin1String("name")); 106 | q->setTitle(escape(title)); 107 | 108 | //q->setToolTip(xml.attribute(QLatin1String("comment"))); 109 | q->setToolTipsVisible(true); 110 | 111 | 112 | QIcon parentIcon; 113 | QMenu* parentMenu = qobject_cast(q->parent()); 114 | if (parentMenu) 115 | parentIcon = parentMenu->icon(); 116 | 117 | q->setIcon(XdgIcon::fromTheme(mXml.attribute(QLatin1String("icon")), parentIcon)); 118 | 119 | buildMenu(); 120 | } 121 | 122 | 123 | XdgMenuWidget::~XdgMenuWidget() 124 | { 125 | delete d_ptr; 126 | } 127 | 128 | 129 | XdgMenuWidget& XdgMenuWidget::operator=(const XdgMenuWidget& other) 130 | { 131 | Q_D(XdgMenuWidget); 132 | d->init(other.d_ptr->mXml); 133 | 134 | return *this; 135 | } 136 | 137 | 138 | bool XdgMenuWidget::event(QEvent* event) 139 | { 140 | Q_D(XdgMenuWidget); 141 | 142 | if (event->type() == QEvent::MouseButtonPress) 143 | { 144 | QMouseEvent *e = static_cast(event); 145 | if (e->button() == Qt::LeftButton) 146 | d->mDragStartPosition = e->pos(); 147 | } 148 | 149 | else if (event->type() == QEvent::MouseMove) 150 | { 151 | QMouseEvent *e = static_cast(event); 152 | d->mouseMoveEvent(e); 153 | } 154 | 155 | return QMenu::event(event); 156 | } 157 | 158 | 159 | void XdgMenuWidgetPrivate::mouseMoveEvent(QMouseEvent *event) 160 | { 161 | if (!(event->buttons() & Qt::LeftButton)) 162 | return; 163 | 164 | if ((event->pos() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance()) 165 | return; 166 | 167 | Q_Q(XdgMenuWidget); 168 | XdgAction *a = qobject_cast(q->actionAt(mDragStartPosition)); 169 | if (!a) 170 | return; 171 | 172 | QList urls; 173 | urls << QUrl::fromLocalFile(a->desktopFile().fileName()); 174 | 175 | QMimeData *mimeData = new QMimeData(); 176 | mimeData->setUrls(urls); 177 | 178 | QDrag *drag = new QDrag(q); 179 | drag->setMimeData(mimeData); 180 | drag->exec(Qt::CopyAction | Qt::LinkAction); 181 | } 182 | 183 | 184 | void XdgMenuWidgetPrivate::buildMenu() 185 | { 186 | Q_Q(XdgMenuWidget); 187 | 188 | QAction* first = nullptr; 189 | if (!q->actions().isEmpty()) 190 | first = q->actions().constLast(); 191 | 192 | 193 | DomElementIterator it(mXml, QString()); 194 | while(it.hasNext()) 195 | { 196 | QDomElement xml = it.next(); 197 | 198 | // Build submenu ........................ 199 | if (xml.tagName() == QLatin1String("Menu")) 200 | q->insertMenu(first, new XdgMenuWidget(xml, q)); 201 | 202 | //Build application link ................ 203 | else if (xml.tagName() == QLatin1String("AppLink")) 204 | q->insertAction(first, createAction(xml)); 205 | 206 | //Build separator ....................... 207 | else if (xml.tagName() == QLatin1String("Separator")) 208 | q->insertSeparator(first); 209 | 210 | } 211 | } 212 | 213 | 214 | XdgAction* XdgMenuWidgetPrivate::createAction(const QDomElement& xml) 215 | { 216 | Q_Q(XdgMenuWidget); 217 | XdgAction* action = new XdgAction(xml.attribute(QLatin1String("desktopFile")), q); 218 | 219 | QString title; 220 | if (!xml.attribute(QLatin1String("title")).isEmpty()) 221 | title = xml.attribute(QLatin1String("title")); 222 | else 223 | title = xml.attribute(QLatin1String("name")); 224 | 225 | action->setText(escape(title)); 226 | 227 | if (!xml.attribute(QLatin1String("genericName")).isEmpty() && 228 | xml.attribute(QLatin1String("genericName")) != title) 229 | action->setToolTip(xml.attribute(QLatin1String("genericName"))); 230 | 231 | return action; 232 | } 233 | 234 | 235 | /************************************************ 236 | This should be used when a menu item text is set 237 | otherwise Qt uses the &'s for creating mnemonics 238 | ************************************************/ 239 | QString XdgMenuWidgetPrivate::escape(QString string) 240 | { 241 | return string.replace(QLatin1Char('&'), QLatin1String("&&")); 242 | } 243 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmenuwidget.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XDGMENUWIDGET_H 29 | #define QTXDG_XDGMENUWIDGET_H 30 | 31 | #include "xdgmacros.h" 32 | #include 33 | #include 34 | 35 | class XdgMenu; 36 | class QEvent; 37 | class XdgMenuWidgetPrivate; 38 | 39 | 40 | /*! 41 | @brief The XdgMenuWidget class provides an QMenu widget for application menu or its part. 42 | 43 | Example usage: 44 | @code 45 | QString menuFile = XdgMenu::getMenuFileName(); 46 | XdgMenu xdgMenu(menuFile); 47 | 48 | bool res = xdgMenu.read(); 49 | if (res) 50 | { 51 | XdgMenuWidget menu(xdgMenu, QString(), this); 52 | menu.exec(QCursor::pos()); 53 | } 54 | else 55 | { 56 | QMessageBox::warning(this, "Parse error", xdgMenu.errorString()); 57 | } 58 | @endcode 59 | */ 60 | 61 | class QTXDG_API XdgMenuWidget : public QMenu 62 | { 63 | Q_OBJECT 64 | public: 65 | /// Constructs a menu for root documentElement in xdgMenu with some text and parent. 66 | XdgMenuWidget(const XdgMenu& xdgMenu, const QString& title = QString(), QWidget* parent=nullptr); 67 | 68 | /// Constructs a menu for menuElement with parent. 69 | explicit XdgMenuWidget(const QDomElement& menuElement, QWidget* parent=nullptr); 70 | 71 | /// Constructs a copy of other. 72 | XdgMenuWidget(const XdgMenuWidget& other, QWidget* parent=nullptr); 73 | 74 | /// Assigns other to this menu. 75 | XdgMenuWidget& operator=(const XdgMenuWidget& other); 76 | 77 | /// Destroys the menu. 78 | ~XdgMenuWidget() override; 79 | 80 | protected: 81 | bool event(QEvent* event) override; 82 | 83 | private: 84 | XdgMenuWidgetPrivate* const d_ptr; 85 | Q_DECLARE_PRIVATE(XdgMenuWidget) 86 | }; 87 | 88 | #endif // QTXDG_XDGMENUWIDGET_H 89 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeapps.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "xdgmimeapps.h" 22 | #include "xdgmimeapps_p.h" 23 | 24 | #include "xdgdesktopfile.h" 25 | #include "xdgmacros.h" 26 | #include "xdgmimeappsglibbackend.h" 27 | 28 | #include 29 | #include 30 | 31 | XdgMimeAppsPrivate::XdgMimeAppsPrivate() 32 | : mBackend(nullptr) 33 | { 34 | } 35 | 36 | void XdgMimeAppsPrivate::init() 37 | { 38 | Q_Q(XdgMimeApps); 39 | mBackend = new XdgMimeAppsGLibBackend(q); 40 | QObject::connect(mBackend, &XdgMimeAppsBackendInterface::changed, q, [=] () { 41 | Q_EMIT q->changed(); 42 | }); 43 | } 44 | 45 | XdgMimeAppsPrivate::~XdgMimeAppsPrivate() = default; 46 | 47 | XdgMimeApps::XdgMimeApps(QObject *parent) 48 | : QObject(*new XdgMimeAppsPrivate, parent) 49 | { 50 | d_func()->init(); 51 | } 52 | 53 | XdgMimeApps::~XdgMimeApps() = default; 54 | 55 | bool XdgMimeApps::addSupport(const QString &mimeType, const XdgDesktopFile &app) 56 | { 57 | Q_D(XdgMimeApps); 58 | if (mimeType.isEmpty() || !app.isValid()) 59 | return false; 60 | 61 | QMutexLocker locker(&d->mutex); 62 | return d->mBackend->addAssociation(mimeType, app); 63 | } 64 | 65 | QList XdgMimeApps::allApps() 66 | { 67 | Q_D(XdgMimeApps); 68 | QMutexLocker locker(&d->mutex); 69 | return d->mBackend->allApps(); 70 | } 71 | 72 | QList XdgMimeApps::apps(const QString &mimeType) 73 | { 74 | Q_D(XdgMimeApps); 75 | if (mimeType.isEmpty()) 76 | return QList(); 77 | 78 | QMutexLocker locker(&d->mutex); 79 | return d->mBackend->apps(mimeType); 80 | } 81 | 82 | QList XdgMimeApps::categoryApps(const QString &category) 83 | { 84 | if (category.isEmpty()) 85 | return QList(); 86 | 87 | const QString cat = category.toUpper(); 88 | const QList apps = allApps(); 89 | QList dl; 90 | for (XdgDesktopFile * const df : apps) { 91 | const QStringList categories = df->value(QL1S("Categories")).toString().toUpper().split(QL1C(';')); 92 | if (!categories.isEmpty() && (categories.contains(cat) || categories.contains(QL1S("X-") + cat))) 93 | dl.append(df); 94 | else 95 | delete df; 96 | } 97 | return dl; 98 | } 99 | 100 | QList XdgMimeApps::fallbackApps(const QString &mimeType) 101 | { 102 | Q_D(XdgMimeApps); 103 | if (mimeType.isEmpty()) 104 | return QList(); 105 | 106 | QMutexLocker locker(&d->mutex); 107 | return d->mBackend->fallbackApps(mimeType); 108 | } 109 | 110 | QList XdgMimeApps::recommendedApps(const QString &mimeType) 111 | { 112 | Q_D(XdgMimeApps); 113 | if (mimeType.isEmpty()) 114 | return QList(); 115 | 116 | QMutexLocker locker(&d->mutex); 117 | return d->mBackend->recommendedApps(mimeType); 118 | } 119 | 120 | XdgDesktopFile *XdgMimeApps::defaultApp(const QString &mimeType) 121 | { 122 | Q_D(XdgMimeApps); 123 | if (mimeType.isEmpty()) 124 | return nullptr; 125 | 126 | QMutexLocker locker(&d->mutex); 127 | return d->mBackend->defaultApp(mimeType); 128 | } 129 | 130 | bool XdgMimeApps::removeSupport(const QString &mimeType, const XdgDesktopFile &app) 131 | { 132 | Q_D(XdgMimeApps); 133 | if (mimeType.isEmpty() || !app.isValid()) 134 | return false; 135 | 136 | QMutexLocker locker(&d->mutex); 137 | return d->mBackend->removeAssociation(mimeType, app); 138 | } 139 | 140 | bool XdgMimeApps::reset(const QString &mimeType) 141 | { 142 | Q_D(XdgMimeApps); 143 | if (mimeType.isEmpty()) 144 | return false; 145 | 146 | QMutexLocker locker(&d->mutex); 147 | return d->mBackend->reset(mimeType); 148 | } 149 | 150 | bool XdgMimeApps::setDefaultApp(const QString &mimeType, const XdgDesktopFile &app) 151 | { 152 | Q_D(XdgMimeApps); 153 | if (mimeType.isEmpty() || !app.isValid()) 154 | return false; 155 | 156 | if (XdgDesktopFile::id(app.fileName()).isEmpty()) 157 | return false; 158 | 159 | QMutexLocker locker(&d->mutex); 160 | return d->mBackend->setDefaultApp(mimeType, app); 161 | } 162 | 163 | #include "moc_xdgmimeapps.cpp" 164 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeapps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef XDGMIMEAPPS_H 22 | #define XDGMIMEAPPS_H 23 | 24 | #include 25 | 26 | #include "xdgmacros.h" 27 | 28 | class XdgDesktopFile; 29 | class XdgMimeAppsPrivate; 30 | 31 | class QString; 32 | 33 | /*! 34 | * \brief The XdgMimeApps class 35 | */ 36 | class QTXDG_API XdgMimeApps : public QObject { 37 | Q_OBJECT 38 | Q_DISABLE_COPY(XdgMimeApps) 39 | Q_DECLARE_PRIVATE(XdgMimeApps) 40 | 41 | public: 42 | /*! 43 | * \brief XdgMimeApps constructor 44 | */ 45 | explicit XdgMimeApps(QObject *parent = nullptr); 46 | 47 | /*! 48 | * \brief XdgMimeApps destructor 49 | */ 50 | ~XdgMimeApps() override; 51 | 52 | /*! 53 | * \brief addSupport 54 | * \param mimeType 55 | * \param app 56 | * \return 57 | */ 58 | bool addSupport(const QString &mimeType, const XdgDesktopFile &app); 59 | 60 | /*! 61 | * \brief allApps 62 | * \return 63 | */ 64 | QList allApps(); 65 | 66 | /*! 67 | * \brief apps 68 | * \param mimeType 69 | * \return 70 | */ 71 | QList apps(const QString &mimeType); 72 | 73 | /*! 74 | * \brief categoryApps 75 | * \param category 76 | * \return 77 | */ 78 | QList categoryApps(const QString &category); 79 | 80 | /*! 81 | * \brief fallbackApps 82 | * \param mimeType 83 | * \return 84 | */ 85 | QList fallbackApps(const QString &mimeType); 86 | 87 | /*! 88 | * \brief recommendedApps 89 | * \param mimeType 90 | * \return 91 | */ 92 | QList recommendedApps(const QString &mimeType); 93 | 94 | /*! 95 | * \brief defaultApp 96 | * \param mimeType 97 | * \return 98 | */ 99 | XdgDesktopFile *defaultApp(const QString &mimeType); 100 | 101 | /*! 102 | * \brief removeSupport 103 | * \param mimeType 104 | * \param app 105 | * \return 106 | */ 107 | bool removeSupport(const QString &mimeType, const XdgDesktopFile &app); 108 | 109 | /*! 110 | * \brief reset 111 | * \param mimeType 112 | * \return 113 | */ 114 | bool reset(const QString &mimeType); 115 | 116 | /*! 117 | * \brief setDefaultApp 118 | * \param mimeType 119 | * \param app 120 | * \return 121 | */ 122 | bool setDefaultApp(const QString &mimeType, const XdgDesktopFile &app); 123 | 124 | Q_SIGNALS: 125 | void changed(); 126 | }; 127 | 128 | #endif // XDGMIMEAPPS_H 129 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeapps_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef XDGMIMEAPPS_P_H 22 | #define XDGMIMEAPPS_P_H 23 | 24 | #include 25 | #include 26 | 27 | class XdgMimeApps; 28 | class XdgMimeAppsBackendInterface; 29 | 30 | class Q_DECL_HIDDEN XdgMimeAppsPrivate : public QObjectPrivate { 31 | Q_DECLARE_PUBLIC(XdgMimeApps) 32 | 33 | public: 34 | XdgMimeAppsPrivate(); 35 | ~XdgMimeAppsPrivate(); 36 | 37 | void init(); 38 | static XdgMimeAppsPrivate *instance(); 39 | 40 | QMutex mutex; 41 | XdgMimeAppsBackendInterface *mBackend; 42 | }; 43 | 44 | #endif // XDGMIMEAPPS_P_H 45 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeappsbackendinterface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "xdgmimeappsbackendinterface.h" 22 | 23 | XdgMimeAppsBackendInterface::XdgMimeAppsBackendInterface(QObject *parent) 24 | : QObject(parent) 25 | { 26 | } 27 | 28 | XdgMimeAppsBackendInterface::~XdgMimeAppsBackendInterface() = default; 29 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeappsbackendinterface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef XDGMIMEAPPSBACKENDINTERFACE_H 22 | #define XDGMIMEAPPSBACKENDINTERFACE_H 23 | 24 | #include 25 | 26 | class XdgDesktopFile; 27 | 28 | class QString; 29 | 30 | class XdgMimeAppsBackendInterface : public QObject { 31 | Q_OBJECT 32 | 33 | public: 34 | explicit XdgMimeAppsBackendInterface(QObject *parent); 35 | virtual ~XdgMimeAppsBackendInterface(); 36 | 37 | virtual bool addAssociation(const QString &mimeType, const XdgDesktopFile &app) = 0; 38 | virtual QList allApps() = 0; 39 | virtual QList apps(const QString &mimeType) = 0; 40 | virtual XdgDesktopFile *defaultApp(const QString &mimeType) = 0; 41 | virtual QList fallbackApps(const QString &mimeType) = 0; 42 | virtual QList recommendedApps(const QString &mimeType) = 0; 43 | virtual bool reset(const QString &mimeType) = 0; 44 | virtual bool removeAssociation(const QString &mimeType, const XdgDesktopFile &app) = 0; 45 | virtual bool setDefaultApp(const QString &mimeType, const XdgDesktopFile &app) = 0; 46 | 47 | Q_SIGNALS: 48 | void changed(); 49 | }; 50 | 51 | #endif // XDGMIMEAPPSBACKENDINTERFACE_H 52 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeappsglibbackend.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "xdgmimeappsglibbackend.h" 22 | #include "xdgmimeapps.h" 23 | 24 | #include "qtxdglogging.h" 25 | #include "xdgdesktopfile.h" 26 | #include "xdgdirs.h" 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | static QList GAppInfoGListToXdgDesktopQList(GList *list) 36 | { 37 | QList dl; 38 | for (GList *l = list; l != nullptr; l = l->next) { 39 | if (l->data) { 40 | const QString file = QString::fromUtf8(g_desktop_app_info_get_filename(G_DESKTOP_APP_INFO(l->data))); 41 | if (!file.isEmpty()) { 42 | XdgDesktopFile *df = new XdgDesktopFile; 43 | if (df->load(file) && df->isValid()) { 44 | dl.append(df); 45 | } else { 46 | delete df; 47 | } 48 | } 49 | } 50 | } 51 | return dl; 52 | } 53 | 54 | static GDesktopAppInfo *XdgDesktopFileToGDesktopAppinfo(const XdgDesktopFile &app) 55 | { 56 | GDesktopAppInfo *gApp = g_desktop_app_info_new_from_filename(app.fileName().toUtf8().constData()); 57 | if (gApp == nullptr) { 58 | qCWarning(QtXdgMimeAppsGLib, "Failed to load GDesktopAppInfo for '%s'", 59 | qPrintable(app.fileName())); 60 | return nullptr; 61 | } 62 | return gApp; 63 | } 64 | 65 | XdgMimeAppsGLibBackend::XdgMimeAppsGLibBackend(QObject *parent) 66 | : XdgMimeAppsBackendInterface(parent), 67 | mWatcher(nullptr) 68 | { 69 | // Make sure that we have glib support enabled. 70 | qunsetenv("QT_NO_GLIB"); 71 | 72 | // This is a trick to init the database. Without it, the changed signal 73 | // functionality doesn't work properly. Also make sure optimizaters can't 74 | // make it go away. 75 | volatile GAppInfo *fooApp = g_app_info_get_default_for_type("foo", FALSE); 76 | if (fooApp) 77 | g_object_unref(G_APP_INFO(fooApp)); 78 | 79 | mWatcher = g_app_info_monitor_get(); 80 | if (mWatcher != nullptr) { 81 | g_signal_connect (mWatcher, "changed", G_CALLBACK (_changed), this); 82 | } 83 | } 84 | 85 | XdgMimeAppsGLibBackend::~XdgMimeAppsGLibBackend() 86 | { 87 | g_object_unref(mWatcher); 88 | } 89 | 90 | void XdgMimeAppsGLibBackend::_changed(GAppInfoMonitor *monitor, XdgMimeAppsGLibBackend *_this) 91 | { 92 | Q_UNUSED(monitor); 93 | Q_EMIT _this->changed(); 94 | } 95 | 96 | bool XdgMimeAppsGLibBackend::addAssociation(const QString &mimeType, const XdgDesktopFile &app) 97 | { 98 | GDesktopAppInfo *gApp = XdgDesktopFileToGDesktopAppinfo(app); 99 | if (gApp == nullptr) 100 | return false; 101 | 102 | GError *error = nullptr; 103 | if (g_app_info_add_supports_type(G_APP_INFO(gApp), 104 | mimeType.toUtf8().constData(), &error) == FALSE) { 105 | qCWarning(QtXdgMimeAppsGLib, "Failed to associate '%s' with '%s'. %s", 106 | qPrintable(mimeType), g_desktop_app_info_get_filename(gApp), error->message); 107 | 108 | g_error_free(error); 109 | g_object_unref(gApp); 110 | return false; 111 | } 112 | g_object_unref(gApp); 113 | return true; 114 | } 115 | 116 | QList XdgMimeAppsGLibBackend::allApps() 117 | { 118 | GList *list = g_app_info_get_all(); 119 | QList dl = GAppInfoGListToXdgDesktopQList(list); 120 | g_list_free_full(list, g_object_unref); 121 | return dl; 122 | } 123 | 124 | QList XdgMimeAppsGLibBackend::apps(const QString &mimeType) 125 | { 126 | GList *list = g_app_info_get_all_for_type(mimeType.toUtf8().constData()); 127 | QList dl = GAppInfoGListToXdgDesktopQList(list); 128 | g_list_free_full(list, g_object_unref); 129 | return dl; 130 | } 131 | 132 | QList XdgMimeAppsGLibBackend::fallbackApps(const QString &mimeType) 133 | { 134 | // g_app_info_get_fallback_for_type() doesn't returns the ones in the 135 | // recommended list 136 | GList *list = g_app_info_get_fallback_for_type(mimeType.toUtf8().constData()); 137 | QList dl = GAppInfoGListToXdgDesktopQList(list); 138 | g_list_free_full(list, g_object_unref); 139 | return dl; 140 | } 141 | 142 | QList XdgMimeAppsGLibBackend::recommendedApps(const QString &mimeType) 143 | { 144 | GList *list = g_app_info_get_recommended_for_type(mimeType.toUtf8().constData()); 145 | QList dl = GAppInfoGListToXdgDesktopQList(list); 146 | g_list_free_full(list, g_object_unref); 147 | return dl; 148 | } 149 | 150 | bool XdgMimeAppsGLibBackend::removeAssociation(const QString &mimeType, const XdgDesktopFile &app) 151 | { 152 | GDesktopAppInfo *gApp = XdgDesktopFileToGDesktopAppinfo(app); 153 | if (gApp == nullptr) 154 | return false; 155 | 156 | GError *error = nullptr; 157 | if (g_app_info_remove_supports_type(G_APP_INFO(gApp), 158 | mimeType.toUtf8().constData(), &error) == FALSE) { 159 | qCWarning(QtXdgMimeAppsGLib, "Failed to remove association between '%s' and '%s'. %s", 160 | qPrintable(mimeType), g_desktop_app_info_get_filename(gApp), error->message); 161 | 162 | g_error_free(error); 163 | g_object_unref(gApp); 164 | return false; 165 | } 166 | g_object_unref(gApp); 167 | return true; 168 | } 169 | 170 | bool XdgMimeAppsGLibBackend::reset(const QString &mimeType) 171 | { 172 | g_app_info_reset_type_associations(mimeType.toUtf8().constData()); 173 | return true; 174 | } 175 | 176 | XdgDesktopFile *XdgMimeAppsGLibBackend::defaultApp(const QString &mimeType) 177 | { 178 | GAppInfo *appinfo = g_app_info_get_default_for_type(mimeType.toUtf8().constData(), false); 179 | if (appinfo == nullptr || !G_IS_DESKTOP_APP_INFO(appinfo)) { 180 | return nullptr; 181 | } 182 | 183 | const char *file = g_desktop_app_info_get_filename(G_DESKTOP_APP_INFO(appinfo)); 184 | 185 | if (file == nullptr) { 186 | g_object_unref(appinfo); 187 | return nullptr; 188 | } 189 | 190 | const QString s = QString::fromUtf8(file); 191 | g_object_unref(appinfo); 192 | 193 | XdgDesktopFile *f = new XdgDesktopFile; 194 | if (f->load(s) && f->isValid()) 195 | return f; 196 | 197 | delete f; 198 | return nullptr; 199 | } 200 | 201 | bool XdgMimeAppsGLibBackend::setDefaultApp(const QString &mimeType, const XdgDesktopFile &app) 202 | { 203 | // NOTE: "g_app_info_set_as_default_for_type()" writes to "~/.config/mimeapps.list" 204 | // but we want to set the default app only for the DE (e.g., LXQt). 205 | 206 | if (!addAssociation(mimeType, app)) 207 | return false; 208 | 209 | GDesktopAppInfo *gApp = XdgDesktopFileToGDesktopAppinfo(app); 210 | if (gApp == nullptr) 211 | return false; 212 | 213 | // first find the DE's mimeapps list file 214 | QByteArray mimeappsList = "mimeapps.list"; 215 | QList desktopsList = qgetenv("XDG_CURRENT_DESKTOP").toLower().split(':'); 216 | if (!desktopsList.isEmpty()) { 217 | mimeappsList = desktopsList.at(0) + "-" + mimeappsList; 218 | } 219 | char *mimeappsListPath = g_build_filename(XdgDirs::configHome(true).toUtf8().constData(), 220 | mimeappsList.constData(), 221 | nullptr); 222 | 223 | const char *desktop_id = g_app_info_get_id(G_APP_INFO(gApp)); 224 | GKeyFile *kf = g_key_file_new(); 225 | g_key_file_load_from_file(kf, mimeappsListPath, G_KEY_FILE_NONE, nullptr); 226 | g_key_file_set_string(kf, "Default Applications", mimeType.toUtf8().constData(), desktop_id); 227 | GError *error = nullptr; 228 | if (g_key_file_save_to_file(kf, mimeappsListPath, &error) == false) { 229 | qCWarning(QtXdgMimeAppsGLib, "Failed to set '%s' as the default for '%s'. %s", 230 | g_desktop_app_info_get_filename(gApp), qPrintable(mimeType), error->message); 231 | g_error_free(error); 232 | g_key_file_free(kf); 233 | g_free(mimeappsListPath); 234 | g_object_unref(gApp); 235 | return false; 236 | } 237 | g_key_file_free(kf); 238 | g_free(mimeappsListPath); 239 | 240 | qCDebug(QtXdgMimeAppsGLib, "Set '%s' as the default for '%s'", 241 | g_desktop_app_info_get_filename(gApp), qPrintable(mimeType)); 242 | 243 | g_object_unref(gApp); 244 | return true; 245 | } 246 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimeappsglibbackend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2018 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef XDGMIMEAPPSGLIBBACKEND_H 22 | #define XDGMIMEAPPSGLIBBACKEND_H 23 | 24 | #include "xdgmimeappsbackendinterface.h" 25 | 26 | class XdgDesktopFile; 27 | 28 | class QString; 29 | 30 | typedef struct _GAppInfoMonitor GAppInfoMonitor; 31 | 32 | class Q_DECL_HIDDEN XdgMimeAppsGLibBackend : public XdgMimeAppsBackendInterface { 33 | public: 34 | XdgMimeAppsGLibBackend(QObject *parent); 35 | ~XdgMimeAppsGLibBackend() override; 36 | 37 | bool addAssociation(const QString &mimeType, const XdgDesktopFile &app) override; 38 | QList allApps() override; 39 | QList apps(const QString &mimeType) override; 40 | XdgDesktopFile *defaultApp(const QString &mimeType) override; 41 | QList fallbackApps(const QString &mimeType) override; 42 | QList recommendedApps(const QString &mimeType) override; 43 | bool removeAssociation(const QString &mimeType, const XdgDesktopFile &app) override; 44 | bool reset(const QString &mimeType) override; 45 | bool setDefaultApp(const QString &mimeType, const XdgDesktopFile &app) override; 46 | 47 | private: 48 | GAppInfoMonitor *mWatcher; 49 | static void _changed(GAppInfoMonitor *monitor, XdgMimeAppsGLibBackend *_this); 50 | }; 51 | 52 | #endif // XDGMIMEAPPSGLIBBACKEND_H 53 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimetype.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2014 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "xdgmimetype.h" 22 | 23 | #include "xdgicon.h" 24 | 25 | #include 26 | 27 | class XdgMimeTypePrivate : public QSharedData { 28 | public: 29 | XdgMimeTypePrivate(); 30 | XdgMimeTypePrivate(const XdgMimeType& other); 31 | 32 | void computeIconName(); 33 | 34 | QString iconName; 35 | bool computed; 36 | }; 37 | 38 | 39 | XdgMimeTypePrivate::XdgMimeTypePrivate() 40 | : computed(false) 41 | { 42 | } 43 | 44 | 45 | XdgMimeTypePrivate::XdgMimeTypePrivate(const XdgMimeType& other) 46 | : iconName(other.dx->iconName), 47 | computed(other.dx->computed) 48 | { 49 | } 50 | 51 | 52 | XdgMimeType::XdgMimeType() 53 | : QMimeType(), 54 | dx(new XdgMimeTypePrivate()) 55 | { 56 | } 57 | 58 | 59 | XdgMimeType::XdgMimeType(const QMimeType& mime) 60 | : QMimeType(mime), 61 | dx(new XdgMimeTypePrivate()) 62 | { 63 | } 64 | 65 | 66 | XdgMimeType::XdgMimeType(const XdgMimeType& mime) 67 | : QMimeType(mime), 68 | dx(mime.dx) 69 | { 70 | } 71 | 72 | 73 | XdgMimeType &XdgMimeType::operator=(const XdgMimeType &other) 74 | { 75 | QMimeType::operator =(other); 76 | 77 | if (dx != other.dx) 78 | dx = other.dx; 79 | 80 | return *this; 81 | } 82 | 83 | void XdgMimeType::swap(XdgMimeType &other) noexcept 84 | { 85 | QMimeType::swap(other); 86 | std::swap(dx, other.dx); 87 | } 88 | 89 | XdgMimeType::~XdgMimeType() = default; 90 | 91 | 92 | QString XdgMimeType::iconName() const 93 | { 94 | if (dx->computed) { 95 | return dx->iconName; 96 | } else { 97 | dx->iconName.clear(); 98 | QStringList names; 99 | 100 | names.append(QMimeType::iconName()); 101 | names.append(QMimeType::genericIconName()); 102 | 103 | for (const QString &s : std::as_const(names)) { 104 | if (!XdgIcon::fromTheme(s).isNull()) { 105 | dx->iconName = s; 106 | break; 107 | } 108 | } 109 | dx->computed = true; 110 | return dx->iconName; 111 | } 112 | } 113 | 114 | 115 | QIcon XdgMimeType::icon() const 116 | { 117 | return XdgIcon::fromTheme((iconName())); 118 | } 119 | -------------------------------------------------------------------------------- /src/qtxdg/xdgmimetype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2014 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef QTXDG_MIMETYPE_H 22 | #define QTXDG_MIMETYPE_H 23 | 24 | #include "xdgmacros.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | class XdgMimeTypePrivate; 33 | 34 | //! Describes types of file or data, represented by a MIME type string. 35 | /*! This class is an QMimeType descendent. The differences are the icon() and 36 | * iconName() methods. @see icon() @see iconName() 37 | * 38 | * Some parts of the documentation are based on QMimeType documentation. 39 | * @see http://qt-project.org/doc/qt-5/qmimetype.html 40 | * 41 | * @author Luís Pereira (luis.artur.pereira@gmail.com) 42 | */ 43 | 44 | class QTXDG_API XdgMimeType : public QMimeType { 45 | public: 46 | 47 | /*! Constructs an XdgMimeType object initialized with default property 48 | values that indicate an invalid MIME type. 49 | @see QMimeType::QMimeType() 50 | */ 51 | XdgMimeType(); 52 | 53 | /*! Constructs an XdgMimeType object from an QMimeType object 54 | * @see QMimeType 55 | */ 56 | XdgMimeType(const QMimeType& mime); 57 | 58 | //! Constructs an XdgMimeType object from another XdgMimeType object 59 | XdgMimeType(const XdgMimeType& mime); 60 | 61 | /*! Assigns the data of other to this XdgMimeType object. 62 | * @return a reference to this object. 63 | */ 64 | XdgMimeType &operator=(const XdgMimeType &other); 65 | 66 | 67 | /*! Compares the other XdgMimeType object to this XdgMimeType object. 68 | * @return true if other equals this XdgMimeType object, otherwise returns 69 | * false. The name is the unique identifier for a mimetype, so two mimetypes 70 | * with the same name, are equal. 71 | * @see QMimeType::operator==() 72 | */ 73 | bool operator==(const XdgMimeType &other) const 74 | { 75 | return name() == other.name(); 76 | } 77 | 78 | inline bool operator!=(const XdgMimeType &other) const 79 | { 80 | return !operator==(other); 81 | } 82 | 83 | void swap(XdgMimeType &other) noexcept; 84 | 85 | //! Destructs the mimetype 86 | ~XdgMimeType(); 87 | 88 | //! Returns the name of the MIME type. 89 | /*! The same as QMimeType::name(). Provided for compatibilty with deprecated 90 | * XdgMimeInfo::mimeType(). 91 | * @see QMimeType::name() 92 | */ 93 | inline QString mimeType() const { return QMimeType::name(); } 94 | 95 | //! Returns an icon associated with the mimetype. 96 | /*! @return an icon from the current icon theme associated with the 97 | * mimetype. If the icon theme doesn't provide one it returns QIcon(). 98 | * It gets the icon name from iconName() and then gives it to 99 | * XdgIcon::fromTheme(). 100 | * @see iconName() @see XdgIcon::fromTheme() 101 | */ 102 | QIcon icon() const; 103 | 104 | //! Returns an icon name associated with the mimetype. 105 | /*! @return an icon name from the current icon theme associated with the 106 | * mimetype. If the current icon theme doesn't provide one, it returns an 107 | * empty QString. 108 | * The returned icon name is suitable to be given to XdgIcon::fromTheme() 109 | * to load the icon. 110 | * @see XdgIcon::fromTheme() 111 | */ 112 | QString iconName() const; 113 | 114 | protected: 115 | friend class XdgMimeTypePrivate; 116 | QExplicitlySharedDataPointer dx; 117 | 118 | 119 | }; 120 | Q_DECLARE_SHARED(XdgMimeType) 121 | 122 | #endif // QTXDG_MIMETYPE_H 123 | -------------------------------------------------------------------------------- /src/qtxdg/xmlhelper.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | 29 | #include "xmlhelper.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | QDebug operator<<(QDebug dbg, const QDomElement &el) 37 | { 38 | QDomNamedNodeMap map = el.attributes(); 39 | 40 | QString args; 41 | for (int i=0; i%3").arg(el.tagName(), args, el.text()); 45 | return dbg.space(); 46 | } 47 | -------------------------------------------------------------------------------- /src/qtxdg/xmlhelper.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2010-2011 Razor team 8 | * Authors: 9 | * Alexander Sokoloff 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #ifndef QTXDG_XMLHELPER_H 29 | #define QTXDG_XMLHELPER_H 30 | 31 | #include "xdgmacros.h" 32 | #include 33 | #include 34 | #include 35 | 36 | class QTXDG_API DomElementIterator 37 | { 38 | public: 39 | explicit DomElementIterator(const QDomNode& parentNode, const QString& tagName = QString()) 40 | : mTagName(tagName), 41 | mParent(parentNode) 42 | { 43 | toFront(); 44 | } 45 | 46 | void toFront() 47 | { 48 | mNext = mParent.firstChildElement(mTagName); 49 | } 50 | 51 | bool hasNext() 52 | { 53 | return (!mNext.isNull()); 54 | } 55 | 56 | const QDomElement& next() 57 | { 58 | mCur = mNext; 59 | mNext = mNext.nextSiblingElement(mTagName); 60 | return mCur; 61 | } 62 | 63 | 64 | void toBack() 65 | { 66 | mNext = mParent.lastChildElement(mTagName); 67 | } 68 | 69 | 70 | bool hasPrevious() 71 | { 72 | return (!mNext.isNull()); 73 | } 74 | 75 | const QDomElement& previous() 76 | { 77 | mCur = mNext; 78 | mNext = mNext.previousSiblingElement(mTagName); 79 | return mCur; 80 | } 81 | 82 | const QDomElement& current() const 83 | { 84 | return mCur; 85 | } 86 | 87 | 88 | private: 89 | QString mTagName; 90 | QDomNode mParent; 91 | QDomElement mCur; 92 | QDomElement mNext; 93 | }; 94 | 95 | class MutableDomElementIterator 96 | { 97 | public: 98 | explicit MutableDomElementIterator(QDomNode& parentNode, const QString& tagName = QString()) 99 | : mTagName(tagName), 100 | mParent(parentNode) 101 | { 102 | toFront(); 103 | } 104 | 105 | void toFront() 106 | { 107 | mNext = mParent.firstChildElement(mTagName); 108 | } 109 | 110 | bool hasNext() 111 | { 112 | return (!mNext.isNull()); 113 | } 114 | 115 | QDomElement& next() 116 | { 117 | mCur = mNext; 118 | mNext = mNext.nextSiblingElement(mTagName); 119 | return mCur; 120 | } 121 | 122 | 123 | void toBack() 124 | { 125 | mNext = mParent.lastChildElement(mTagName); 126 | } 127 | 128 | 129 | bool hasPrevious() 130 | { 131 | return (!mNext.isNull()); 132 | } 133 | 134 | QDomElement& previous() 135 | { 136 | mCur = mNext; 137 | mNext = mNext.previousSiblingElement(mTagName); 138 | return mCur; 139 | } 140 | 141 | QDomElement& current() 142 | { 143 | return mCur; 144 | } 145 | 146 | 147 | private: 148 | QString mTagName; 149 | QDomNode mParent; 150 | QDomElement mCur; 151 | QDomElement mNext; 152 | }; 153 | 154 | 155 | 156 | 157 | 158 | QDebug operator<<(QDebug dbg, const QDomElement &el); 159 | 160 | 161 | #endif // QTXDG_XMLHELPER_H 162 | -------------------------------------------------------------------------------- /src/xdgiconloader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(xdgiconloader_PUBLIC_H_FILES 2 | ) 3 | 4 | set(xdgiconloader_PUBLIC_CLASSES 5 | ) 6 | 7 | set(xdgiconloader_PRIVATE_H_FILES 8 | ) 9 | 10 | set(xdgiconloader_CPP_FILES 11 | xdgiconloader.cpp 12 | ) 13 | 14 | set(xdgiconloader_PRIVATE_INSTALLABLE_H_FILES 15 | xdgiconloader_p.h 16 | ) 17 | 18 | 19 | add_library(${QTXDGX_ICONLOADER_LIBRARY_NAME} SHARED 20 | ${xdgiconloader_CPP_FILES} 21 | ${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES} 22 | ) 23 | 24 | generate_export_header(${QTXDGX_ICONLOADER_LIBRARY_NAME} BASE_NAME XdgIconLoader) 25 | 26 | # Copy public headers (in tree building) 27 | set(XDGICONLOADER_EXPORT_FILE "xdgiconloader_export.h") 28 | configure_file( 29 | "${CMAKE_CURRENT_BINARY_DIR}/${XDGICONLOADER_EXPORT_FILE}" 30 | "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${XDGICONLOADER_EXPORT_FILE}" 31 | COPYONLY 32 | ) 33 | 34 | target_compile_definitions(${QTXDGX_ICONLOADER_LIBRARY_NAME} 35 | PRIVATE 36 | "QT_NO_KEYWORDS" 37 | ) 38 | 39 | target_include_directories(${QTXDGX_ICONLOADER_LIBRARY_NAME} 40 | INTERFACE 41 | "$" 42 | "$" 43 | "$" 44 | PUBLIC 45 | "$" 46 | "$" 47 | "$" 48 | PRIVATE 49 | ${Qt6Gui_PRIVATE_INCLUDE_DIRS} 50 | ) 51 | 52 | target_link_libraries(${QTXDGX_ICONLOADER_LIBRARY_NAME} 53 | PUBLIC 54 | Qt6::Gui 55 | Qt6::Svg 56 | ) 57 | 58 | set_target_properties(${QTXDGX_ICONLOADER_LIBRARY_NAME} 59 | PROPERTIES 60 | VERSION ${QTXDG_VERSION_STRING} 61 | SOVERSION ${QTXDG_MAJOR_VERSION} 62 | ) 63 | 64 | add_subdirectory(plugin) 65 | 66 | install(TARGETS 67 | ${QTXDGX_ICONLOADER_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}" 68 | EXPORT "${QTXDGX_ICONLOADER_FILE_NAME}-targets" 69 | COMPONENT Runtime 70 | ) 71 | 72 | install(FILES 73 | ${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES} 74 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}/private/xdgiconloader" 75 | COMPONENT Devel 76 | ) 77 | 78 | file(COPY 79 | ${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES} 80 | DESTINATION "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}/private/xdgiconloader" 81 | ) 82 | 83 | install(FILES 84 | "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${XDGICONLOADER_EXPORT_FILE}" 85 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}" 86 | ) 87 | -------------------------------------------------------------------------------- /src/xdgiconloader/plugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(xdgiconengineplugin_CPP_FILES 2 | xdgiconengineplugin.cpp 3 | ) 4 | 5 | add_library(${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME} MODULE 6 | ${xdgiconengineplugin_CPP_FILES} 7 | ) 8 | 9 | target_compile_definitions(${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME} 10 | PRIVATE 11 | "QT_NO_KEYWORDS" 12 | ) 13 | target_link_libraries(${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME} 14 | PUBLIC 15 | Qt6::Gui 16 | "${QTXDGX_ICONLOADER_LIBRARY_NAME}" 17 | ) 18 | 19 | target_include_directories("${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME}" 20 | PRIVATE 21 | "${Qt6Gui_PRIVATE_INCLUDE_DIRS}" 22 | ) 23 | 24 | mark_as_advanced(QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH) 25 | 26 | if (NOT DEFINED QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH) 27 | include(LXQtQueryQt) 28 | lxqt_query_qt(_QT_PLUGINS_DIR QT_INSTALL_PLUGINS) 29 | 30 | if (NOT _QT_PLUGINS_DIR) 31 | message(FATAL_ERROR "Qt6 plugin directory cannot be detected.") 32 | endif() 33 | set(QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH "${_QT_PLUGINS_DIR}/iconengines") 34 | endif() 35 | 36 | message(STATUS "XdgIconEnginePlugin will be installed into: ${QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH}") 37 | 38 | install(TARGETS 39 | "${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME}" DESTINATION "${QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH}" 40 | COMPONENT Runtime 41 | ) 42 | 43 | -------------------------------------------------------------------------------- /src/xdgiconloader/plugin/xdgiconengineplugin.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight Qt based desktop 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2017 LXQt team 8 | * Authors: 9 | * Palo Kisa 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include "xdgiconengineplugin.h" 29 | #include "../xdgiconloader_p.h" 30 | 31 | QIconEngine * XdgIconEnginePlugin::create(const QString & filename/* = QString{}*/) 32 | { 33 | return new XdgIconLoaderEngine{filename}; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/xdgiconloader/plugin/xdgiconengineplugin.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight Qt based desktop 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2017 LXQt team 8 | * Authors: 9 | * Palo Kisa 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include 29 | 30 | class XdgIconEnginePlugin : public QIconEnginePlugin 31 | { 32 | Q_OBJECT 33 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QIconEngineFactoryInterface" FILE "xdgiconengineplugin.json") 34 | public: 35 | using QIconEnginePlugin::QIconEnginePlugin; 36 | QIconEngine * create(const QString & filename = QString{}) override; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /src/xdgiconloader/plugin/xdgiconengineplugin.json: -------------------------------------------------------------------------------- 1 | {"Keys": ["XdgIconLoaderEngine"]} 2 | -------------------------------------------------------------------------------- /src/xdgiconloader/xdgiconloader_p.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). 4 | ** Contact: http://www.qt-project.org/legal 5 | ** 6 | ** This file is part of the QtGui module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL21$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and Digia. For licensing terms and 14 | ** conditions see http://qt.digia.com/licensing. For further information 15 | ** use the contact form at http://qt.digia.com/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 2.1 or version 3 as published by the Free 20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22 | ** following information to ensure the GNU Lesser General Public License 23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25 | ** 26 | ** In addition, as a special exception, Digia gives you certain additional 27 | ** rights. These rights are described in the Digia Qt LGPL Exception 28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29 | ** 30 | ** $QT_END_LICENSE$ 31 | ** 32 | ****************************************************************************/ 33 | 34 | #ifndef XDGICONLOADER_P_H 35 | #define XDGICONLOADER_P_H 36 | 37 | #include 38 | 39 | #ifndef QT_NO_ICON 40 | // 41 | // W A R N I N G 42 | // ------------- 43 | // 44 | // This file is not part of the Qt API. It exists purely as an 45 | // implementation detail. This header file may change from version to 46 | // version without notice, or even be removed. 47 | // 48 | // We mean it. 49 | // 50 | 51 | #include 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | //QT_BEGIN_NAMESPACE 61 | 62 | class XdgIconLoader; 63 | 64 | struct ScalableFollowsColorEntry : public QIconLoaderEngineEntry 65 | { 66 | #if (QT_VERSION >= QT_VERSION_CHECK(6,8,0)) 67 | QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override; 68 | #else 69 | QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; 70 | #endif 71 | QIcon svgIcon; 72 | }; 73 | 74 | //class QIconLoaderEngine : public QIconEngine 75 | class XDGICONLOADER_EXPORT XdgIconLoaderEngine : public QIconEngine 76 | { 77 | public: 78 | XdgIconLoaderEngine(const QString& iconName = QString()); 79 | ~XdgIconLoaderEngine() override; 80 | 81 | void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; 82 | QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; 83 | QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; 84 | QIconEngine *clone() const override; 85 | bool read(QDataStream &in) override; 86 | bool write(QDataStream &out) const override; 87 | 88 | QString iconName() override; 89 | bool isNull() override; 90 | QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override; 91 | QList availableSizes(QIcon::Mode mode, QIcon::State state) override; 92 | 93 | private: 94 | QString key() const override; 95 | bool hasIcon() const; 96 | void ensureLoaded(); 97 | QIconLoaderEngineEntry *entryForSize(const QThemeIconInfo &info, const QSize &size, int scale = 1); 98 | XdgIconLoaderEngine(const XdgIconLoaderEngine &other); 99 | QThemeIconInfo m_info; 100 | QString m_iconName; 101 | uint m_key; 102 | 103 | friend class XdgIconLoader; 104 | }; 105 | 106 | class QIconCacheGtkReader; 107 | 108 | // Note: We can't simply reuse the QIconTheme from Qt > 5.7 because 109 | // the QIconTheme constructor symbol isn't exported. 110 | class XdgIconTheme 111 | { 112 | public: 113 | XdgIconTheme(const QString &name); 114 | XdgIconTheme() = default; 115 | QStringList parents() { return m_parents; } 116 | QList keyList() { return m_keyList; } 117 | QStringList contentDirs() { return m_contentDirs; } 118 | bool isValid() const { return m_valid; } 119 | bool followsColorScheme() const { return m_followsColorScheme; } 120 | private: 121 | QStringList m_contentDirs; 122 | QList m_keyList; 123 | QStringList m_parents; 124 | bool m_valid = false; 125 | bool m_followsColorScheme = false; 126 | public: 127 | QList> m_gtkCaches; 128 | }; 129 | 130 | class XDGICONLOADER_EXPORT XdgIconLoader 131 | { 132 | public: 133 | QThemeIconInfo loadIcon(const QString &iconName) const; 134 | 135 | /* TODO: deprecate & remove all QIconLoader wrappers */ 136 | inline uint themeKey() const { return QIconLoader::instance()->themeKey(); } 137 | inline QString themeName() const { return QIconLoader::instance()->themeName(); } 138 | inline void setThemeName(const QString &themeName) { QIconLoader::instance()->setThemeName(themeName); } 139 | inline void setThemeSearchPath(const QStringList &searchPaths) { QIconLoader::instance()->setThemeSearchPath(searchPaths); } 140 | inline QIconDirInfo dirInfo(int dirindex) { return QIconLoader::instance()->dirInfo(dirindex); } 141 | inline QStringList themeSearchPaths() const { return QIconLoader::instance()->themeSearchPaths(); } 142 | inline void updateSystemTheme() { QIconLoader::instance()->updateSystemTheme(); } 143 | inline void invalidateKey() { QIconLoader::instance()->invalidateKey(); } 144 | inline void ensureInitialized() { QIconLoader::instance()->ensureInitialized(); } 145 | inline bool hasUserTheme() const { return QIconLoader::instance()->hasUserTheme(); } 146 | /*! 147 | * Flag if the "FollowsColorScheme" hint (the KDE extension to XDG 148 | * themes) should be honored. 149 | */ 150 | inline bool followColorScheme() const { return m_followColorScheme; } 151 | void setFollowColorScheme(bool enable); 152 | 153 | XdgIconTheme theme() { return themeList.value(QIconLoader::instance()->themeName()); } 154 | static XdgIconLoader *instance(); 155 | 156 | private: 157 | QThemeIconInfo findIconHelper(const QString &themeName, 158 | const QString &iconName, 159 | QStringList &visited, 160 | bool dashFallback = false) const; 161 | QThemeIconInfo unthemedFallback(const QString &iconName, const QStringList &searchPaths) const; 162 | mutable QHash themeList; 163 | bool m_followColorScheme = true; 164 | }; 165 | 166 | #endif // QT_NO_ICON 167 | 168 | #endif // XDGICONLOADER_P_H 169 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | remove_definitions( 2 | -DQT_USE_QSTRINGBUILDER 3 | -DQT_NO_CAST_FROM_ASCII 4 | ) 5 | 6 | add_definitions( 7 | -DQT_NO_KEYWORDS 8 | ) 9 | 10 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 11 | 12 | macro(qtxdg_add_test) 13 | foreach(_testname ${ARGN}) 14 | add_executable(${_testname} ${_testname}.cpp) 15 | target_link_libraries(${_testname} Qt6::Test ${QTXDGX_LIBRARY_NAME}) 16 | target_include_directories(${_testname} 17 | PRIVATE "${PROJECT_SOURCE_DIR}/src/qtxdg" 18 | ) 19 | add_test(NAME ${_testname} COMMAND ${_testname}) 20 | endforeach() 21 | endmacro() 22 | 23 | set_property(DIRECTORY APPEND 24 | PROPERTY COMPILE_DEFINITIONS "QTXDG_BUILDING_TESTS=\"1\"" 25 | ) 26 | 27 | qtxdg_add_test( 28 | qtxdg_test 29 | tst_xdgdirs 30 | tst_xdgdesktopfile 31 | ) 32 | -------------------------------------------------------------------------------- /test/qtxdg_test.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2013~2015 LXQt team 8 | * Authors: 9 | * Christian Surlykke 10 | * Jerome Leclanche 11 | * Luís Pereira 12 | * 13 | * This program or library is free software; you can redistribute it 14 | * and/or modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2.1 of the License, or (at your option) any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | 23 | * You should have received a copy of the GNU Lesser General 24 | * Public License along with this library; if not, write to the 25 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 | * Boston, MA 02110-1301 USA 27 | * 28 | * END_COMMON_COPYRIGHT_HEADER */ 29 | 30 | 31 | #include "qtxdg_test.h" 32 | 33 | #include "xdgdesktopfile.h" 34 | #include "xdgdesktopfile_p.h" 35 | #include "xdgdirs.h" 36 | #include "xdgmimeapps.h" 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | void QtXdgTest::testDefaultApp() 48 | { 49 | QStringList mimedirs = XdgDirs::dataDirs(); 50 | mimedirs.prepend(XdgDirs::dataHome(false)); 51 | for (const QString &mimedir : std::as_const(mimedirs)) 52 | { 53 | QDir dir(mimedir + QStringLiteral("/mime")); 54 | qDebug() << dir.path(); 55 | QStringList filters = (QStringList() << QStringLiteral("*.xml")); 56 | const QFileInfoList &mediaDirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); 57 | for (const QFileInfo &mediaDir : mediaDirs) 58 | { 59 | qDebug() << " " << mediaDir.fileName(); 60 | const QStringList mimeXmlFileNames = QDir(mediaDir.absoluteFilePath()).entryList(filters, QDir::Files); 61 | for (const QString &mimeXmlFileName : mimeXmlFileNames) 62 | { 63 | QString mimetype = mediaDir.fileName() + QLatin1Char('/') + mimeXmlFileName.left(mimeXmlFileName.length() - 4); 64 | QString xdg_utils_default = xdgUtilDefaultApp(mimetype); 65 | QString desktop_file_default = xdgDesktopFileDefaultApp(mimetype); 66 | 67 | if (xdg_utils_default != desktop_file_default) 68 | { 69 | qDebug() << mimetype; 70 | qDebug() << "xdg-mime query default:" << xdg_utils_default; 71 | qDebug() << "xdgdesktopfile default:" << desktop_file_default; 72 | } 73 | } 74 | } 75 | 76 | } 77 | } 78 | 79 | void QtXdgTest::compare(const QString &mimetype) 80 | { 81 | QString xdgUtilDefault = xdgUtilDefaultApp(mimetype); 82 | QString xdgDesktopDefault = xdgDesktopFileDefaultApp(mimetype); 83 | if (xdgUtilDefault != xdgDesktopDefault) 84 | { 85 | qDebug() << mimetype; 86 | qDebug() << "xdg-mime default:" << xdgUtilDefault; 87 | qDebug() << "xdgDesktopfile default:" << xdgDesktopDefault; 88 | } 89 | } 90 | 91 | 92 | void QtXdgTest::testTextHtml() 93 | { 94 | compare(QStringLiteral("text/html")); 95 | } 96 | 97 | void QtXdgTest::testMeldComparison() 98 | { 99 | compare(QStringLiteral("application/x-meld-comparison")); 100 | } 101 | 102 | void QtXdgTest::testCustomFormat() 103 | { 104 | QSettings::Format desktopFormat = QSettings::registerFormat(QStringLiteral("list"), readDesktopFile, writeDesktopFile); 105 | QFile::remove(QStringLiteral("/tmp/test.list")); 106 | QFile::remove(QStringLiteral("/tmp/test2.list")); 107 | QSettings test(QStringLiteral("/tmp/test.list"), desktopFormat); 108 | test.beginGroup(QStringLiteral("Default Applications")); 109 | test.setValue(QStringLiteral("text/plain"), QStringLiteral("gvim.desktop")); 110 | test.setValue(QStringLiteral("text/html"), QStringLiteral("firefox.desktop")); 111 | test.endGroup(); 112 | test.beginGroup(QStringLiteral("Other Applications")); 113 | test.setValue(QStringLiteral("application/pdf"), QStringLiteral("qpdfview.desktop")); 114 | test.setValue(QStringLiteral("image/svg+xml"), QStringLiteral("inkscape.desktop")); 115 | test.sync(); 116 | 117 | QFile::copy(QStringLiteral("/tmp/test.list"), QStringLiteral("/tmp/test2.list")); 118 | 119 | QSettings test2(QStringLiteral("/tmp/test2.list"), desktopFormat); 120 | QVERIFY(test2.allKeys().size() == 4); 121 | 122 | test2.beginGroup(QStringLiteral("Default Applications")); 123 | // qDebug() << test2.value("text/plain"); 124 | QVERIFY(test2.value(QStringLiteral("text/plain")).toString() == QLatin1String("gvim.desktop")); 125 | 126 | // qDebug() << test2.value("text/html"); 127 | QVERIFY(test2.value(QStringLiteral("text/html")).toString() == QLatin1String("firefox.desktop")); 128 | test2.endGroup(); 129 | 130 | test2.beginGroup(QStringLiteral("Other Applications")); 131 | // qDebug() << test2.value("application/pdf"); 132 | QVERIFY(test2.value(QStringLiteral("application/pdf")).toString() == QLatin1String("qpdfview.desktop")); 133 | 134 | // qDebug() << test2.value("image/svg+xml"); 135 | QVERIFY(test2.value(QStringLiteral("image/svg+xml")).toString() == QStringLiteral("inkscape.desktop")); 136 | test2.endGroup(); 137 | } 138 | 139 | 140 | QString QtXdgTest::xdgDesktopFileDefaultApp(const QString &mimetype) 141 | { 142 | XdgMimeApps appsDb; 143 | XdgDesktopFile *defaultApp = appsDb.defaultApp(mimetype); 144 | QString defaultAppS; 145 | if (defaultApp) 146 | { 147 | defaultAppS = QFileInfo(defaultApp->fileName()).fileName(); 148 | } 149 | return defaultAppS; 150 | } 151 | 152 | 153 | 154 | QString QtXdgTest::xdgUtilDefaultApp(const QString &mimetype) 155 | { 156 | QProcess xdg_mime; 157 | QString program = QStringLiteral("xdg-mime"); 158 | QStringList args = (QStringList() << QStringLiteral("query") << QStringLiteral("default") << mimetype); 159 | qDebug() << "running" << program << args.join(QLatin1Char(' ')); 160 | xdg_mime.start(program, args); 161 | xdg_mime.waitForFinished(1000); 162 | return QString::fromUtf8(xdg_mime.readAll()).trimmed(); 163 | } 164 | 165 | #if 0 166 | int main(int argc, char** args) 167 | { 168 | // QtXdgTest().testDefaultApp(); 169 | // qDebug() << "Default for text/html:" << QtXdgTest().xdgDesktopFileDefaultApp("text/html"); 170 | // QtXdgTest().testMeldComparison(); 171 | qDebug() << QtXdgTest().testCustomFormat(); 172 | }; 173 | #endif // 0 174 | 175 | QTEST_MAIN(QtXdgTest) 176 | -------------------------------------------------------------------------------- /test/qtxdg_test.h: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2013~2014 LXQt team 8 | * Authors: 9 | * Christian Surlykke 10 | * Luís Pereira 11 | * Jerome Leclanche 12 | * 13 | * This program or library is free software; you can redistribute it 14 | * and/or modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2.1 of the License, or (at your option) any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | 23 | * You should have received a copy of the GNU Lesser General 24 | * Public License along with this library; if not, write to the 25 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 | * Boston, MA 02110-1301 USA 27 | * 28 | * END_COMMON_COPYRIGHT_HEADER */ 29 | 30 | 31 | #ifndef QTXDG_TEST_H 32 | #define QTXDG_TEST_H 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | class QtXdgTest : public QObject 39 | { 40 | Q_OBJECT 41 | 42 | private Q_SLOTS: 43 | void testCustomFormat(); 44 | 45 | private: 46 | // Test that XdgDesktopFile and xdg-mime script agree on 47 | // default application for each mime-type. 48 | void testDefaultApp(); 49 | 50 | void testTextHtml(); 51 | void testMeldComparison(); 52 | void compare(const QString &mimetype); 53 | QString xdgDesktopFileDefaultApp(const QString &mimetype); 54 | QString xdgUtilDefaultApp(const QString &mimetype); 55 | 56 | }; 57 | 58 | #endif /* QTXDG_TEST_H */ 59 | -------------------------------------------------------------------------------- /test/tst_xdgdesktopfile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs. 3 | * Copyright (C) 2016 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | * 19 | */ 20 | 21 | #include "tst_xdgdesktopfile.h" 22 | #include "XdgDesktopFile" 23 | #include 24 | 25 | 26 | class Language 27 | { 28 | public: 29 | Language (const QString& lang) 30 | : mPreviousLang(QString::fromLocal8Bit(qgetenv("LC_MESSAGES"))) 31 | { 32 | qputenv("LC_MESSAGES", lang.toLocal8Bit()); 33 | } 34 | ~Language() 35 | { 36 | qputenv("LC_MESSAGES", mPreviousLang.toLocal8Bit()); 37 | } 38 | private: 39 | QString mPreviousLang; 40 | }; 41 | 42 | 43 | QTEST_MAIN(tst_xdgdesktopfile) 44 | 45 | void tst_xdgdesktopfile::testRead() 46 | { 47 | QTemporaryFile file(QDir::temp().filePath(QStringLiteral("testReadXXXXXX.desktop"))); 48 | QVERIFY(file.open()); 49 | const QString fileName = file.fileName(); 50 | QTextStream ts(&file); 51 | ts << 52 | "[Desktop Entry]\n" 53 | "Type=Application\n" 54 | "Name=MyApp\n" 55 | "Icon=foobar\n" 56 | "MimeType=text/plain;image/png;;\n" 57 | "\n"; 58 | file.close(); 59 | QVERIFY(QFile::exists(fileName)); 60 | 61 | XdgDesktopFile df; 62 | df.load(fileName); 63 | 64 | QVERIFY(df.isValid()); 65 | QCOMPARE(df.type(), XdgDesktopFile::ApplicationType); 66 | QCOMPARE(df.name(), QString::fromLatin1("MyApp")); 67 | QCOMPARE(df.iconName(), QString::fromLatin1("foobar")); 68 | QCOMPARE(df.mimeTypes(), QStringList() << QString::fromLatin1("text/plain") 69 | << QString::fromLatin1("image/png")); 70 | QCOMPARE(df.fileName(), QFileInfo(fileName).canonicalFilePath()); 71 | } 72 | 73 | void tst_xdgdesktopfile::testReadLocalized_data() 74 | { 75 | QTest::addColumn("locale"); 76 | QTest::addColumn("translation"); 77 | 78 | const QString pt = QString::fromUtf8("A Minha Aplicação"); 79 | const QString pt_BR = QString::fromUtf8("O Meu Aplicativo"); 80 | 81 | QTest::newRow("pt") << QStringLiteral("pt") << pt; 82 | QTest::newRow("pt_PT") << QStringLiteral("pt_PT") << pt; 83 | QTest::newRow("pt_BR") << QStringLiteral("pt_BR") << pt_BR; 84 | 85 | QTest::newRow("de") << QStringLiteral("de") << QStringLiteral("My Application"); 86 | } 87 | 88 | void tst_xdgdesktopfile::testReadLocalized() 89 | { 90 | QTemporaryFile file(QDir::temp().filePath(QStringLiteral("testReadLocalizedXXXXXX.desktop"))); 91 | QVERIFY(file.open()); 92 | const QString fileName = file.fileName(); 93 | QTextStream ts(&file); 94 | ts << QString::fromUtf8( 95 | "[Desktop Entry]\n" 96 | "Type=Application\n" 97 | "Name=My Application\n" 98 | "Name[pt]=A Minha Aplicação\n" 99 | "Name[pt_BR]=O Meu Aplicativo\n" 100 | "Icon=foo\n" 101 | "\n"); 102 | file.close(); 103 | 104 | QVERIFY(QFile::exists(fileName)); 105 | 106 | XdgDesktopFile df; 107 | df.load(fileName); 108 | QVERIFY(df.isValid()); 109 | 110 | QFETCH(QString, locale); 111 | QFETCH(QString, translation); 112 | 113 | Language lang(locale); 114 | 115 | QCOMPARE(df.localizedValue(QStringLiteral("Name")).toString(), translation); 116 | } 117 | -------------------------------------------------------------------------------- /test/tst_xdgdesktopfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs. 3 | * Copyright (C) 2016 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | * 19 | */ 20 | 21 | #ifndef TST_XDGDESKTOPFILE_H 22 | #define TST_XDGDESKTOPFILE_H 23 | 24 | #include 25 | 26 | class tst_xdgdesktopfile : public QObject { 27 | Q_OBJECT 28 | private Q_SLOTS: 29 | 30 | void testRead(); 31 | void testReadLocalized(); 32 | void testReadLocalized_data(); 33 | }; 34 | 35 | #endif // TST_XDGDESKTOPFILE_H 36 | -------------------------------------------------------------------------------- /test/tst_xdgdirs.cpp: -------------------------------------------------------------------------------- 1 | /* BEGIN_COMMON_COPYRIGHT_HEADER 2 | * (c)LGPL2+ 3 | * 4 | * LXQt - a lightweight, Qt based, desktop toolset 5 | * https://lxqt.org 6 | * 7 | * Copyright: 2015 LXQt team 8 | * Authors: 9 | * Luís Pereira 10 | * 11 | * This program or library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2.1 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | 21 | * You should have received a copy of the GNU Lesser General 22 | * Public License along with this library; if not, write to the 23 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 | * Boston, MA 02110-1301 USA 25 | * 26 | * END_COMMON_COPYRIGHT_HEADER */ 27 | 28 | #include 29 | 30 | #include "xdgdirs.h" 31 | 32 | #include 33 | #include 34 | 35 | class tst_xdgdirs : public QObject 36 | { 37 | Q_OBJECT 38 | 39 | private Q_SLOTS: 40 | void initTestCase(); 41 | void cleanupTestCase(); 42 | 43 | void testDataHome(); 44 | void testConfigHome(); 45 | void testDataDirs(); 46 | void testConfigDirs(); 47 | void testCacheHome(); 48 | void testAutostartHome(); 49 | void testAutostartDirs(); 50 | 51 | private: 52 | void setDefaultLocations(); 53 | void setCustomLocations(); 54 | 55 | QString m_configHome; 56 | QTemporaryDir m_configHomeTemp; 57 | QString m_configDirs; 58 | QTemporaryDir m_configDirsTemp; 59 | QString m_dataHome; 60 | QTemporaryDir m_dataHomeTemp; 61 | QString m_dataDirs; 62 | QTemporaryDir m_dataDirsTemp; 63 | QString m_cacheHome; 64 | QTemporaryDir m_cacheHomeTemp; 65 | }; 66 | 67 | void tst_xdgdirs::initTestCase() 68 | { 69 | QCoreApplication::instance()->setOrganizationName(QStringLiteral("QtXdg")); 70 | QCoreApplication::instance()->setApplicationName(QStringLiteral("tst_xdgdirs")); 71 | } 72 | 73 | void tst_xdgdirs::cleanupTestCase() 74 | { 75 | QCoreApplication::instance()->setOrganizationName(QString()); 76 | QCoreApplication::instance()->setApplicationName(QString()); 77 | } 78 | 79 | void tst_xdgdirs::setDefaultLocations() 80 | { 81 | qputenv("XDG_CONFIG_HOME", QByteArray()); 82 | qputenv("XDG_CONFIG_DIRS", QByteArray()); 83 | qputenv("XDG_DATA_HOME", QByteArray()); 84 | qputenv("XDG_DATA_DIRS", QByteArray()); 85 | qputenv("XDG_CACHE_HOME", QByteArray()); 86 | } 87 | 88 | void tst_xdgdirs::setCustomLocations() 89 | { 90 | m_configHome = m_configHomeTemp.path(); 91 | m_configDirs = m_configDirsTemp.path(); 92 | m_dataHome = m_dataHomeTemp.path(); 93 | m_dataDirs = m_dataDirsTemp.path(); 94 | m_cacheHome = m_cacheHomeTemp.path(); 95 | qputenv("XDG_CONFIG_HOME", QFile::encodeName(m_configHome)); 96 | qputenv("XDG_CONFIG_DIRS", QFile::encodeName(m_configDirs)); 97 | qputenv("XDG_DATA_HOME", QFile::encodeName(m_dataHome)); 98 | qputenv("XDG_DATA_DIRS", QFile::encodeName(m_dataDirs)); 99 | qputenv("XDG_CACHE_HOME", QFile::encodeName(m_cacheHome)); 100 | 101 | } 102 | 103 | void tst_xdgdirs::testDataHome() 104 | { 105 | setDefaultLocations(); 106 | const QString expectedDataHome = QDir::homePath() + QString::fromLatin1("/.local/share"); 107 | QCOMPARE(XdgDirs::dataHome(), expectedDataHome); 108 | QCOMPARE(XdgDirs::dataHome(false), expectedDataHome); 109 | 110 | setCustomLocations(); 111 | QCOMPARE(XdgDirs::dataHome(), m_dataHome); 112 | QCOMPARE(XdgDirs::dataHome(false), m_dataHome); 113 | } 114 | 115 | void tst_xdgdirs::testConfigHome() 116 | { 117 | setDefaultLocations(); 118 | const QString expectedConfigHome = QDir::homePath() + QString::fromLatin1("/.config"); 119 | QCOMPARE(XdgDirs::configHome(), expectedConfigHome); 120 | QCOMPARE(XdgDirs::configHome(false), expectedConfigHome); 121 | 122 | setCustomLocations(); 123 | QCOMPARE(XdgDirs::configHome(), m_configHome); 124 | QCOMPARE(XdgDirs::configHome(false), m_configHome); 125 | } 126 | 127 | void tst_xdgdirs::testDataDirs() 128 | { 129 | const QString postfix = QString::fromLatin1("/") + QCoreApplication::applicationName(); 130 | 131 | setDefaultLocations(); 132 | const QStringList dataDirs = XdgDirs::dataDirs(); 133 | QCOMPARE(dataDirs.count(), 2); 134 | QCOMPARE(dataDirs.at(0), QString::fromLatin1("/usr/local/share")); 135 | QCOMPARE(dataDirs.at(1), QString::fromLatin1("/usr/share")); 136 | 137 | const QStringList dataDirsWithPostfix = XdgDirs::dataDirs(postfix); 138 | QCOMPARE(dataDirsWithPostfix.count(), 2); 139 | QCOMPARE(dataDirsWithPostfix.at(0), QString::fromLatin1("/usr/local/share") + postfix); 140 | QCOMPARE(dataDirsWithPostfix.at(1), QString::fromLatin1("/usr/share") + postfix); 141 | 142 | setCustomLocations(); 143 | const QStringList dataDirsCustom = XdgDirs::dataDirs(); 144 | QCOMPARE(dataDirsCustom.count(), 1); 145 | QCOMPARE(dataDirsCustom.at(0), m_dataDirs); 146 | 147 | const QStringList dataDirsCustomWithPostfix = XdgDirs::dataDirs(postfix); 148 | QCOMPARE(dataDirsCustomWithPostfix.count(), 1); 149 | QCOMPARE(dataDirsCustomWithPostfix.at(0), m_dataDirs + postfix); 150 | } 151 | 152 | void tst_xdgdirs::testConfigDirs() 153 | { 154 | const QString postfix = QString::fromLatin1("/") + QCoreApplication::applicationName(); 155 | setDefaultLocations(); 156 | 157 | const QStringList configDirs = XdgDirs::configDirs(); 158 | QCOMPARE(configDirs.count(), 1); 159 | QCOMPARE(configDirs.at(0), QString::fromLatin1("/etc/xdg")); 160 | 161 | const QStringList configDirsWithPostfix = XdgDirs::configDirs(postfix); 162 | QCOMPARE(configDirsWithPostfix.count(), 1); 163 | QCOMPARE(configDirsWithPostfix.at(0), QString::fromLatin1("/etc/xdg") + postfix); 164 | 165 | setCustomLocations(); 166 | const QStringList configDirsCustom = XdgDirs::configDirs(); 167 | QCOMPARE(configDirsCustom.count(), 1); 168 | QCOMPARE(configDirsCustom.at(0), m_configDirs); 169 | 170 | const QStringList configDirsCustomWithPostfix = XdgDirs::configDirs(postfix); 171 | QCOMPARE(configDirsCustomWithPostfix.count(), 1); 172 | QCOMPARE(configDirsCustomWithPostfix.at(0), m_configDirs + postfix); 173 | } 174 | 175 | void tst_xdgdirs::testCacheHome() 176 | { 177 | setDefaultLocations(); 178 | const QString expectedCacheHome = QDir::homePath() + QStringLiteral("/.cache"); 179 | QCOMPARE(XdgDirs::cacheHome(), expectedCacheHome); 180 | QCOMPARE(XdgDirs::cacheHome(false), expectedCacheHome); 181 | 182 | setCustomLocations(); 183 | const QString expectedCacheHomeCustom = XdgDirs::cacheHome(); 184 | QCOMPARE(XdgDirs::cacheHome(), expectedCacheHomeCustom); 185 | QCOMPARE(XdgDirs::cacheHome(false), expectedCacheHomeCustom); 186 | 187 | } 188 | 189 | void tst_xdgdirs::testAutostartHome() 190 | { 191 | setDefaultLocations(); 192 | const QString expectedAutoStartHome = QDir::homePath() + QString::fromLatin1("/.config/autostart"); 193 | QCOMPARE(XdgDirs::autostartHome(), expectedAutoStartHome); 194 | QCOMPARE(XdgDirs::autostartHome(false), expectedAutoStartHome); 195 | 196 | setCustomLocations(); 197 | const QString expectedAutostartHomeCustom = XdgDirs::configHome() + QString::fromLatin1("/autostart"); 198 | QCOMPARE(XdgDirs::autostartHome(), expectedAutostartHomeCustom); 199 | QCOMPARE(XdgDirs::autostartHome(false), expectedAutostartHomeCustom); 200 | } 201 | 202 | void tst_xdgdirs::testAutostartDirs() 203 | { 204 | const QString postfix = QString::fromLatin1("/") + QCoreApplication::applicationName(); 205 | 206 | setDefaultLocations(); 207 | const QStringList autostartDirs = XdgDirs::autostartDirs(); 208 | QCOMPARE(autostartDirs.count(), 1); 209 | QCOMPARE(autostartDirs.at(0), QString::fromLatin1("/etc/xdg/autostart")); 210 | 211 | const QStringList autostartDirsWithPostfix = XdgDirs::autostartDirs(postfix); 212 | QCOMPARE(autostartDirsWithPostfix.count(), 1); 213 | QCOMPARE(autostartDirsWithPostfix.at(0), QString::fromLatin1("/etc/xdg/autostart") + postfix); 214 | 215 | 216 | setCustomLocations(); 217 | const QStringList autostartDirsCustom = XdgDirs::autostartDirs(); 218 | QCOMPARE(autostartDirsCustom.count(), 1); 219 | QCOMPARE(autostartDirsCustom.at(0), m_configDirs + QString::fromLatin1("/autostart")); 220 | 221 | const QStringList autostartDirsCustomWithPostfix = XdgDirs::autostartDirs(postfix); 222 | QCOMPARE(autostartDirsCustomWithPostfix.count(), 1); 223 | QCOMPARE(autostartDirsCustomWithPostfix.at(0), m_configDirs + QString::fromLatin1("/autostart") + postfix); 224 | } 225 | 226 | QTEST_APPLESS_MAIN(tst_xdgdirs) 227 | #include "tst_xdgdirs.moc" 228 | -------------------------------------------------------------------------------- /util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 2 | 3 | set(QTXDG_DESKTOP_FILE_START_SRCS 4 | qtxdg-desktop-file-start.cpp 5 | ) 6 | 7 | set(QTXDG_ICONFINDER_SRCS 8 | qtxdg-iconfinder.cpp 9 | ) 10 | 11 | add_executable(qtxdg-desktop-file-start 12 | ${QTXDG_DESKTOP_FILE_START_SRCS} 13 | ) 14 | 15 | add_executable(qtxdg-iconfinder 16 | ${QTXDG_ICONFINDER_SRCS} 17 | ) 18 | 19 | target_include_directories(qtxdg-desktop-file-start 20 | PRIVATE "${PROJECT_SOURCE_DIR}/qtxdg" 21 | ) 22 | 23 | target_include_directories(qtxdg-iconfinder 24 | PRIVATE "${Qt6Gui_PRIVATE_INCLUDE_DIRS}" 25 | ) 26 | 27 | target_compile_definitions(qtxdg-desktop-file-start 28 | PRIVATE 29 | "-DQTXDG_VERSION=\"${QTXDG_VERSION_STRING}\"" 30 | "QT_NO_KEYWORDS" 31 | ) 32 | 33 | target_compile_definitions(qtxdg-iconfinder 34 | PRIVATE 35 | "-DQTXDG_VERSION=\"${QTXDG_VERSION_STRING}\"" 36 | "QT_NO_KEYWORDS" 37 | ) 38 | 39 | target_link_libraries(qtxdg-desktop-file-start 40 | ${QTXDGX_LIBRARY_NAME} 41 | ) 42 | 43 | target_link_libraries(qtxdg-iconfinder 44 | ${QTXDGX_ICONLOADER_LIBRARY_NAME} 45 | ) 46 | 47 | install(TARGETS 48 | qtxdg-desktop-file-start 49 | qtxdg-iconfinder 50 | RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 51 | COMPONENT Runtime 52 | ) 53 | -------------------------------------------------------------------------------- /util/qtxdg-desktop-file-start.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2016 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | static void printErr(const QString & out) 30 | { 31 | std::cerr << qPrintable(out); 32 | } 33 | 34 | int main(int argc, char *argv[]) 35 | { 36 | QCoreApplication app(argc, argv); 37 | QCoreApplication::setApplicationName(QLatin1String("qtxdg-desktop-file-start")); 38 | QCoreApplication::setApplicationVersion(QLatin1String(QTXDG_VERSION)); 39 | 40 | QCommandLineParser parser; 41 | parser.setApplicationDescription(QLatin1String("QtXdg XdgDesktopFile start Tester")); 42 | parser.addHelpOption(); 43 | parser.addVersionOption(); 44 | parser.addPositionalArgument(QLatin1String("file [urls...]"), QLatin1String("desktop file to start and its urls"),QLatin1String("file [urls...]")); 45 | parser.process(app); 46 | 47 | if (parser.positionalArguments().isEmpty()) { 48 | parser.showHelp(EXIT_FAILURE); 49 | } 50 | 51 | QStringList userArgs = parser.positionalArguments(); 52 | const QString userFileName = userArgs.takeFirst(); 53 | 54 | const QFileInfo fileInfo(userFileName); 55 | if (fileInfo.isAbsolute()) { 56 | if (!fileInfo.exists()) { 57 | printErr(QString::fromLatin1("File %1 does not exist\n").arg(userFileName)); 58 | return EXIT_FAILURE; 59 | } 60 | } 61 | 62 | XdgDesktopFile f; 63 | const bool valid = f.load(userFileName); 64 | if (valid) { 65 | f.startDetached(userArgs); 66 | } else { 67 | printErr(QString::fromLatin1("%1 doesn't exist or isn't a valid .desktop file\n").arg(userFileName)); 68 | return EXIT_FAILURE; 69 | } 70 | 71 | return EXIT_SUCCESS; 72 | } 73 | -------------------------------------------------------------------------------- /util/qtxdg-iconfinder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libqtxdg - An Qt implementation of freedesktop.org xdg specs 3 | * Copyright (C) 2017 Luís Pereira 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 | * Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include // XdgIconLoader needs a QGuiApplication 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | #include 28 | #include 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | QGuiApplication app(argc, argv); 33 | app.setApplicationName(QStringLiteral("qtxdg-iconfinder")); 34 | app.setApplicationVersion(QStringLiteral(QTXDG_VERSION)); 35 | 36 | QCommandLineParser parser; 37 | parser.setApplicationDescription(QStringLiteral("QtXdg icon finder")); 38 | parser.addPositionalArgument(QStringLiteral("iconnames"), 39 | QStringLiteral("The icon names to search for"), 40 | QStringLiteral("[iconnames...]")); 41 | parser.addVersionOption(); 42 | parser.addHelpOption(); 43 | parser.process(app); 44 | 45 | if (parser.positionalArguments().isEmpty()) 46 | parser.showHelp(EXIT_FAILURE); 47 | 48 | qint64 totalElapsed = 0; 49 | const auto icons = parser.positionalArguments(); 50 | for (const QString& iconName : icons) { 51 | QElapsedTimer t; 52 | t.start(); 53 | const auto info = XdgIconLoader::instance()->loadIcon(iconName); 54 | qint64 elapsed = t.elapsed(); 55 | const auto icon = info.iconName; 56 | const auto &entries = info.entries; 57 | 58 | std::cout << qPrintable(iconName) << 59 | qPrintable(QString::fromLatin1(":")) << qPrintable(icon) << 60 | qPrintable(QString::fromLatin1(":")) << 61 | qPrintable(QString::number(elapsed)) << "\n"; 62 | 63 | for (const auto &i : entries) { 64 | std::cout << "\t" << qPrintable(i->filename) << "\n"; 65 | } 66 | totalElapsed += elapsed; 67 | } 68 | 69 | std::cout << qPrintable(QString::fromLatin1("Total loadIcon() time: ")) << 70 | qPrintable(QString::number(totalElapsed)) << 71 | qPrintable(QString::fromLatin1(" ms")) << "\n"; 72 | 73 | return EXIT_SUCCESS; 74 | } 75 | --------------------------------------------------------------------------------