Remove pristine-tar junk.

ubuntu/cosmic
Simon Quigley 6 years ago
parent 6edaa856ac
commit 02b99e2301

@ -1,11 +0,0 @@
Upstream Authors:
LXQt team: http://lxqt.org
Razor team: http://razor-qt.org
Copyright:
Copyright (c) 2010-2012 Razor team
Copyright (c) 2012-2017 LXQt team
License: LGPL-2.1+ and LGPL-2.1-or-3-with-Digia-1.1-exception
The full text of the LGPL-2.1+ license can be found in the 'COPYING' file.
The Digia-1.1 exception can be found in the 'Digia-Qt-LGPL-Exception-1.1' file.

@ -1,436 +0,0 @@
libqtxdg-3.1.0 / 2017-10-21
===========================
* Bump version to 3.1.0
* xdgdesktopfile: Add API for getting actions info
* xdgdesktopfile: Add support for activating actions
* xdgdesktopfile: Add getting actions
* Check $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS for mimeapps.list first.
* Fix reading and writing mimeapps.list file.
* Don't export github templates
3.0.0 / 2017-09-22
==================
* Release 3.0.0: Update changelog
* Backport support for Scale directory key according to Icon Theme spec
* Bump Major to 3
* test: Drop Q_FOREACH
* Drop Q_FOREACH
* liblxqt make no sense here
* Copied issue template
* Drops Qt5Core_VERSION_STRING
* Avoid Qt special keywords collision
* XdgDesktopFile: Stops allocating unneeded QMap::keys()
* XdgDesktopFile: Stop allocating unneeded QHash:values()
* XdgDesktopFile: Improve const-ness
* xdgiconloader: Reworks the unthemed/pixmap search
* xdgiconloader: Puts the hicolor at the end of the theme hierarchy
* XdgIcon: Add flag for "FollowsColorScheme" processing
* xdgiconloader: Honor "FolowsColorScheme" theme hint
* xdgiconloader: Support symbolic SVG icons
* More fixes (#131)
* xdgiconloader: Correct hierarchy of fallbacks (#116)
* xdgiconloader: Fix XdgIconLoaderEngine::actualSize() (#130)
* Update CMakeLists.txt
* It adds loadIcon() timing measurements.
* xdgiconloader: Consider all existing files/images
* Check QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH existence
* Mark QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH as advanced
* xdgiconloader: Implement QIconEnginePlugin interface
* Disables uninstall target
* Remove last uses of Java-style (non-mutable) iterators from QtBase
* Adds a development qtxdg-iconfinder utility tool
* Enable strict iterators for debug builds
* Removes extra semi-colons
* Improve build warnings
* Bump year
* QtGui: eradicate Q_FOREACH loops [already const]
* Optimize QIconLoader::findIconHelper()
* Remove unused variable in QIconLoader::findIconHelper()
* Improve use of QHash to minimize double hashing
* QIconLoaderEngine: add missing Q_DECL_OVERRIDEs
* Replace QLatin1Literal with QLatin1String
* QIconCacheGtkReader: use QStringRef more
* Gui: use const (and const APIs) more
* Adds Link Time Optimization
* Replaces CMAKE_SOURCE_DIR by PROJECT_SOURCE_DIR
* Refactors superbuild support
* Remove duplicate use of source header files
* Use AUTOMOC everywhere
* Stop using include_directories()
* Removes test project definition
* Use CMAKE_INCLUDE_CURRENT_DIR
* Adds PROJECT_NAME to the build Qt version message
* Simplify target_compile_definitions() and target_include_directories()
* qiconloader: Reuse Qt implementation
* XdgIconLoader: Fix FTBFS in super-build/in-tree builds
* Allow xdg-user-dirs in the realpath of $HOME. On some systems /home is a symlink and $HOME points to the symlink. This commit allows the xdg-user-dirs to start with the real/canonical path.
* Updates version requirements in pkg-config (.pc) stuff
* Make Qt5Xdg use only the same version Qt5XdgIconLoader
* Adds minimum Qt version requirement (5.4.2)
* test: Fixes false positive in tst_xdgdesktopfile::testReadLocalized()
* Remove cpack (#106)
2.0.0 / 2016-09-17
==================
* Release 2.0.0: Add changelog
* Bump version to 2.0.0
* Extend README.md
* Updates dependencies
* Fixes QIcon::hasThemeIcon() behavior with our Icon Loader Engine
* Adds Qt5Svg explicitly to the required packages
* QIconLoader: Use the GTK+ icon caches
* QIcon: add a hook in the engine so a non null QIconEngine can still be a null icon
* QIconLoader: don't make QIconDirInfo::type a bit-field
* Do not support static QIcon instances
* Respect manual set icon themes.
* Remove <qhash.h> where it's not used
* Make it more obvious that Q_WS_ is dead code, and should perhaps be ported
* XdgDesktopFileData: Explicitly initialize members (#91)
* build: Create separate Qt5XdgIconLoader target
* XdgDesktopFile: Adds tests
* xdgdesktopfile: Removes an not needed debug info
* xdgdesktopfile: Removes double QLatin1String's contruction
* XdgDesktopFileCache: Check if a file isValid() only when needed
* XdgDesktopFile: Reworks XdgDesktopFileCache::getFile()
* XdgDesktopFileCache: Check new acquired objects before using it
* XdgDesktopFile: Removes unneeded assignment
* XdgDesktopFile: Add break to switch case
* qtxdg: Get the HOME environment variable just one time
* Replace the QString % operator by the + operator
* No more implicit string conversions
* Moves QT_USE_QSTRINGBUILDER to the compiler_settings CMake module
* XdgDesktopFileCache: Fixes an coding typing error
* xdgiconloader: Fix typo in directoryMatchesSize
* Xdgiconloader (#84)
* Improve foreach iteraror performance
* XdgDesktopFile: Improve the performance of the foreach loop
* XdgDesktopFile: Use XdgDirs::userDir(), drop QStandardPaths()
* XdgDesktopFile: Standardize text strings scope
* XdgDesktopFile: Adds a Desktop File ID calculator method
* XdgDesktopFile: Document Exec fallback when DBusActivatable fails
* Adds QT_USE_QSTRINGBUILDER to the compile definitions
* Adds the BUILD_DEV_UTILS to README.md
* Makes the development utils build/install optional
* XdgDesktopFile: Adds Exec fallback when DBusActivatable fails
* Adds an .desktop file start tester
* XdgDirs: Use Q_ASSERT to check for XdgDirs::userDirectory invalid values
* XdgDirs: Use XdgDirs::UserDirectory enum instead of int
* XdgDirs: Makes XdgDirs::userDir use userDirectoryFallback()
* XdgDirs: Adds userDirDefault() method.
* Adds XdgDesktopFile::mimeTypes() member
* build: Enable C++11 usage
* iconloader: Fix actualSize() for non-themed icons
* desktopfile: Change validity check
* Added Digia-Qt-LGPL-Exception-1.1
* Update years and Licenses
* desktopfile: Check validity of DBus object path
* desktopfile: Don't invoke DBus call on invalid interface
* XdgUserDirs: Return a fallback when the path is empty
* README.md: Fix grammatical error, adjust wording
* Update and rename README to README.md
* xdgdesktopfile: handle 'Path' entry for application's working directory
* Fix possible use of cachedIcon after free
* Update release.sh server url
1.3.0 / 2015-10-27
==================
* Release 1.3.0
* desktopfile: Remove support for $XDG_MOVIES_DIR (which doesn't exist)
* Assorted style cleanups
* Adds XdgDesktopFile != operator
* Fixes the XdgMimeType == operator
* Handles CMake policy CMP0063
* Adds an compiler_settings CMake "module"
* CMake: Adds Runtime install COMPONENT
* Drops find_package(), use find_dependency()
* Marks link libraries as PUBLIC
* Handles in-tree builds headers the right way.
* Narrows the scope of compile definitions
* Improves create_pkgconfig_file.cmake
* Use the Targets CMake stuff
* Adds package version config info file
* Code reordering
* Use Qt5 style library names
* Remove unneeded add_definitions()
* Simplifies version variables a little bit
* Removes unneeded include_directories()
* Uses standard GNUInstallDirs instead of FindLibSuffix
* Remove trailing whitespaces
* added missing licensing headers
* Backports Fixed icons lookup in QIcon::fromTheme
* Adds XdgDirs tests
* Adds XdgDirs::configHome() fallback default locations
* XdgDesktopFile: Handles NotShowIn correctly
* Fixes XdgDirs::dataHome() regression
* QIconLoader: Change the order fallback icon lookup order
* Gets rid of translations stuff
* Cleans up empty comment lines
* Remove Qt4 stuff from the documentation
* Remove Qt4 stuff from the example and tests
* Remove Qt4 stuff from the source files
* Get rid of Qt4 stuff in the build system
1.2.0 / 2015-03-29
==================
* Release 1.2.0
* Fixes XdgDesktop::isShow() caching mechanism
* Add QtDBus/Qt5DBus dependency
* Adds support for X-Categories
* Adds support for X-OnlyShowIn and X-NotShowIn
* Fixes an Qt4 FTBFS
* Use QLatin1Char()
* Adds platform-data handling
* Make DBusActivatable work for Qt4 too
* desktopfile: support for DBusActivatable applications
* Adds a list of special non detachable execs
* desktopfile: run new process as a direct child
* Qt5: Use QStandardPaths() where possible
* XdgDirs: Updates documentation.
* String manipulation enhancements
* Make sure returned directories don't have an trailing '/'
* XdgDirs: postfix should always start with an /
* XdgDirs::configHome() handle postfix slash
* Fix XdgDirs::dataDirs() postfix handling
* Replace empty quotes by QString()
* XdgDesktopFileCache: Retrieve apps of a category
* Quote all paths in the CMake stuff
* Qt5: Use Qt5 private headers
* Ignore empty dirs in xdgDirList()
* Makes needed helper functions available to tests
* - Fix compilation when using internal mime
* Release with a proper versioned prefix
* Avoid adding empty parent icon theme
* Update license headers and add new license files
* Use QPlatformTheme::SystemIconFallbackThemeName in static QString fallbackTheme()
* QIconLoader: enable an easy case of transactional processing
* QIconLoader: don't inherit QObject
* QIconLoader: replace an inefficient QList with a QVector
* QIconLoader: mark virtual overrides
* QIconLoader: mark a helper type as movable
* QIconLoader: replace while(!empty()) delete takeLast() with qDeleteAll()
* QIconLoader: don't re-evaluate container.size() all the time (II)
* QIconLoader: don't re-evaluate container.size() all the time
* QIconLoader: remove another unused variable
* QIconLoader: remove an unused variable
1.1.0 / 2015-02-07
==================
* Update the release script to sign packages
* Sets visibility to hidden symbols for Clang
* Move static const variable from a public .h file to the .cpp
* Use gcc visibility attribute and Q_DECL_EXPORT macro to avoid exporting private symbols in the lib. This greatly reduced the size of dynamic symbol table and might potentially speed up loading. Also, turn off exception handling to save more since we don't use it. For non-gcc compilers, this change does nothing.
* Makes the Qt5 build the default
* Qt5: Updates CMake minimum required version
* Qt4: Backport add fallback for unthemed app icons
* add fallback for unthemed app icons
* XdgDesktopFileCache::getFile(): Don't insert/removes non existent files
* Enhance the loading of a .desktop file.
* Adds helper functions prototypes
* Fixes issue #7
* Updates .gitignore
* Removes i18n/i10n
* Updates translations
* Updates the translation infrastructure
* Update Russian translation
* Qt4: Fixes an FTBFS on Gentoo x86_64 when USE_QTMIMETYPES=On
* Add a release script
1.0.0 / 2014-09-06
==================
* Release 1.0.0
* Replaces XdgMimeInfo with XdgMimeType
* Updates the cmake_minimum_required() version
* Build system maintenance
* if QT_VERSION < 5 load the qt4 header
* Allows QIconLoader to search in multiple theme directories.
* Fixes an FTBFS in the Qt4 build
* Merge branch 'use-qt5-qiconloader'
* Revert "Merge branch 'use-qt5-qiconloader'"
* Revert "Fixes an FTBFS in the Qt4 build"
* Fixes an FTBFS in the Qt4 build
* Get and set XDG user dirs variables in config file
* Honors /usr/share/pixmaps when searching for icons.
* Adds xpm icon support
* Adds Qt5 QIconLoader for the Qt5 build
* Ports Qt5 commit: Make sure QIconLoader is always initialized
* Use environment to trigger Qt5 builds
* Fixes an XdgMimeInfo memory leak
* Use case insensitive comparisons with desktop environment names
* Updates some XdgDesktopFile methods documentation
* Make desktop enviroment names comparisons case insensitive
* solve failed comp LXQT with LXQt (OnlyShowIn=LXQt;) in desktop files
* Re-adds Support XDG_CURRENT_DESKTOP in autostart handling
* Deprecates non desktop environment neutral XdgDesktopFile methods
* Revert "Support XDG_CURRENT_DESKTOP in autostart handling."
* Adds QTXDG_DEPRECATED macro
* Install pkgconfig files to /usr/local/libdata/pkgconfig in FreeBSD.
* Set library dirs properly in qtxdg-config and use files.
0.5.3 / 2014-05-08
==================
* Release 0.5.3
* Update some comments
0.5.1 / 2014-05-05
==================
* libqtxdg 0.5.1
* Revert "Change default environment to LXQt"
* Revert "Check for lxqt-applications instead of razor-applications"
* Support XDG_CURRENT_DESKTOP in autostart handling.
* Update .gitignore
* Check for lxqt-applications instead of razor-applications
* Change default environment to LXQt
* Avoid XdgAction mnemonics caused by '&' symbol in the name of desktop app.
0.1.0 / 2014-04-29
==================
* Update AUTHORS and COPYING
* Add CPack rules for creating tarball
* Put iconloaderfix into own namespace
* Adds an uninstall target
* Fixes an FTBFS on the test target
* Fixes an FTBFS when a mix of PIC and PIE compiler flags are used
* Updates CMake's minimum required version
* Adds Qt5Widgets to the required pkg-config required packages
* test: Removes meaningless add_dependencies(..... razorqt)
* Don't use STREQUAL to test the BUILD_TESTS option
* Removed CMAKE_SOURCE_DIR usage from test/CMakeLists.txt
* Adds missing ${CMAKE_INSTALL_PREFIX}
* Fixes bugs in create_pkgconfig_file cmake macro
* Use GNU installation directories
* prefix parameter for autostartDirs, configDirs and dataDirs. (part2)
* prefix parameter for autostartDirs, configDirs and dataDirs.
* Updates buildsystem typical use documentation
* Reformatting for an easy reading in a 80x24 terminal
* Documents the QTXDG_QT_LIBRARIES variable
* Adds an tiny example on how to use the lib
* RazorLibSuffix.cmake -> ../cmake/FindLibSuffix.cmake and QUIET mode for find_package
* Adds ${CMAKE_CURRENT_BINARY_DIR} to the include_directories list
* Fix qtxdg_use.cmake and qtxdg-config.cmake generation location
* Replace QDomNodeList::length() by QDomNodeList::size()
* Portable headers
* Adds pkg-config to Qt5Xdg
* Renames the Qt5 build
* Packs Qt version specific stuff
* Removes unneeded set(QT_USE_QTXML TRUE)
* qtxdg/test: Adapts the build system to support Qt4 and Qt5
* qtxdg/test: Removes Qt4 CMake stuff
* Adds missing library (Qt5Xml) to qtxdg target
* qtxdg/test: Removes the project command and cmake_minimum_required()
* Explicitly requires QtTest module
* Make BUILD_TESTS an option
* Replace Q_GLOBAL_STATIC_WITH_INITIALIZER
* Replaces QIconEngineV2 with QIconEngine
* Adds QMimeData include file
* Port QString::toAscii()
* Port QDesktopServices
* Ran fixqt4headers
* Adds support to Qt5 in the buildsystem
* Adds test target to CMake
* Use the QtTestLib facilities
* Cmake find_package files for the QtXdg
* Revert "Cmake find_package files"
* Cmake find_package files
* Add COPYING and AUTHORS files
* X-RAZOR changed to Razor in desktop files
* config-file-associations, mimetypeviewer: Replaced QTreeWidget with QTreeView and new class MimetypeItemModel as model
* Improved (hopefuly) layout and look of config-fileassociations, application chooser
* Clang complained about type mismatch
* application-x-executable now fallback icon for desktopfiles of type Application
* Added XdgMimeInfoCache
* Added more info to XdgMime
* XdgDesktopFileCache now holds list of all apps that can handle a given mimetype
* Make QtXdg build by itself again
* libraries: Removes unneeded include(RazorLibSuffix)
* libraries: Removes unneeded cmake_minimum_required(VERSION 2.6)
* libraries: Removes unneeded find_package(Qt4)
* xdgdesktopfilecache now looks in <datadir or datahome>/applications/defaults.list for default app
* Add getApps method to XdgDesktopFileCache - returns all applications that can handle a mimetype
* Fix building with C++11
* XdgDesktopFile: Don't strip quotes
* initial fix for #520 XdgDesktopFileCache::getDefaultApp cache wrong behavior
* Closes Issue #487
* Set minimum percent to 1% for transifex in cmake
* Translations updated
* Translations updated
* Soname was changed
* Update translations
* Translations updated
* Removed line num from TS files.
* Fix autostart dir detection when the env var is set
* Updated .tx file
* version bump to 0.4.99 (public "release candiates") for qtxdg
* Translation for razor-sesion
* Fixes in the qtxdg translations
* Transifex resource renamed qtxdg->libqtxdg
* Fix for Issue #290 Fails to build on BSD
* New translations for libqtxdg
* Starting the razor-confupdate from the razor-session.
* Razor-confupdate: fixes and .upd file for 0.4.1-0.5
* Language name zh_CN.GB2312 braked cmake process.
* Translations updated
* Add operator== for XdgDesktopFile
* Don't replace space with \s
* Fixed for Preloading menu
* Cleaning the code.
* Move autostart directory code to XdgDirs
* Improvements to the XdgMenu. Added changed signal.
* Small speed opetimistaion in the qiconloader
* Add function to remove entries from desktop files
* Transifex desktop: sr_BA.ts should be a local
* Transifex desktop: local translations
* Transifex desktop: Translations pulled
* Icons for the desktop menu
* Add Traditional Chinese Translations
* Translations update
* Added support for the online translation service. www.transifex.net
* Serbian translation files
* Class documentation for XdgMimeInfo
* Greek translation by iosifidis
* Fix for issue #170. Escaping.
* Fix for issue #170. Escaping.
* Fix for issue #170
* Fix for issue #170
* Added danish translations
* X-RAZOR -> Razor for autostart
* Russian translation
* RAZOR -> X-RAZOR
* MINOR_VERSION & PATCH_VERSION for libraries
* fix #169: italian translation
* XdgAutoStart rewriten (lgpl2+)
* Closes #158
* Support icons with absolute path file names
* LGPL2+ for qtxdg
* Escape &'s to prevent Qt from using them for mnemonics
* Revert "XdgDesktopFile: Display an actual ampersand character"
* Update german [de] translation
* Add setLocalizedValue() function
* fixed qtxdg/translations/translate.sh
* Add a constructor to generate basic XdgDesktopFiles
* Correct the XdgAutoStart behavior
* SVK translation finalized
* Replaces return"" by return QString()
* License audit
* implemented #70: pkg-config for libs
* Add Chinese(simplified) translation files.
* fix #119 qtxdg bug and patch
* License audit
* Add Slovak (sk) translation
* Czech translations (cs_CZ)
* Fix doxygen documentation in xdgdesktopfile
* New doxygen ifrastructure
* devel-docs generated in CMAKE_BINARY_DIR/docs includig dummy index.html
* missing translations in CMakeLists
* XdgDesktopFile is implicitly shared
* huge refactoring of the libraries build organization

@ -1,173 +0,0 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
project(libqtxdg)
option(BUILD_TESTS "Builds tests" OFF)
option(BUILD_DEV_UTILS "Builds and install development utils" OFF)
# additional cmake files
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if (CMAKE_VERSION VERSION_LESS "3.1")
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
# -std=c++0x is deprecated but some tools e.g. qmake or older gcc are still using it
if(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER} does not support c++11/c++0x")
endif()
endif()
else()
set(CMAKE_CXX_STANDARD 11)
endif()
set(QTXDG_MAJOR_VERSION 3)
set(QTXDG_MINOR_VERSION 1)
set(QTXDG_PATCH_VERSION 0)
set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION})
set(QT_MINIMUM_VERSION "5.6.1")
include(GNUInstallDirs) # Standard directories for installation
include(CMakePackageConfigHelpers)
include(GenerateExportHeader)
include(create_portable_headers)
include(create_pkgconfig_file)
include(compiler_settings NO_POLICY_SCOPE)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Widgets Svg Xml DBus)
if (BUILD_TESTS)
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Test)
endif()
set(QTXDGX_LIBRARY_NAME "Qt5Xdg")
set(QTXDGX_FILE_NAME "qt5xdg")
set(QTXDGX_ICONLOADER_LIBRARY_NAME "Qt5XdgIconLoader")
set(QTXDGX_ICONLOADER_FILE_NAME "qt5xdgiconloader")
set(QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME "Qt5XdgIconPlugin")
set(QTXDGX_PKG_CONFIG_DESCRIPTION "Qt5Xdg, a Qt5 implementation of XDG standards")
set(QTXDGX_PKG_CONFIG_REQUIRES "Qt5Core >= ${QT_MINIMUM_VERSION}, Qt5Xml >= ${QT_MINIMUM_VERSION}, Qt5Widgets >= ${QT_MINIMUM_VERSION}, Qt5DBus >= ${QT_MINIMUM_VERSION}, Qt5XdgIconLoader = ${QTXDG_VERSION_STRING}")
set(QTXDGX_ICONLOADER_PKG_CONFIG_DESCRIPTION "Qt5XdgIconLader, a Qt5 XDG Icon Loader")
set(QTXDGX_ICONLOADER_PKG_CONFIG_REQUIRES "Qt5Gui >= ${QT_MINIMUM_VERSION}, Qt5Svg >= ${QT_MINIMUM_VERSION}")
set(QTXDGX_INTREE_INCLUDEDIR "${CMAKE_CURRENT_BINARY_DIR}/InTreeBuild/include")
if (NOT CMAKE_BUILD_TYPE)
set ( CMAKE_BUILD_TYPE Release )
endif (NOT CMAKE_BUILD_TYPE)
message(STATUS "Building ${PROJECT_NAME} with Qt ${Qt5Core_VERSION}")
add_subdirectory(xdgiconloader)
add_subdirectory(qtxdg)
if(BUILD_TESTS)
enable_testing()
target_compile_definitions(${QTXDGX_LIBRARY_NAME}
PRIVATE "QTXDG_TESTS=\"1\""
)
add_subdirectory(test)
else()
message(STATUS "")
message(STATUS "For building tests use -DBUILD_TESTS=Yes option.")
message(STATUS "")
endif()
if (BUILD_DEV_UTILS)
add_subdirectory(util)
endif()
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/${QTXDGX_FILE_NAME}-config.cmake.in"
"${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}"
)
write_basic_package_version_file(
"${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config-version.cmake"
VERSION ${QTXDG_VERSION_STRING}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}-config.cmake.in"
"${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}"
)
write_basic_package_version_file(
"${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config-version.cmake"
VERSION ${QTXDG_VERSION_STRING}
COMPATIBILITY AnyNewerVersion
)
create_pkgconfig_file(
PACKAGE_NAME ${QTXDGX_LIBRARY_NAME}
DESCRIPTIVE_NAME ${QTXDGX_LIBRARY_NAME}
DESCRIPTION ${QTXDGX_PKG_CONFIG_DESCRIPTION}
INCLUDEDIRS ${QTXDGX_FILE_NAME}
LIBS ${QTXDGX_LIBRARY_NAME}
REQUIRES ${QTXDGX_PKG_CONFIG_REQUIRES}
REQUIRES_PRIVATE ${QTXDGX_ICONLOADER_LIBRARY_NAME}
VERSION ${QTXDG_VERSION_STRING}
INSTALL
)
create_pkgconfig_file(
PACKAGE_NAME ${QTXDGX_ICONLOADER_LIBRARY_NAME}
DESCRIPTIVE_NAME ${QTXDGX_ICONLOADER_LIBRARY_NAME}
DESCRIPTION ${QTXDGX_ICONLOADER_PKG_CONFIG_DESCRIPTION}
INCLUDEDIRS ${QTXDGX_ICONLOADER_FILE_NAME}
LIBS ${QTXDGX_ICONLOADER_LIBRARY_NAME}
REQUIRES ${QTXDGX_ICONLOADER_PKG_CONFIG_REQUIRES}
VERSION ${QTXDG_VERSION_STRING}
INSTALL
)
install(FILES
"${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake"
"${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}"
COMPONENT Devel
)
install(FILES
"${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config.cmake"
"${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}"
COMPONENT Devel
)
install(EXPORT
"${QTXDGX_FILE_NAME}-targets"
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}"
FILE "${QTXDGX_FILE_NAME}-targets.cmake"
COMPONENT Devel
)
install(EXPORT
"${QTXDGX_ICONLOADER_FILE_NAME}-targets"
DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_ICONLOADER_FILE_NAME}"
FILE "${QTXDGX_ICONLOADER_FILE_NAME}-targets.cmake"
COMPONENT Devel
)
# uninstall target
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
#add_custom_target(uninstall
# COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

@ -1,461 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control
compilation and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply, and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License
may add an explicit geographical distribution limitation excluding those
countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

@ -1,22 +0,0 @@
Digia Qt LGPL Exception version 1.1
As an additional permission to the GNU Lesser General Public License version
2.1, the object code form of a "work that uses the Library" may incorporate
material from a header file that is part of the Library. You may distribute
such object code under terms of your choice, provided that:
(i) the header files of the Library have not been modified; and
(ii) the incorporated material is limited to numerical parameters, data
structure layouts, accessors, macros, inline functions and
templates; and
(iii) you comply with the terms of Section 6 of the GNU Lesser General
Public License version 2.1.
Moreover, you may apply this exception to a modified version of the Library,
provided that such modification does not involve copying material from the
Library into the modified Library's header files unless such material is
limited to (i) numerical parameters; (ii) data structure layouts;
(iii) accessors; and (iv) small macros, templates and inline functions of
five lines or less in length.
Furthermore, you are not required to apply this additional permission to a
modified version of the Library.

@ -1,27 +0,0 @@
# libqtxdg
## Overview
`libqtxdg` is a Qt 5 implementation of freedesktop.org XDG specifications.
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.
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.
## Installation
### Sources
At runtime qtbase is needed. gtk-update-icon-cache represents an optional runtime dependency for the reasons stated above.
Additional build dependencies are CMake, qtsvg, qttools and optionally Git to pull latest VCS checkouts.
The code configuration is handled by CMake so all corresponding generic instructions apply. Specific CMake variables are
* BUILD_TESTS to build tests. Disabled by default (`OFF`).
* BUILD_DEV_UTILS which builds and installs development utils. Disabled by default as well.
To build and install run `make` and `make install`respectively.
### Binary packages
The library is provided by all major Linux distributions like Arch Linux, Debian, Fedora and openSUSE.
Just use the distributions' package managers to search for string `libqtxdg`.

@ -1,21 +0,0 @@
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

@ -1,171 +0,0 @@
#=============================================================================
# Copyright 2015 Luís Pereira <luis.artur.pereira@gmail.com>
# Copyright 2013 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
#-----------------------------------------------------------------------------
# Honor visibility properties for all target types.
#
# The ``<LANG>_VISIBILITY_PRESET`` and
# ``VISIBILITY_INLINES_HIDDEN`` target properties affect visibility
# of symbols during dynamic linking. When first introduced these properties
# affected compilation of sources only in shared libraries, module libraries,
# and executables with the ``ENABLE_EXPORTS`` property set. This
# was sufficient for the basic use cases of shared libraries and executables
# with plugins. However, some sources may be compiled as part of static
# libraries or object libraries and then linked into a shared library later.
# CMake 3.3 and above prefer to honor these properties for sources compiled
# in all target types. This policy preserves compatibility for projects
# expecting the properties to work only for some target types.
#
# The ``OLD`` behavior for this policy is to ignore the visibility properties
# for static libraries, object libraries, and executables without exports.
# The ``NEW`` behavior for this policy is to honor the visibility properties
# for all target types.
#
# This policy was introduced in CMake version 3.3. CMake version
# 3.3.0 warns when the policy is not set and uses ``OLD`` behavior. Use
# the ``cmake_policy()`` command to set it to ``OLD`` or ``NEW``
# explicitly.
#-----------------------------------------------------------------------------
if(COMMAND CMAKE_POLICY)
if (POLICY CMP0063)
cmake_policy(SET CMP0063 NEW)
endif()
endif()
#-----------------------------------------------------------------------------
# Detect Clang compiler
#-----------------------------------------------------------------------------
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(QTXDG_COMPILER_IS_CLANGCXX 1)
endif()
#-----------------------------------------------------------------------------
# Global definitions
#-----------------------------------------------------------------------------
if (CMAKE_BUILD_TYPE MATCHES "Debug")
add_definitions(-DQT_STRICT_ITERATORS)
endif()
#-----------------------------------------------------------------------------
# Set visibility to hidden to hide symbols, unless they're exported manually
# in the code
#-----------------------------------------------------------------------------
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
#-----------------------------------------------------------------------------
# Disable exceptions
#-----------------------------------------------------------------------------
if (CMAKE_COMPILER_IS_GNUCXX OR QTXDG_COMPILER_IS_CLANGCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
endif()
#-----------------------------------------------------------------------------
# Common warning flags
#-----------------------------------------------------------------------------
set(QTXDG_COMMON_WARNING_FLAGS "-Wall -Wextra -Wchar-subscripts -Wno-long-long -Wpointer-arith -Wundef -Wformat-security")
#-----------------------------------------------------------------------------
# Warning flags
#-----------------------------------------------------------------------------
if (CMAKE_COMPILER_IS_GNUCXX OR QTXDG_COMPILER_IS_CLANGCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${__QTXDG_COMMON_WARNING_FLAGS} -Wnon-virtual-dtor -Woverloaded-virtual -Wpedantic")
endif()
if (QTXDG_COMPILER_IS_CLANGCXX)
# qCDebug(), qCWarning, etc trigger a very verbose warning, about.... nothing. Disable it.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
endif()
list(APPEND QTXDG_WARNING_FLAGS ${QTXDG_COMMON_WARNING_FLAGS})
#-----------------------------------------------------------------------------
# String conversion flags
#-----------------------------------------------------------------------------
add_definitions(
-DQT_USE_QSTRINGBUILDER
-DQT_NO_CAST_FROM_ASCII
-DQT_NO_CAST_TO_ASCII
-DQT_NO_URL_CAST_FROM_STRING
-DQT_NO_CAST_FROM_BYTEARRAY
)
#-----------------------------------------------------------------------------
# Linker flags
# Do not allow undefined symbols
#-----------------------------------------------------------------------------
if (CMAKE_COMPILER_IS_GNUCXX OR QTXDG_COMPILER_IS_CLANGCXX)
# -Bsymbolic-functions: replace dynamic symbols used internally in
# shared libs with direct addresses.
set(SYMBOLIC_FLAGS
"-Wl,-Bsymbolic-functions -Wl,-Bsymbolic"
)
set(CMAKE_SHARED_LINKER_FLAGS
"-Wl,--no-undefined ${SYMBOLIC_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}"
)
set(CMAKE_MODULE_LINKER_FLAGS
"-Wl,--no-undefined ${SYMBOLIC_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}"
)
set(CMAKE_EXE_LINKER_FLAGS
"${SYMBOLIC_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}"
)
endif()
#-----------------------------------------------------------------------------
# Turn on more aggrassive optimizations not supported by CMake
# References: https://wiki.qt.io/Performance_Tip_Startup_Time
#-----------------------------------------------------------------------------
if (CMAKE_COMPILER_IS_GNUCXX OR QTXDG_COMPILER_IS_CLANGCXX)
# -flto: use link-time optimizations to generate more efficient code
if (CMAKE_COMPILER_IS_GNUCXX)
set(LTO_FLAGS "-flto -fuse-linker-plugin")
# When building static libraries with LTO in gcc >= 4.9,
# "gcc-ar" and "gcc-ranlib" should be used instead of "ar" and "ranlib".
# references:
# https://gcc.gnu.org/gcc-4.9/changes.html
# http://hubicka.blogspot.tw/2014/04/linktime-optimization-in-gcc-2-firefox.html
# https://github.com/monero-project/monero/pull/1065/commits/1855213c8fb8f8727f4107716aab8e7ba826462b
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0") # gcc >= 4.9
set(CMAKE_AR "gcc-ar")
set(CMAKE_RANLIB "gcc-ranlib")
endif()
elseif (QTXDG_COMPILER_IS_CLANGCXX)
# The link-time optimization of clang++/llvm seems to be too aggrassive.
# After testing, it breaks the signal/slots of QObject sometimes.
# So disable it for now until there is a solution.
# set(LTO_FLAGS "-flto")
endif()
# apply these options to "Release" build type only
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${LTO_FLAGS}")
endif()

@ -1,245 +0,0 @@
#=============================================================================
# Copyright 2015 Luís Pereira <luis.artur.pereira@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================#
# create_pkgconfig_file(PACKAGE_NAME <package_name>
# VERSION <version>
# [PREFIX <path>]
# [EXEC_PREFIX <path>]
# [INCLUDEDIR_PREFIX <path>]
# [INCLUDEDIRS <path1> <path2> ... <path3>]
# [LIBDIR_PREFIX <path>]
# [DESCRIPTIVE_NAME <name>]
# [DESCRIPTION <description>]
# [URL <url>]
# [REQUIRES <dep1> <dep2> ... <dep3>]
# [REQUIRES_PRIVATE <dep1> <dep2> ... <dep3>]
# [LIB_INSTALLDIR <dir>]
# [CFLAGS <cflags>]
# [PATH <path>]
# [INSTALL])
#
#
# PACKAGE_NAME and VERSION are mandatory. Everything else is optional
include(CMakeParseArguments)
include(GNUInstallDirs)
function(create_pkgconfig_file)
set(options INSTALL)
set(oneValueArgs
PACKAGE_NAME
PREFIX
EXEC_PREFIX
INCLUDEDIR_PREFIX
LIBDIR_PREFIX
DESCRIPTIVE_NAME
DESCRIPTION
URL
VERSION
PATH
)
set(multiValueArgs
INCLUDEDIRS
REQUIRES
REQUIRES_PRIVATE
CONFLICTS
CFLAGS
LIBS
LIBS_PRIVATE
)
cmake_parse_arguments(USER "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (USER_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to create_pkgconfig_file(): \"${USER_UNPARSED_ARGUMENTS}\"")
endif()
# Check for mandatory args. Abort if not set
if (NOT DEFINED USER_PACKAGE_NAME)
message(FATAL_ERROR "Required argument PACKAGE_NAME missing in generate_pkgconfig_file() call")
else()
set(_PKGCONFIG_PACKAGE_NAME "${USER_PACKAGE_NAME}")
endif()
if (NOT DEFINED USER_VERSION)
message(FATAL_ERROR "Required argument VERSION missing in generate_pkgconfig_file() call")
else()
set(_PKGCONFIG_VERSION "${USER_VERSION}")
endif()
# Optional args
if (NOT DEFINED USER_PREFIX)
set(_PKGCONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}")
endif()
if (NOT DEFINED USER_EXEC_PREFIX)
set(_PKGCONFIG_EXEC_PREFIX "\${prefix}")
endif()
if (NOT DEFINED USER_INCLUDEDIR_PREFIX)
set(_PKGCONFIG_INCLUDEDIR_PREFIX "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
if (NOT DEFINED USER_LIBDIR_PREFIX)
set(_PKGCONFIG_LIBDIR_PREFIX "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
if (NOT DEFINED USER_DESCRIPTIVE_NAME)
set(_PKGCONFIG_DESCRIPTIVE_NAME "")
else()
set(_PKGCONFIG_DESCRIPTIVE_NAME "${USER_DESCRIPTIVE_NAME}")
endif()
if (DEFINED USER_INCLUDEDIRS)
set(tmp "")
foreach(dir ${USER_INCLUDEDIRS})
if (NOT IS_ABSOLUTE "${dir}")
list(APPEND tmp "-I\${includedir}/${dir}")
endif()
endforeach()
string(REPLACE ";" " " _INCLUDEDIRS "${tmp}")
endif()
if (DEFINED USER_REQUIRES)
string(REPLACE ";" ", " _PKGCONFIG_REQUIRES "${USER_REQUIRES}")
endif()
if (DEFINED USER_REQUIRES_PRIVATE)
string(REPLACE ";" ", " _PKGCONFIG_REQUIRES_PRIVATE "${USER_REQUIRES_PRIVATE}")
else()
set(_PKGCONFIG_REQUIRES_PRIVATE "")
endif()
if (NOT DEFINED USER_CFLAGS)
set(_PKGCONFIG_CFLAGS "-I\${includedir} ${_INCLUDEDIRS}")
endif()
if (NOT DEFINED USER_LIBS)
set(_PKGCONFIG_LIBS "-L\${libdir}")
else()
set(tmp "-L\${libdir}")
set(_libs "${USER_LIBS}")
foreach(lib ${_libs})
list(APPEND tmp "-l${lib}")
endforeach()
string(REPLACE ";" " " _PKGCONFIG_LIBS "${tmp}")
endif()
if (NOT DEFINED USER_LIBS_PRIVATE)
set(PKGCONFIG_LIBS "-L\${libdir}")
else()
set(tmp "")
set(_libs "${USER_LIBS_PRIVATE}")
foreach(lib ${_libs})
list(APPEND tmp "-l${lib}")
endforeach()
string(REPLACE ";" " " _PKGCONFIG_LIBS_PRIVATE "${tmp}")
endif()
if (DEFINED USER_DESCRIPTION)
set(_PKGCONFIG_DESCRIPTION "${USER_DESCRIPTION}")
else()
set(_PKGCONFIG_DESCRIPTION "")
endif()
if (DEFINED USER_URL)
set(_PKFCONFIG_URL "${USER_URL}")
else()
set(_PKGCONFIG_URL "")
endif()
if (NOT DEFINED USER_PATH)
set(_PKGCONFIG_FILE "${PROJECT_BINARY_DIR}/${_PKGCONFIG_PACKAGE_NAME}.pc")
else()
if (IS_ABSOLUTE "${USER_PATH}")
set(_PKGCONFIG_FILE "${USER_PATH}/${_PKGCONFIG_PACKAGE_NAME}.pc")
else()
set(_PKGCONFIG_FILE "${PROJECT_BINARY_DIR}/${USER_PATH}/${_PKGCONFIG_PACKAGE_NAME}.pc")
endif()
endif()
# Write the .pc file
FILE(WRITE "${_PKGCONFIG_FILE}"
"# file generated by create_pkgconfig_file()\n"
"prefix=${_PKGCONFIG_PREFIX}\n"
"exec_prefix=${_PKGCONFIG_EXEC_PREFIX}\n"
"libdir=${_PKGCONFIG_LIBDIR_PREFIX}\n"
"includedir=${_PKGCONFIG_INCLUDEDIR_PREFIX}\n"
"\n"
"Name: ${_PKGCONFIG_DESCRIPTIVE_NAME}\n"
)
if (NOT "${_PKGCONFIG_DESCRIPTION}" STREQUAL "")
FILE(APPEND ${_PKGCONFIG_FILE}
"Description: ${_PKGCONFIG_DESCRIPTION}\n"
)
endif()
if (NOT "${_PKGCONFIG_URL}" STREQUAL "")
FILE(APPEND ${_PKGCONFIG_FILE} "URL: ${_PKGCONFIG_URL}\n")
endif()
FILE(APPEND ${_PKGCONFIG_FILE} "Version: ${_PKGCONFIG_VERSION}\n")
if (NOT "${_PKGCONFIG_REQUIRES}" STREQUAL "")
FILE(APPEND ${_PKGCONFIG_FILE} "Requires: ${_PKGCONFIG_REQUIRES}\n")
endif()
if (NOT "${_PKGCONFIG_REQUIRES_PRIVATE}" STREQUAL "")
FILE(APPEND ${_PKGCONFIG_FILE}
"Requires.private: ${_PKGCONFIG_REQUIRES_PRIVATE}\n"
)
endif()
FILE(APPEND ${_PKGCONFIG_FILE}
"Cflags: ${_PKGCONFIG_CFLAGS}\n"
"Libs: ${_PKGCONFIG_LIBS}\n"
)
if (NOT "${_PKGCONFIG_LIBS_PRIVATE}" STREQUAL "")
FILE(APPEND ${_PKGCONFIG_FILE}
"Libs.private: ${_PKGCONFIG_REQUIRES_PRIVATE}\n"
)
endif()
if (DEFINED USER_INSTALL)
# FreeBSD loves to install files to different locations
# http://www.freebsd.org/doc/handbook/dirstructure.html
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(_PKGCONFIG_INSTALL_DESTINATION "libdata/pkgconfig")
else()
set(_PKGCONFIG_INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
# Make the COMPONENT an parameter ?
install(FILES "${_PKGCONFIG_FILE}"
DESTINATION "${_PKGCONFIG_INSTALL_DESTINATION}"
COMPONENT Devel)
endif()
endfunction()

@ -1,94 +0,0 @@
#=============================================================================
# Copyright 2015 Luís Pereira <luis.artur.pereira@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
# create_portable_headers(<portable_headers>
# HEADER_NAMES <CamelCaseName> [<CamelCaseName1> [...]]
# [OUTPUT_DIR <output_dir>]
# )
#
# Creates portable headers; e.g.:
# Creates XdgAction from xdgaction.h
# XdgAction contents:
# #include "xdgaction.h"
#
# Output:
# portable_headers File locations of the created headers
#
# Input:
# HEADER_NAMES Header CamelCaseNames. An CamelCaseName header will be created
# that includes camelcasename.h file
#
# OUTPUT_DIR Specifies where the files will be created. Defaults to
# ``${CMAKE_CURRENT_BINARY_DIR}``. If the value is an relative path, it
# will be appended to ``${CMAKE_CURRENT_BINARY_DIR}``.
#
# Use:
# set(PUBLIC_CLASSES MyClass YourClass)
# create_portable_headers(PORTABLE_HEADERS ${PUBLIC_CLASSES})
# PORTABLE_HEADER is an return value that contains the full name of the
# generated headers.
function(create_portable_headers outfiles)
set(options)
set(oneValueArgs OUTPUT_DIR)
set(multiValueArgs HEADER_NAMES)
cmake_parse_arguments(USER "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (USER_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to create_portable_headers(): \"${USER_UNPARSED_ARGUMENTS}\"")
endif()
if (NOT DEFINED USER_HEADER_NAMES)
message(FATAL_ERROR "Required argument HEADER_NAMES missing in create_portable_headers() call")
else()
set(_HEADER_NAMES "${USER_HEADER_NAMES}")
endif()
if (NOT DEFINED USER_OUTPUT_DIR)
set(_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
else()
if (IS_ABSOLUTE "${USER_OUTPUT_DIR}")
set(_OUTPUT_DIR "${USER_OUTPUT_DIR}")
else()
set(_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${USER_OUTPUT_DIR}")
endif()
endif()
set(class_list ${_HEADER_NAMES})
foreach(f ${class_list})
string(TOLOWER "${f}.h" _filename)
file(WRITE "${_OUTPUT_DIR}/${f}"
"#include \"${_filename}\"")
list(APPEND ${outfiles} "${_OUTPUT_DIR}/${f}")
endforeach()
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
endfunction()

@ -1,15 +0,0 @@
@PACKAGE_INIT@
if (NOT TARGET @QTXDGX_LIBRARY_NAME@)
include(CMakeFindDependencyMacro)
find_dependency(Qt5Widgets @QT_MINIMUM_VERSION@)
find_dependency(Qt5Xml @QT_MINIMUM_VERSION@)
find_dependency(Qt5DBus @QT_MINIMUM_VERSION@)
find_dependency(Qt5XdgIconLoader @QTXDG_VERSION_STRING@ EXACT)
if (CMAKE_VERSION VERSION_GREATER 2.8.12)
cmake_policy(SET CMP0024 NEW)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/qt5xdg-targets.cmake")
endif()

@ -1,13 +0,0 @@
@PACKAGE_INIT@
if (NOT TARGET @QTXDGX_ICONLOADER_LIBRARY_NAME@)
include(CMakeFindDependencyMacro)
find_dependency(Qt5Gui @QT_MINIMUM_REQUIRED@)
find_dependency(Qt5Svg @QT_MINIMUM_REQUIRED@)
if (CMAKE_VERSION VERSION_GREATER 2.8.12)
cmake_policy(SET CMP0024 NEW)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/qt5xdgiconloader-targets.cmake")
endif()

@ -1,6 +0,0 @@
project(use-qtxdg)
cmake_minimum_required(VERSION 2.8.12)
find_package(QT5XDG)
add_executable(use-qtxdg main.cpp)
target_link_libraries(use-qtxdg Qt5Xdg)

@ -1,4 +0,0 @@
An example of how to write an CMakeLists.txt to use libqtxdg.
To build this example just use:
cmake ..

@ -1,8 +0,0 @@
#include <XdgDirs>
#include <QDebug>
int main(int argc, char **argv)
{
qDebug() << XdgDirs::dataDirs();
return 0;
}

@ -1,138 +0,0 @@
set(QTX_LIBRARIES Qt5::Widgets Qt5::Xml Qt5::DBus)
set(libqtxdg_PUBLIC_H_FILES
xdgaction.h
xdgdesktopfile.h
xdgdirs.h
xdgicon.h
xdgmenu.h
xdgmenuwidget.h
xmlhelper.h
xdgautostart.h
xdgmacros.h
xdgmimetype.h
)
set(libqtxdg_PUBLIC_CLASSES
XdgAction
XdgDesktopFile
XdgDirs
XdgIcon
XdgMenu
XdgMenuWidget
XmlHelper
XdgAutoStart
XdgMimeType
)
set(libqtxdg_PRIVATE_H_FILES
xdgmenuapplinkprocessor.h
xdgmenulayoutprocessor.h
xdgmenu_p.h
xdgmenureader.h
xdgmenurules.h
xdgdesktopfile_p.h
)
set(libqtxdg_CPP_FILES
xdgaction.cpp
xdgdesktopfile.cpp
xdgdirs.cpp
xdgicon.cpp
xdgmenuapplinkprocessor.cpp
xdgmenu.cpp
xdgmenulayoutprocessor.cpp
xdgmenureader.cpp
xdgmenurules.cpp
xdgmenuwidget.cpp
xmlhelper.cpp
xdgautostart.cpp
xdgmimetype.cpp
)
set(libqtxdg_MOCS
xdgaction.h
xdgmenuapplinkprocessor.h
xdgmenu.h
xdgmenu_p.h
xdgmenureader.h
xdgmenurules.h
xdgmenuwidget.h
)
add_library(${QTXDGX_LIBRARY_NAME} SHARED
${libqtxdg_PUBLIC_H_FILES}
${libqtxdg_PRIVATE_H_FILES}
${libqtxdg_CPP_FILES}
${libqtxdg_MOCS}
)
target_link_libraries(${QTXDGX_LIBRARY_NAME}
PUBLIC
${QTX_LIBRARIES}
${QTXDGX_ICONLOADER_LIBRARY_NAME}
)
set_target_properties(${QTXDGX_LIBRARY_NAME} PROPERTIES
VERSION ${QTXDG_VERSION_STRING}
SOVERSION ${QTXDG_MAJOR_VERSION}
)
target_compile_definitions(${QTXDGX_LIBRARY_NAME}
PRIVATE
"QTXDG_COMPILATION=\"1\""
"QTXDG_VERSION=\"${QTXDG_VERSION_STRING}\""
"QT_NO_KEYWORDS"
)
target_include_directories(${QTXDGX_LIBRARY_NAME}
INTERFACE
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
"$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}>"
"$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}>"
PRIVATE
${Qt5Gui_PRIVATE_INCLUDE_DIRS}
)
# create the portble headers
create_portable_headers(libqtxdg_PORTABLE_HEADERS
HEADER_NAMES ${libqtxdg_PUBLIC_CLASSES}
OUTPUT_DIR "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}"
)
# Copy public headers (in tree building)
foreach(h ${libqtxdg_PUBLIC_H_FILES})
get_filename_component(bh ${h} NAME)
configure_file(${h} "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}/${bh}" COPYONLY)
endforeach()
# Copy private headers (in tree building)
foreach(h ${libqtxdg_PRIVATE_INSTALLABLE_H_FILES})
get_filename_component(bh ${h} NAME)
configure_file(${h} "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}/${QTXDG_VERSION_STRING}/private/qtxdg/${bh}" COPYONLY)
endforeach()
install(TARGETS
${QTXDGX_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}"
EXPORT "${QTXDGX_FILE_NAME}-targets"
COMPONENT Runtime
)
install(FILES
${libqtxdg_PUBLIC_H_FILES}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}"
COMPONENT Devel
)
install(FILES
${libqtxdg_PRIVATE_INSTALLABLE_H_FILES}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}/${QTXDG_VERSION_STRING}/private/qtxdg"
COMPONENT Devel
)
install(FILES
${libqtxdg_PORTABLE_HEADERS}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}"
COMPONENT Devel
)

@ -1,37 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2014 LXQt team
* Authors:
* Luís Pereira <luis.artur.pereira@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include <QtCore/QByteArray>
static inline QByteArray detectDesktopEnvironment()
{
const QByteArray _desktop = qgetenv("XDG_CURRENT_DESKTOP");
if (!_desktop.isEmpty()) {
return _desktop.toUpper();
}
return QByteArray("UNKNOWN");
}

@ -1,122 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgaction.h"
#include "xdgicon.h"
#include <QDebug>
#include <QCoreApplication>
XdgAction::XdgAction(QObject *parent):
QAction(parent)
{
}
XdgAction::XdgAction(const XdgDesktopFile& desktopFile, QObject *parent):
QAction(parent)
{
load(desktopFile);
}
XdgAction::XdgAction(const XdgDesktopFile* desktopFile, QObject *parent):
QAction(parent)
{
load(*desktopFile);
}
XdgAction::XdgAction(const QString& desktopFileName, QObject *parent):
QAction(parent)
{
XdgDesktopFile df;
df.load(desktopFileName);
load(df);
}
XdgAction::XdgAction(const XdgAction& other, QObject *parent):
QAction(parent)
{
load(other.mDesktopFile);
}
XdgAction::~XdgAction()
{
}
XdgAction& XdgAction::operator=(const XdgAction& other)
{
load(other.mDesktopFile);
return *this;
}
bool XdgAction::isValid() const
{
return mDesktopFile.isValid();
}
void XdgAction::load(const XdgDesktopFile& desktopFile)
{
mDesktopFile = desktopFile;
if (mDesktopFile.isValid())
{
// & is reserved for mnemonics
setText(mDesktopFile.name().replace(QLatin1Char('&'), QLatin1String("&&")));
setToolTip(mDesktopFile.comment());
connect(this, SIGNAL(triggered()), this, SLOT(runConmmand()));
QMetaObject::invokeMethod(this, "updateIcon", Qt::QueuedConnection);
}
else
{
setText(QString());
setToolTip(QString());
setIcon(QIcon());
}
}
void XdgAction::runConmmand() const
{
if (mDesktopFile.isValid())
mDesktopFile.startDetached();
}
void XdgAction::updateIcon()
{
setIcon(mDesktopFile.icon());
if (icon().isNull())
setIcon(XdgIcon::fromTheme(QLatin1String("application-x-executable")));
QCoreApplication::processEvents();
}

@ -1,84 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGACTION_H
#define QTXDG_XDGACTION_H
#include "xdgmacros.h"
#include "xdgdesktopfile.h"
#include <QAction>
#include <QString>
/*******************************************************************/ /*!
@brief The XdgAction class provides an QAction object based on XdgDesktopFile.
The following properties of the action are set based on the desktopFile.
Text - XdgDesktopFile localizeValue("Name")
Icon - XdgDesktopFile icon()
ToolTip - XdgDesktopFile localizeValue("Comment")
Internally this function will create a copy of the desktopFile, so you
can delete original XdgDesktopFile object.
When an action is activated by the user; for example, when the user clicks
a menu option, toolbar button or when trigger() was called, XdgAction start
the application defined in XdgDesktopFile. @sa XdgDesktopFile::startDetached.
****************************************/
//*******************************************************************
class QTXDG_API XdgAction : public QAction
{
Q_OBJECT
public:
explicit XdgAction(QObject *parent=0);
explicit XdgAction(const XdgDesktopFile& desktopFile, QObject *parent=0);
explicit XdgAction(const XdgDesktopFile* desktopFile, QObject *parent=0);
explicit XdgAction(const QString& desktopFileName, QObject *parent=0);
// Constructs a XdgAction that is a copy of the given XdgAction.
explicit XdgAction(const XdgAction& other, QObject *parent=0);
/// Destroys the object and frees allocated resources.
virtual ~XdgAction();
XdgAction& operator=(const XdgAction& other);
//! Returns true if the XdgAction is valid; otherwise returns false.
bool isValid() const;
const XdgDesktopFile& desktopFile() const { return mDesktopFile; }
private Q_SLOTS:
void runConmmand() const;
void updateIcon();
private:
void load(const XdgDesktopFile& desktopFile);
XdgDesktopFile mDesktopFile;
};
#endif // QTXDG_XDGACTION_H

@ -1,92 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2012 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgautostart.h"
#include "xdgdirs.h"
#include <QDebug>
#include <QSet>
#include <QDir>
/**
* The Autostart Directories are $XDG_CONFIG_DIRS/autostart. If the same filename is
* located under multiple Autostart Directories only the file under the most
* important directory should be used.
*
* When multiple .desktop files with the same name exists in multiple directories
* then only the Hidden key in the most important .desktop file must be considered:
* If it is set to true all .desktop files with the same name in the other
* directories MUST be ignored as well.
*/
XdgDesktopFileList XdgAutoStart::desktopFileList(bool excludeHidden)
{
QStringList dirs;
dirs << XdgDirs::autostartHome(false) << XdgDirs::autostartDirs();
return desktopFileList(dirs, excludeHidden);
}
XdgDesktopFileList XdgAutoStart::desktopFileList(QStringList dirs, bool excludeHidden)
{
dirs.removeDuplicates();
QSet<QString> processed;
XdgDesktopFileList ret;
for (const QString &dirName : const_cast<const QStringList&>(dirs))
{
QDir dir(dirName);
if (!dir.exists())
continue;
const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files | QDir::Readable);
for (const QFileInfo &fi : files)
{
if (processed.contains(fi.fileName()))
continue;
processed << fi.fileName();
XdgDesktopFile desktop;
if (!desktop.load(fi.absoluteFilePath()))
continue;
if (!desktop.isSuitable(excludeHidden))
continue;
ret << desktop;
}
}
return ret;
}
QString XdgAutoStart::localPath(const XdgDesktopFile& file)
{
QFileInfo fi(file.fileName());
return QString::fromLatin1("%1/%2").arg(XdgDirs::autostartHome(), fi.fileName());
}

@ -1,59 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2012 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGAUTOSTART_H
#define QTXDG_XDGAUTOSTART_H
#include "xdgmacros.h"
#include "xdgdesktopfile.h"
/*! @brief The XdgAutoStart class implements the "Desktop Application Autostart Specification"
* from freedesktop.org.
* This specification defines a method for automatically starting applications during the startup
* of a desktop environment and after mounting a removable medium.
* Now we impliment only startup.
*
* @sa http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
*/
class QTXDG_API XdgAutoStart
{
public:
/*! Returns a list of XdgDesktopFile objects for all the .desktop files in the Autostart directories
When the .desktop file has the Hidden key set to true, the .desktop file must be ignored. But you
can change this behavior by setting excludeHidden to false. */
static XdgDesktopFileList desktopFileList(bool excludeHidden=true);
/*! Returns a list of XdgDesktopFile objects for .desktop files in the specified Autostart directories
When the .desktop file has the Hidden key set to true, the .desktop file must be ignored. But you
can change this behavior by setting excludeHidden to false. */
static XdgDesktopFileList desktopFileList(QStringList dirs, bool excludeHidden=true);
/// For XdgDesktopFile returns the file path of the same name in users personal autostart directory.
static QString localPath(const XdgDesktopFile& file);
};
#endif // XDGAUTOSTART_H

File diff suppressed because it is too large Load Diff

@ -1,293 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGDESKTOPFILE_H
#define QTXDG_XDGDESKTOPFILE_H
#include "xdgmacros.h"
#include <QSharedDataPointer>
#include <QString>
#include <QVariant>
#include <QStringList>
#include <QtGui/QIcon>
#include <QSettings>
class XdgDesktopFileData;
/**
\brief Desktop files handling.
XdgDesktopFile class gives the interface for reading the values from the XDG .desktop file.
The interface of this class is similar on QSettings. XdgDesktopFile objects can be passed
around by value since the XdgDesktopFile class uses implicit data sharing.
The Desktop Entry Specification defines 3 types of desktop entries: Application, Link and
Directory. The format of .desktop file is described on
http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
Note that not all methods in this class make sense for all types of desktop files.
\author Alexander Sokoloff <sokoloff.a@gmail.com>
*/
class QTXDG_API XdgDesktopFile
{
public:
/*! The Desktop Entry Specification defines 3 types of desktop entries: Application, Link and
Directory. File type is determined by the "Type" tag. */
enum Type
{
UnknownType, //! Unknown desktop file type. Maybe is invalid.
ApplicationType, //! The file describes application.
LinkType, //! The file describes URL.
DirectoryType //! The file describes directory settings.
};
//! Constructs an empty XdgDesktopFile
XdgDesktopFile();
/*! Constructs a copy of other.
This operation takes constant time, because XdgDesktopFile is implicitly shared. This makes
returning a XdgDesktopFile from a function very fast. If a shared instance is modified,
it will be copied (copy-on-write), and that takes linear time. */
XdgDesktopFile(const XdgDesktopFile& other);
/*! Constructs a new basic DesktopFile. If type is:
- ApplicationType, "value" should be the Exec value;
- LinkType, "value" should be the URL;
- DirectoryType, "value" should be omitted */
XdgDesktopFile(XdgDesktopFile::Type type, const QString& name, const QString& value = QString());
//! Destroys the object.
virtual ~XdgDesktopFile();
//! Assigns other to this DesktopFile and returns a reference to this DesktopFile.
XdgDesktopFile& operator=(const XdgDesktopFile& other);
//! Returns true if both files contain the identical key-value pairs
bool operator==(const XdgDesktopFile &other) const;
//! Returns false if both files contain the identical key-value pairs
inline bool operator!=(const XdgDesktopFile &other) const
{
return !operator==(other);
}
//! Loads an DesktopFile from the file with the given fileName.
virtual bool load(const QString& fileName);
//! Saves the DesktopFile to the file with the given fileName. Returns true if successful; otherwise returns false.
virtual bool save(const QString &fileName) const;
/*! This is an overloaded function.
This function writes a DesktopFile to the given device. */
virtual bool save(QIODevice *device) const;
/*! Returns the value for key. If the key doesn't exist, returns defaultValue.
If no default value is specified, a default QVariant is returned. */
QVariant value(const QString& key, const QVariant& defaultValue = QVariant()) const;
/*! Returns the localized value for key. In the desktop file keys may be postfixed by [LOCALE]. If the
localized value doesn't exist, returns non lokalized value. If non localized value doesn't exist, returns defaultValue.
LOCALE must be of the form lang_COUNTRY.ENCODING@MODIFIER, where _COUNTRY, .ENCODING, and @MODIFIER may be omitted.
If no default value is specified, a default QVariant is returned. */
QVariant localizedValue(const QString& key, const QVariant& defaultValue = QVariant()) const;
//! Sets the value of setting key to value. If the key already exists, the previous value is overwritten.
void setValue(const QString &key, const QVariant &value);
/*! Sets the value of setting key to value. If a localized version of the key already exists, the previous value is
overwritten. Otherwise, it overwrites the the un-localized version. */
void setLocalizedValue(const QString &key, const QVariant &value);
//! Removes the entry with the specified key, if it exists.
void removeEntry(const QString& key);
//! Returns the entry Categories. It supports X-Categories extensions.
QStringList categories() const;
//! Returns list of values in entry Actions.
QStringList actions() const;
//! Returns true if there exists a setting called key; returns false otherwise.
bool contains(const QString& key) const;
//! Returns true if the XdgDesktopFile is valid; otherwise returns false.
bool isValid() const;
/*! Returns the file name of the desktop file.
* Returns QString() if the file wasn't found when load was called. */
QString fileName() const;
//! Returns an icon specified in this file.
QIcon const icon(const QIcon& fallback = QIcon()) const;
//! Returns an icon for application action \param action.
QIcon const actionIcon(const QString & action, const QIcon& fallback = QIcon()) const;
//! Returns an icon name specified in this file.
QString const iconName() const;
//! Returns an icon name for application action \param action.
QString const actionIconName(const QString & action) const;
//! Returns an list of mimetypes specified in this file.
/*! @return Returns a list of the "MimeType=" entries.
* If the file doens't contain the MimeType entry, an empty QStringList is
* returned. Empty values are removed from the returned list.
*/
QStringList mimeTypes() const;
//! This function is provided for convenience. It's equivalent to calling localizedValue("Name").toString().
QString name() const { return localizedValue(QLatin1String("Name")).toString(); }
//! Returns an (localized) name for application action \param action.
QString actionName(const QString & action) const;
//! This function is provided for convenience. It's equivalent to calling localizedValue("Comment").toString().
QString comment() const { return localizedValue(QLatin1String("Comment")).toString(); }
/*! Returns the desktop file type.
@see XdgDesktopFile::Type */
Type type() const;
/*! For file with Application type. Starts the program with the optional urls in a new process, and detaches from it.
Returns true on success; otherwise returns false.
@par urls - A list of files or URLS. Each file is passed as a separate argument to the executable program.
For file with Link type. Opens URL in the associated application. Parametr urls is not used.
For file with Directory type, do nothing. */
bool startDetached(const QStringList& urls) const;
//! This function is provided for convenience. It's equivalent to calling startDetached(QStringList(url)).
bool startDetached(const QString& url = QString()) const;
/*! For file with Application type. Activates action defined by the \param action. Action is activated
* either with the [Desktop Action %s]/Exec or by the D-Bus if the [Desktop Entry]/DBusActivatable is set.
* \note Starting is done the same way as \sa startDetached()
*
* \return true on success; otherwise returns false.
* \param urls - A list of files or URLS. Each file is passed as a separate argument to the executable program.
*
* For file with Link type, do nothing.
*
* For file with Directory type, do nothing.
*/
bool actionActivate(const QString & action, const QStringList & urls) const;
/*! A Exec value consists of an executable program optionally followed by one or more arguments.
This function expands this arguments and returns command line string parts.
Note this method make sense only for Application type.
@par urls - A list of files or URLS. Each file is passed as a separate argument to the result string program.*/
QStringList expandExecString(const QStringList& urls = QStringList()) const;
/*! Returns the URL for the Link desktop file; otherwise an empty string is returned. */
QString url() const;
/*! Computes the desktop file ID. It is the identifier of an installed
* desktop entry file.
* @par fileName - The desktop file complete name.
* @par checkFileExists If true and the file doesn't exist the computed ID
* will be an empty QString(). Defaults to true.
* @return The computed ID. Returns an empty QString() if it's impossible to
* compute the ID. Reference:
* https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id
*/
static QString id(const QString &fileName, bool checkFileExists = true);
/*! The desktop entry specification defines a number of fields to control
the visibility of the application menu. Thisfunction checks whether
to display a this application or not.
@par environment - User supplied desktop environment name. If not
supplied the desktop will be detected reading the
XDG_CURRENT_DESKTOP environment variable. If not set, "UNKNOWN"
will be used as the desktop name. All operations envolving the
desktop environment name are case insensitive.
*/
bool isShown(const QString &environment = QString()) const;
/*! This fuction returns true if the desktop file is applicable to the
current environment.
@par excludeHidden - if set to true (default), files with
"Hidden=true" will be considered "not applicable". Setting this
to false is be useful when the user wants to enable/disable items
and wants to see those that are Hidden
@par environment - User supplied desktop environment name. If not
supplied the desktop will be detected reading the
XDG_CURRENT_DESKTOP environment variable. If not set, "UNKNOWN"
will be used as the desktop name. All operations envolving the
desktop environment name are case insensitive.
*/
bool isSuitable(bool excludeHidden = true, const QString &environment = QString()) const;
protected:
virtual QString prefix() const { return QLatin1String("Desktop Entry"); }
virtual bool check() const { return true; }
private:
/*! Returns the localized version of the key if the Desktop File already contains a localized version of it.
If not, returns the same key back */
QString localizedKey(const QString& key) const;
QSharedDataPointer<XdgDesktopFileData> d;
};
/// Synonym for QList<XdgDesktopFile>
typedef QList<XdgDesktopFile> XdgDesktopFileList;
class QTXDG_API XdgDesktopFileCache
{
public:
static XdgDesktopFile* getFile(const QString& fileName);
static QList<XdgDesktopFile*> getAllFiles();
static QList<XdgDesktopFile*> getApps(const QString & mimeType);
static XdgDesktopFile* getDefaultApp(const QString& mimeType);
static QSettings::Format desktopFileSettingsFormat();
/*! Return all desktop apps that have category for their Categories key
* Note that, according to xdg's spec, for non-standard categories "X-"
* is added to the beginning of the category's name. This method takes care
* of both cases.
* See http://standards.freedesktop.org/menu-spec/menu-spec-latest.html#desktop-entry-extensions
*/
static QList<XdgDesktopFile*> getAppsOfCategory(const QString &category);
private:
static XdgDesktopFileCache & instance();
static XdgDesktopFile* load(const QString & fileName);
XdgDesktopFileCache();
~XdgDesktopFileCache();
void initialize();
void initialize(const QString & dirName);
bool m_IsInitialized;
QHash<QString, QList<XdgDesktopFile*> > m_defaultAppsCache;
QHash<QString, XdgDesktopFile*> m_fileCache;
};
#endif // QTXDG_XDGDESKTOPFILE_H

@ -1,34 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2015 LXQt team
* Authors:
* Luís Pereira <luis.artur.pereira@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef XDGDESKTOPFILE_P_H
#define XDGDESKTOPFILE_P_H
QTXDG_AUTOTEST bool readDesktopFile(QIODevice & device, QSettings::SettingsMap & map);
QTXDG_AUTOTEST bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map);
#endif // XDGDESKTOPFILE_P_H

@ -1,343 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgdirs.h"
#include <stdlib.h>
#include <QDir>
#include <QDebug>
#include <QStandardPaths>
static const QString userDirectoryString[8] =
{
QLatin1String("Desktop"),
QLatin1String("Download"),
QLatin1String("Templates"),
QLatin1String("Publicshare"),
QLatin1String("Documents"),
QLatin1String("Music"),
QLatin1String("Pictures"),
QLatin1String("Videos")
};
// Helper functions prototypes
void fixBashShortcuts(QString &s);
void removeEndingSlash(QString &s);
QString createDirectory(const QString &dir);
void cleanAndAddPostfix(QStringList &dirs, const QString& postfix);
QString userDirFallback(XdgDirs::UserDirectory dir);
/************************************************
Helper func.
************************************************/
void fixBashShortcuts(QString &s)
{
if (s.startsWith(QLatin1Char('~')))
s = QFile::decodeName(qgetenv("HOME")) + (s).mid(1);
}
void removeEndingSlash(QString &s)
{
// We don't check for empty strings. Caller must check it.
// Remove the ending slash, except for root dirs.
if (s.length() > 1 && s.endsWith(QLatin1Char('/')))
s.chop(1);
}
QString createDirectory(const QString &dir)
{
QDir d(dir);
if (!d.exists())
{
if (!d.mkpath(QLatin1String(".")))
{
qWarning() << QString::fromLatin1("Can't create %1 directory.").arg(d.absolutePath());
}
}
QString r = d.absolutePath();
removeEndingSlash(r);
return r;
}
void cleanAndAddPostfix(QStringList &dirs, const QString& postfix)
{
const int N = dirs.count();
for(int i = 0; i < N; ++i)
{
fixBashShortcuts(dirs[i]);
removeEndingSlash(dirs[i]);
dirs[i].append(postfix);
}
}
QString userDirFallback(XdgDirs::UserDirectory dir)
{
QString fallback;
const QString home = QFile::decodeName(qgetenv("HOME"));
if (home.isEmpty())
return QString::fromLatin1("/tmp");
else if (dir == XdgDirs::Desktop)
fallback = QString::fromLatin1("%1/%2").arg(home, QLatin1String("Desktop"));
else
fallback = home;
return fallback;
}
QString XdgDirs::userDirDefault(XdgDirs::UserDirectory dir)
{
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return QString();
return userDirFallback(dir);
}
QString XdgDirs::userDir(XdgDirs::UserDirectory dir)
{
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return QString();
QString folderName = userDirectoryString[dir];
const QString fallback = userDirFallback(dir);
QString configDir(configHome());
QFile configFile(configDir + QLatin1String("/user-dirs.dirs"));
if (!configFile.exists())
return fallback;
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text))
return fallback;
QString userDirVar(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR"));
QTextStream in(&configFile);
QString line;
while (!in.atEnd())
{
line = in.readLine();
if (line.contains(userDirVar))
{
configFile.close();
// get path between quotes
line = line.section(QLatin1Char('"'), 1, 1);
if (line.isEmpty())
return fallback;
line.replace(QLatin1String("$HOME"), QLatin1String("~"));
fixBashShortcuts(line);
return line;
}
}
configFile.close();
return fallback;
}
bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool createDir)
{
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return false;
const QString home = QFile::decodeName(qgetenv("HOME"));
if (!(value.startsWith(QLatin1String("$HOME"))
|| value.startsWith(QLatin1String("~/"))
|| value.startsWith(home)
|| value.startsWith(QDir(home).canonicalPath())))
return false;
QString folderName = userDirectoryString[dir];
QString configDir(configHome());
QFile configFile(configDir + QLatin1String("/user-dirs.dirs"));
// create the file if doesn't exist and opens it
if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text))
return false;
QTextStream stream(&configFile);
QVector<QString> lines;
QString line;
bool foundVar = false;
while (!stream.atEnd())
{
line = stream.readLine();
if (line.indexOf(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR")) == 0)
{
foundVar = true;
QString path = line.section(QLatin1Char('"'), 1, 1);
line.replace(path, value);
lines.append(line);
}
else if (line.indexOf(QLatin1String("XDG_")) == 0)
{
lines.append(line);
}
}
stream.reset();
configFile.resize(0);
if (!foundVar)
stream << QString::fromLatin1("XDG_%1_DIR=\"%2\"\n").arg(folderName.toUpper(),(value));
for (QVector<QString>::iterator i = lines.begin(); i != lines.end(); ++i)
stream << *i << QLatin1Char('\n');
configFile.close();
if (createDir) {
QString path = QString(value).replace(QLatin1String("$HOME"), QLatin1String("~"));
fixBashShortcuts(path);
QDir().mkpath(path);
}
return true;
}
QString XdgDirs::dataHome(bool createDir)
{
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
}
QString XdgDirs::configHome(bool createDir)
{
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
}
QStringList XdgDirs::dataDirs(const QString &postfix)
{
QString d = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
QStringList dirs = d.split(QLatin1Char(':'), QString::SkipEmptyParts);
if (dirs.isEmpty()) {
dirs.append(QString::fromLatin1("/usr/local/share"));
dirs.append(QString::fromLatin1("/usr/share"));
} else {
QMutableListIterator<QString> it(dirs);
while (it.hasNext()) {
const QString dir = it.next();
if (!dir.startsWith(QLatin1Char('/')))
it.remove();
}
}
dirs.removeDuplicates();
cleanAndAddPostfix(dirs, postfix);
return dirs;
}
QStringList XdgDirs::configDirs(const QString &postfix)
{
QStringList dirs;
const QString env = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
if (env.isEmpty())
dirs.append(QString::fromLatin1("/etc/xdg"));
else
dirs = env.split(QLatin1Char(':'), QString::SkipEmptyParts);
cleanAndAddPostfix(dirs, postfix);
return dirs;
}
QString XdgDirs::cacheHome(bool createDir)
{
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
}
QString XdgDirs::runtimeDir()
{
QString result = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
fixBashShortcuts(result);
removeEndingSlash(result);
return result;
}
QString XdgDirs::autostartHome(bool createDir)
{
QString s = QString::fromLatin1("%1/autostart").arg(configHome(createDir));
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
QDir d(s);
QString r = d.absolutePath();
removeEndingSlash(r);
return r;
}
QStringList XdgDirs::autostartDirs(const QString &postfix)
{
QStringList dirs;
const QStringList s = configDirs();
for (const QString &dir : s)
dirs << QString::fromLatin1("%1/autostart").arg(dir) + postfix;
return dirs;
}

@ -1,155 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGDIRS_H
#define QTXDG_XDGDIRS_H
#include "xdgmacros.h"
#include <QString>
#include <QStringList>
/*! @brief The XdgMenu class implements the "XDG Base Directory Specification" from freedesktop.org.
* This specification defines where these files should be looked for by defining one or more base
* directories relative to which files should be located.
*
* All postfix parameters should start with an '/' slash.
*
* @sa http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*/
class QTXDG_API XdgDirs
{
public:
enum UserDirectory
{
Desktop,
Download,
Templates,
PublicShare,
Documents,
Music,
Pictures,
Videos
};
/*! @brief Returns the path to the user folder passed as parameter dir defined in
* $XDG_CONFIG_HOME/user-dirs.dirs. Returns /tmp if no $HOME defined, $HOME/Desktop if
* dir equals XdgDirs::Desktop or $HOME othewise.
*/
static QString userDir(UserDirectory dir);
/*! @brief Returns the default path to the user specified directory.
* Returns /tmp if no $HOME defined, $HOME/Desktop if dir equals
* XdgDirs::Desktop or $HOME othewise. If dir value is invalid, an empty
* QString is returned.
*/
static QString userDirDefault(UserDirectory dir);
/*! @brief Returns true if writting into configuration file $XDG_CONFIG_HOME/user-dirs.dirs
* the path in value for the directory in dir is succesfull. Returns false otherwise. If
* createDir is true, dir will be created if it doesn't exist.
*/
static bool setUserDir(UserDirectory dir, const QString &value, bool createDir);
/*! @brief Returns the path to the directory that corresponds to the $XDG_DATA_HOME.
* If @i createDir is true, the function will create the directory.
*
* $XDG_DATA_HOME defines the base directory relative to which user specific data files
* should be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to
* $HOME/.local/share should be used.
*/
static QString dataHome(bool createDir=true);
/*! @brief Returns the path to the directory that corresponds to the $XDG_CONFIG_HOME.
* If @i createDir is true, the function will create the directory.
*
* $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration
* files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal
* to $HOME/.config should be used.
*/
static QString configHome(bool createDir=true);
/*! @brief Returns a list of all directories that corresponds to the $XDG_DATA_DIRS.
* $XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data
* files in addition to the $XDG_DATA_HOME base directory. If $XDG_DATA_DIRS is either not set
* or empty, a value equal to /usr/local/share:/usr/share is used.
*
* If the postfix is not empty it will append to end of each returned directory.
*/
static QStringList dataDirs(const QString &postfix = QString());
/*! @brief Returns a list of all directories that corresponds to the $XDG_CONFIG_DIRS.
* $XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for
* configuration files in addition to the $XDG_CONFIG_HOME base directory. If $XDG_CONFIG_DIRS
* is either not set or empty, a value equal to /etc/xdg should be used.
*
* If the postfix is not empty it will append to end of each returned directory.
*/
static QStringList configDirs(const QString &postfix = QString());
/*! @brief Returns the path to the directory that corresponds to the $XDG_CACHE_HOME.
* If @i createDir is true, the function will create the directory.
*
* $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential
* data files should be stored. If $XDG_CACHE_HOME is either not set or empty,
* a default equal to $HOME/.cache should be used.
*/
static QString cacheHome(bool createDir=true);
/*! @brief Returns the path to the directory that corresponds to the $XDG_RUNTIME_DIR.
* $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential
* runtime files and other file objects (such as sockets, named pipes, ...) should be stored.
* The directory MUST be owned by the user, and he MUST be the only one having read and write
* access to it. Its Unix access mode MUST be 0700.
*/
static QString runtimeDir();
/*! @brief Returns the path to the directory that corresponds to the $XDG_CONFIG_HOME/autostart
*
* If $XDG_CONFIG_HOME is not set, the Autostart Directory in the user's home directory is
* ~/.config/autostart/
*/
static QString autostartHome(bool createDir=true);
/*! @brief Returns a list of all directories that correspond to $XDG_CONFIG_DIRS/autostart
* If $XDG_CONFIG_DIRS is not set, the system wide Autostart Directory is /etc/xdg/autostart
*
* If the postfix is not empty it will append to end of each returned directory.
*
* Note: this does not include the user's autostart directory
* @sa autostartHome()
*/
static QStringList autostartDirs(const QString &postfix = QString());
};
#endif // QTXDG_XDGDIRS_H

@ -1,169 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgicon.h"
#include <QString>
#include <QDebug>
#include <QDir>
#include <QStringList>
#include <QFileInfo>
#include <QCache>
#include "../xdgiconloader/xdgiconloader_p.h"
#include <QCoreApplication>
static const QLatin1String DEFAULT_APP_ICON("application-x-executable");
static void qt_cleanup_icon_cache();
typedef QCache<QString, QIcon> IconCache;
namespace {
struct QtIconCache: public IconCache
{
QtIconCache()
{
qAddPostRoutine(qt_cleanup_icon_cache);
}
};
}
Q_GLOBAL_STATIC(IconCache, qtIconCache)
static void qt_cleanup_icon_cache()
{
qtIconCache()->clear();
}
XdgIcon::XdgIcon()
{
}
XdgIcon::~XdgIcon()
{
}
/************************************************
Returns the QIcon corresponding to name in the current icon theme. If no such icon
is found in the current theme fallback is return instead.
************************************************/
QIcon XdgIcon::fromTheme(const QString& iconName, const QIcon& fallback)
{
if (iconName.isEmpty())
return fallback;
bool isAbsolute = (iconName[0] == QLatin1Char('/'));
QString name = QFileInfo(iconName).fileName();
if (name.endsWith(QLatin1String(".png"), Qt::CaseInsensitive) ||
name.endsWith(QLatin1String(".svg"), Qt::CaseInsensitive) ||
name.endsWith(QLatin1String(".xpm"), Qt::CaseInsensitive))
{
name.truncate(name.length() - 4);
}
QIcon icon;
if (qtIconCache()->contains(name)) {
icon = *qtIconCache()->object(name);
} else {
QIcon *cachedIcon;
if (!isAbsolute)
cachedIcon = new QIcon(new XdgIconLoaderEngine(name));
else
cachedIcon = new QIcon(iconName);
icon = *cachedIcon;
qtIconCache()->insert(name, cachedIcon);
}
// Note the qapp check is to allow lazy loading of static icons
// Supporting fallbacks will not work for this case.
if (qApp && !isAbsolute && icon.availableSizes().isEmpty())
{
return fallback;
}
return icon;
}
/************************************************
Returns the QIcon corresponding to names in the current icon theme. If no such icon
is found in the current theme fallback is return instead.
************************************************/
QIcon XdgIcon::fromTheme(const QStringList& iconNames, const QIcon& fallback)
{
for (const QString &iconName : iconNames)
{
QIcon icon = fromTheme(iconName);
if (!icon.isNull())
return icon;
}
return fallback;
}
QIcon XdgIcon::fromTheme(const QString &iconName,
const QString &fallbackIcon1,
const QString &fallbackIcon2,
const QString &fallbackIcon3,
const QString &fallbackIcon4)
{
QStringList icons;
icons << iconName;
if (!fallbackIcon1.isEmpty()) icons << fallbackIcon1;
if (!fallbackIcon2.isEmpty()) icons << fallbackIcon2;
if (!fallbackIcon3.isEmpty()) icons << fallbackIcon3;
if (!fallbackIcon4.isEmpty()) icons << fallbackIcon4;
return fromTheme(icons);
}
bool XdgIcon::followColorScheme()
{
return XdgIconLoader::instance()->followColorScheme();
}
void XdgIcon::setFollowColorScheme(bool enable)
{
XdgIconLoader::instance()->setFollowColorScheme(enable);
}
QIcon XdgIcon::defaultApplicationIcon()
{
return fromTheme(DEFAULT_APP_ICON);
}
QString XdgIcon::defaultApplicationIconName()
{
return DEFAULT_APP_ICON;
}

@ -1,71 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGICON_H
#define QTXDG_XDGICON_H
#include "xdgmacros.h"
#include <QtGui/QIcon>
#include <QString>
#include <QStringList>
class QTXDG_API XdgIcon
{
public:
static QIcon fromTheme(const QString& iconName, const QIcon& fallback = QIcon());
static QIcon fromTheme(const QString& iconName,
const QString &fallbackIcon1,
const QString &fallbackIcon2 = QString(),
const QString &fallbackIcon3 = QString(),
const QString &fallbackIcon4 = QString());
static QIcon fromTheme(const QStringList& iconNames, const QIcon& fallback = QIcon());
/*!
* Flag if the "FollowsColorScheme" hint (the KDE extension to XDG
* themes) should be honored. If enabled and the icon theme supports
* this, the icon engine "colorizes" icons based on the application's
* palette.
*
* Default is true (use this extension).
*/
static bool followColorScheme();
static void setFollowColorScheme(bool enable);
/* TODO: deprecate & remove all QIcon wrappers */
static QString themeName() { return QIcon::themeName(); }
static void setThemeName(const QString& themeName) { QIcon::setThemeName(themeName); }
static QIcon defaultApplicationIcon();
static QString defaultApplicationIconName();
protected:
explicit XdgIcon();
virtual ~XdgIcon();
private:
};
#endif // QTXDG_XDGICON_H

@ -1,45 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs
* Copyright (C) 2014 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef QTXDG_MACROS_H
#define QTXDG_MACROS_H
#ifdef __cplusplus
# include <QtCore/qglobal.h>
# ifndef QTXDG_DEPRECATED
# define QTXDG_DEPRECATED Q_DECL_DEPRECATED
# endif
#endif
#ifdef QTXDG_COMPILATION
#define QTXDG_API Q_DECL_EXPORT
#else
#define QTXDG_API Q_DECL_IMPORT
#endif
#if defined(QTXDG_COMPILATION) && defined(QTXDG_TESTS)
# define QTXDG_AUTOTEST Q_DECL_EXPORT /* Build library,tests enabled */
#elif defined(QTXDG_BUILDING_TESTS) /* Build the tests */
# define QTXDG_AUTOTEST Q_DECL_IMPORT
#else
# define QTXDG_AUTOTEST /* Building library, tests disabled */
#endif
#endif // QTXDG_MACROS_H

@ -1,729 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include "xdgmenu_p.h"
#include "xdgmenureader.h"
#include "xmlhelper.h"
#include "xdgmenurules.h"
#include "xdgmenuapplinkprocessor.h"
#include "xdgdirs.h"
#include "xdgmenulayoutprocessor.h"
#include <QDebug>
#include <QtXml/QDomElement>
#include <QtXml/QDomNamedNodeMap>
#include <QFile>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QSettings>
#include <QDir>
#include <QHash>
#include <QLocale>
#include <QTranslator>
#include <QCoreApplication>
#include <QCryptographicHash>
// Helper functions prototypes
void installTranslation(const QString &name);
bool isParent(const QDomElement& parent, const QDomElement& child);
XdgMenu::XdgMenu(QObject *parent) :
QObject(parent),
d_ptr(new XdgMenuPrivate(this))
{
}
XdgMenu::~XdgMenu()
{
Q_D(XdgMenu);
delete d;
}
XdgMenuPrivate::XdgMenuPrivate(XdgMenu *parent):
mOutDated(true),
q_ptr(parent)
{
mRebuildDelayTimer.setSingleShot(true);
mRebuildDelayTimer.setInterval(REBUILD_DELAY);
connect(&mRebuildDelayTimer, SIGNAL(timeout()), this, SLOT(rebuild()));
connect(&mWatcher, SIGNAL(fileChanged(QString)), &mRebuildDelayTimer, SLOT(start()));
connect(&mWatcher, SIGNAL(directoryChanged(QString)), &mRebuildDelayTimer, SLOT(start()));
connect(this, SIGNAL(changed()), q_ptr, SIGNAL(changed()));
}
const QString XdgMenu::logDir() const
{
Q_D(const XdgMenu);
return d->mLogDir;
}
void XdgMenu::setLogDir(const QString& directory)
{
Q_D(XdgMenu);
d->mLogDir = directory;
}
const QDomDocument XdgMenu::xml() const
{
Q_D(const XdgMenu);
return d->mXml;
}
QString XdgMenu::menuFileName() const
{
Q_D(const XdgMenu);
return d->mMenuFileName;
}
QStringList XdgMenu::environments()
{
Q_D(XdgMenu);
return d->mEnvironments;
}
void XdgMenu::setEnvironments(const QStringList &envs)
{
Q_D(XdgMenu);
d->mEnvironments = envs;
}
void XdgMenu::setEnvironments(const QString &env)
{
setEnvironments(QStringList() << env);
}
const QString XdgMenu::errorString() const
{
Q_D(const XdgMenu);
return d->mErrorString;
}
bool XdgMenu::read(const QString& menuFileName)
{
Q_D(XdgMenu);
d->mMenuFileName = menuFileName;
d->clearWatcher();
XdgMenuReader reader(this);
if (!reader.load(d->mMenuFileName))
{
qWarning() << reader.errorString();
d->mErrorString = reader.errorString();
return false;
}
d->mXml = reader.xml();
QDomElement root = d->mXml.documentElement();
d->saveLog(QLatin1String("00-reader.xml"));
d->simplify(root);
d->saveLog(QLatin1String("01-simplify.xml"));
d->mergeMenus(root);
d->saveLog(QLatin1String("02-mergeMenus.xml"));
d->moveMenus(root);
d->saveLog(QLatin1String("03-moveMenus.xml"));
d->mergeMenus(root);
d->saveLog(QLatin1String("04-mergeMenus.xml"));
d->deleteDeletedMenus(root);
d->saveLog(QLatin1String("05-deleteDeletedMenus.xml"));
d->processDirectoryEntries(root, QStringList());
d->saveLog(QLatin1String("06-processDirectoryEntries.xml"));
d->processApps(root);
d->saveLog(QLatin1String("07-processApps.xml"));
d->processLayouts(root);
d->saveLog(QLatin1String("08-processLayouts.xml"));
d->deleteEmpty(root);
d->saveLog(QLatin1String("09-deleteEmpty.xml"));
d->fixSeparators(root);
d->saveLog(QLatin1String("10-fixSeparators.xml"));
d->mOutDated = false;
d->mHash = QCryptographicHash::hash(d->mXml.toByteArray(), QCryptographicHash::Md5);
return true;
}
void XdgMenu::save(const QString& fileName)
{
Q_D(const XdgMenu);
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
{
qWarning() << QString::fromLatin1("Cannot write file %1:\n%2.")
.arg(fileName, file.errorString());
return;
}
QTextStream ts(&file);
d->mXml.save(ts, 2);
file.close();
}
/************************************************
For debug only
************************************************/
void XdgMenuPrivate::load(const QString& fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
qWarning() << QString::fromLatin1("%1 not loading: %2").arg(fileName, file.errorString());
return;
}
mXml.setContent(&file, true);
}
void XdgMenuPrivate::saveLog(const QString& logFileName)
{
Q_Q(XdgMenu);
if (!mLogDir.isEmpty())
q->save(mLogDir + QLatin1Char('/') + logFileName);
}
void XdgMenuPrivate::mergeMenus(QDomElement& element)
{
QHash<QString, QDomElement> menus;
MutableDomElementIterator it(element, QLatin1String("Menu"));
it.toFront();
while(it.hasNext())
{
it.next();
menus[it.current().attribute(QLatin1String("name"))] = it.current();
}
it.toBack();
while (it.hasPrevious())
{
QDomElement src = it.previous();
QDomElement dest = menus[src.attribute(QLatin1String("name"))];
if (dest != src)
{
prependChilds(src, dest);
element.removeChild(src);
}
}
QDomElement n = element.firstChildElement(QLatin1String("Menu"));
while (!n.isNull())
{
mergeMenus(n);
n = n.nextSiblingElement(QLatin1String("Menu"));
}
it.toFront();
while(it.hasNext())
mergeMenus(it.next());
}
void XdgMenuPrivate::simplify(QDomElement& element)
{
MutableDomElementIterator it(element);
//it.toFront();
while(it.hasNext())
{
QDomElement n = it.next();
if (n.tagName() == QLatin1String("Name"))
{
// The <Name> field must not contain the slash character ("/");
// implementations should discard any name containing a slash.
element.setAttribute(QLatin1String("name"), n.text().remove(QLatin1Char('/')));
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == QLatin1String("Deleted"))
{
element.setAttribute(QLatin1String("deleted"), true);
n.parentNode().removeChild(n);
}
else if(n.tagName() == QLatin1String("NotDeleted"))
{
element.setAttribute(QLatin1String("deleted"), false);
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == QLatin1String("OnlyUnallocated"))
{
element.setAttribute(QLatin1String("onlyUnallocated"), true);
n.parentNode().removeChild(n);
}
else if(n.tagName() == QLatin1String(QLatin1String("NotOnlyUnallocated")))
{
element.setAttribute(QLatin1String("onlyUnallocated"), false);
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == QLatin1String("FileInfo"))
{
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == QLatin1String("Menu"))
{
simplify(n);
}
}
}
void XdgMenuPrivate::prependChilds(QDomElement& srcElement, QDomElement& destElement)
{
MutableDomElementIterator it(srcElement);
it.toBack();
while(it.hasPrevious())
{
QDomElement n = it.previous();
destElement.insertBefore(n, destElement.firstChild());
}
if (srcElement.attributes().contains(QLatin1String("deleted")) &&
!destElement.attributes().contains(QLatin1String("deleted"))
)
destElement.setAttribute(QLatin1String("deleted"), srcElement.attribute(QLatin1String("deleted")));
if (srcElement.attributes().contains(QLatin1String("onlyUnallocated")) &&
!destElement.attributes().contains(QLatin1String("onlyUnallocated"))
)
destElement.setAttribute(QLatin1String("onlyUnallocated"), srcElement.attribute(QLatin1String("onlyUnallocated")));
}
void XdgMenuPrivate::appendChilds(QDomElement& srcElement, QDomElement& destElement)
{
MutableDomElementIterator it(srcElement);
while(it.hasNext())
destElement.appendChild(it.next());
if (srcElement.attributes().contains(QLatin1String("deleted")))
destElement.setAttribute(QLatin1String("deleted"), srcElement.attribute(QLatin1String("deleted")));
if (srcElement.attributes().contains(QLatin1String("onlyUnallocated")))
destElement.setAttribute(QLatin1String("onlyUnallocated"), srcElement.attribute(QLatin1String("onlyUnallocated")));
}
/************************************************
Search item by path. The path can be absolute or relative. If the element not
found, the behavior depends on a parameter "createNonExisting." If it's true, then
the missing items will be created, otherwise the function returns 0.
************************************************/
QDomElement XdgMenu::findMenu(QDomElement& baseElement, const QString& path, bool createNonExisting)
{
Q_D(XdgMenu);
// Absolute path ..................
if (path.startsWith(QLatin1Char('/')))
{
QDomElement root = d->mXml.documentElement();
return findMenu(root, path.section(QLatin1Char('/'), 2), createNonExisting);
}
// Relative path ..................
if (path.isEmpty())
return baseElement;
QString name = path.section(QLatin1Char('/'), 0, 0);
MutableDomElementIterator it(baseElement);
while(it.hasNext())
{
QDomElement n = it.next();
if (n.attribute(QLatin1String("name")) == name)
return findMenu(n, path.section(QLatin1Char('/'), 1), createNonExisting);
}
// Not found ......................
if (!createNonExisting)
return QDomElement();
const QStringList names = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
QDomElement el = baseElement;
for (const QString &name : names)
{
QDomElement p = el;
el = d->mXml.createElement(QLatin1String("Menu"));
p.appendChild(el);
el.setAttribute(QLatin1String("name"), name);
}
return el;
}
bool isParent(const QDomElement& parent, const QDomElement& child)
{
QDomNode n = child;
while (!n.isNull())
{
if (n == parent)
return true;
n = n.parentNode();
}
return false;
}
/************************************************
Recurse to resolve <Move> elements for each menu starting with any child menu before
handling the more top level menus. So the deepest menus have their <Move> operations
performed first. Within each <Menu>, execute <Move> operations in the order that
they appear.
If the destination path does not exist, simply relocate the origin <Menu> element,
and change its <Name> field to match the destination path.
If the origin path does not exist, do nothing.
If both paths exist, take the origin <Menu> element, delete its <Name> element, and
prepend its remaining child elements to the destination <Menu> element.
************************************************/
void XdgMenuPrivate::moveMenus(QDomElement& element)
{
Q_Q(XdgMenu);
{
MutableDomElementIterator i(element, QLatin1String("Menu"));
while(i.hasNext())
moveMenus(i.next());
}
MutableDomElementIterator i(element, QLatin1String("Move"));
while(i.hasNext())
{
i.next();
QString oldPath = i.current().lastChildElement(QLatin1String("Old")).text();
QString newPath = i.current().lastChildElement(QLatin1String("New")).text();
element.removeChild(i.current());
if (oldPath.isEmpty() || newPath.isEmpty())
continue;
QDomElement oldMenu = q->findMenu(element, oldPath, false);
if (oldMenu.isNull())
continue;
QDomElement newMenu = q->findMenu(element, newPath, true);
if (isParent(oldMenu, newMenu))
continue;
appendChilds(oldMenu, newMenu);
oldMenu.parentNode().removeChild(oldMenu);
}
}
/************************************************
For each <Menu> containing a <Deleted> element which is not followed by a
<NotDeleted> element, remove that menu and all its child menus.
Kmenuedit create .hidden menu entry, delete it too.
************************************************/
void XdgMenuPrivate::deleteDeletedMenus(QDomElement& element)
{
MutableDomElementIterator i(element, QLatin1String("Menu"));
while(i.hasNext())
{
QDomElement e = i.next();
if (e.attribute(QLatin1String("deleted")) == QLatin1String("1") ||
e.attribute(QLatin1String("name")) == QLatin1String(".hidden")
)
element.removeChild(e);
else
deleteDeletedMenus(e);
}
}
void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QStringList& parentDirs)
{
QStringList dirs;
QStringList files;
element.setAttribute(QLatin1String("title"), element.attribute(QLatin1String("name")));
MutableDomElementIterator i(element, QString());
i.toBack();
while(i.hasPrevious())
{
QDomElement e = i.previous();
if (e.tagName() == QLatin1String("Directory"))
{
files << e.text();
element.removeChild(e);
}
else if (e.tagName() == QLatin1String("DirectoryDir"))
{
dirs << e.text();
element.removeChild(e);
}
}
dirs << parentDirs;
bool found = false;
for (const QString &file : const_cast<const QStringList&>(files)){
if (file.startsWith(QLatin1Char('/')))
found = loadDirectoryFile(file, element);
else
{
for (const QString &dir : const_cast<const QStringList&>(dirs))
{
found = loadDirectoryFile(dir + QLatin1Char('/') + file, element);
if (found) break;
}
}
if (found) break;
}
MutableDomElementIterator it(element, QLatin1String("Menu"));
while(it.hasNext())
{
QDomElement e = it.next();
processDirectoryEntries(e, dirs);
}
}
bool XdgMenuPrivate::loadDirectoryFile(const QString& fileName, QDomElement& element)
{
XdgDesktopFile file;
file.load(fileName);
if (!file.isValid())
return false;
element.setAttribute(QLatin1String("title"), file.localizedValue(QLatin1String("Name")).toString());
element.setAttribute(QLatin1String("comment"), file.localizedValue(QLatin1String("Comment")).toString());
element.setAttribute(QLatin1String("icon"), file.value(QLatin1String("Icon")).toString());
Q_Q(XdgMenu);
q->addWatchPath(QFileInfo(file.fileName()).absolutePath());
return true;
}
void XdgMenuPrivate::processApps(QDomElement& element)
{
Q_Q(XdgMenu);
XdgMenuApplinkProcessor processor(element, q);
processor.run();
}
void XdgMenuPrivate::deleteEmpty(QDomElement& element)
{
MutableDomElementIterator it(element, QLatin1String("Menu"));
while(it.hasNext())
deleteEmpty(it.next());
if (element.attribute(QLatin1String("keep")) == QLatin1String("true"))
return;
QDomElement childMenu = element.firstChildElement(QLatin1String("Menu"));
QDomElement childApps = element.firstChildElement(QLatin1String("AppLink"));
if (childMenu.isNull() && childApps.isNull())
{
element.parentNode().removeChild(element);
}
}
void XdgMenuPrivate::processLayouts(QDomElement& element)
{
XdgMenuLayoutProcessor proc(element);
proc.run();
}
void XdgMenuPrivate::fixSeparators(QDomElement& element)
{
MutableDomElementIterator it(element, QLatin1String("Separator"));
while(it.hasNext())
{
QDomElement s = it.next();
if (s.previousSiblingElement().tagName() == QLatin1String("Separator"))
element.removeChild(s);
}
QDomElement first = element.firstChild().toElement();
if (first.tagName() == QLatin1String("Separator"))
element.removeChild(first);
QDomElement last = element.lastChild().toElement();
if (last.tagName() == QLatin1String("Separator"))
element.removeChild(last);
MutableDomElementIterator mi(element, QLatin1String("Menu"));
while(mi.hasNext())
fixSeparators(mi.next());
}
/************************************************
$XDG_CONFIG_DIRS/menus/${XDG_MENU_PREFIX}applications.menu
The first file found in the search path should be used; other files are ignored.
************************************************/
QString XdgMenu::getMenuFileName(const QString& baseName)
{
const QStringList configDirs = XdgDirs::configDirs();
QString menuPrefix = QString::fromLocal8Bit(qgetenv("XDG_MENU_PREFIX"));
for (const QString &configDir : configDirs)
{
QFileInfo file(QString::fromLatin1("%1/menus/%2%3").arg(configDir, menuPrefix, baseName));
if (file.exists())
return file.filePath();
}
QStringList wellKnownFiles;
// razor- is a priority for us
wellKnownFiles << QLatin1String("razor-applications.menu");
// the "global" menu file name on suse and fedora
wellKnownFiles << QLatin1String("applications.menu");
// rest files ordered by priority (descending)
wellKnownFiles << QLatin1String("kde4-applications.menu");
wellKnownFiles << QLatin1String("kde-applications.menu");
wellKnownFiles << QLatin1String("gnome-applications.menu");
wellKnownFiles << QLatin1String("lxde-applications.menu");
for (const QString &configDir : configDirs)
{
for (const QString &f : const_cast<const QStringList&>(wellKnownFiles))
{
QFileInfo file(QString::fromLatin1("%1/menus/%2").arg(configDir, f));
if (file.exists())
return file.filePath();
}
}
return QString();
}
void XdgMenu::addWatchPath(const QString &path)
{
Q_D(XdgMenu);
if (d->mWatcher.files().contains(path))
return;
if (d->mWatcher.directories().contains(path))
return;
d->mWatcher.addPath(path);
}
bool XdgMenu::isOutDated() const
{
Q_D(const XdgMenu);
return d->mOutDated;
}
void XdgMenuPrivate::rebuild()
{
Q_Q(XdgMenu);
QByteArray prevHash = mHash;
q->read(mMenuFileName);
if (prevHash != mHash)
{
mOutDated = true;
Q_EMIT changed();
}
}
void XdgMenuPrivate::clearWatcher()
{
QStringList sl;
sl << mWatcher.files();
sl << mWatcher.directories();
if (sl.length())
mWatcher.removePaths(sl);
}

@ -1,127 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENU_H
#define QTXDG_XDGMENU_H
#include "xdgmacros.h"
#include <QObject>
#include <QString>
#include <QStringList>
#include <QtXml/QDomDocument>
class QDomDocument;
class QDomElement;
class XdgMenuPrivate;
/*! @brief The XdgMenu class implements the "Desktop Menu Specification" from freedesktop.org.
Freedesktop menu is a user-visible hierarchy of applications, typically displayed as a menu.
Example usage:
@code
QString menuFile = XdgMenu::getMenuFileName();
XdgMenu xdgMenu();
bool res = xdgMenu.read(menuFile);
if (!res)
{
QMessageBox::warning(this, "Parse error", xdgMenu.errorString());
}
QDomElement rootElement = xdgMenu.xml().documentElement()
@endcode
@sa http://specifications.freedesktop.org/menu-spec/menu-spec-latest.html
*/
class QTXDG_API XdgMenu : public QObject
{
Q_OBJECT
friend class XdgMenuReader;
friend class XdgMenuApplinkProcessor;
public:
explicit XdgMenu(QObject *parent = 0);
virtual ~XdgMenu();
bool read(const QString& menuFileName);
void save(const QString& fileName);
const QDomDocument xml() const;
QString menuFileName() const;
QDomElement findMenu(QDomElement& baseElement, const QString& path, bool createNonExisting);
/*! Returns a list of strings identifying the environments that should
* display a desktop entry. Internally all comparisions involving the
* desktop enviroment names are made case insensitive.
*/
QStringList environments();
/*!
* Set currently running environments. Example: RAZOR, KDE, or GNOME...
* Internally all comparisions involving the desktop enviroment names
* are made case insensitive.
*/
void setEnvironments(const QStringList &envs);
void setEnvironments(const QString &env);
/*!
* Returns a string description of the last error that occurred if read() returns false.
*/
const QString errorString() const;
/*!
* @brief The name of the directory for the debug XML-files.
*/
const QString logDir() const;
/*!
* @brief The name of the directory for the debug XML-files. If a directory is specified,
* then after you run the XdgMenu::read, you can see and check the results of the each step.
*/
void setLogDir(const QString& directory);
static QString getMenuFileName(const QString& baseName = QLatin1String("applications.menu"));
bool isOutDated() const;
Q_SIGNALS:
void changed();
protected:
void addWatchPath(const QString& path);
private:
XdgMenuPrivate* const d_ptr;
Q_DECLARE_PRIVATE(XdgMenu)
};
#endif // QTXDG_XDGMENU_H

@ -1,86 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include <QObject>
#include <QFileSystemWatcher>
#include <QTimer>
#define REBUILD_DELAY 3000
class QDomElement;
class QStringList;
class QString;
class QDomDocument;
class XdgMenuPrivate: QObject
{
Q_OBJECT
public:
XdgMenuPrivate(XdgMenu* parent);
void simplify(QDomElement& element);
void mergeMenus(QDomElement& element);
void moveMenus(QDomElement& element);
void deleteDeletedMenus(QDomElement& element);
void processDirectoryEntries(QDomElement& element, const QStringList& parentDirs);
void processApps(QDomElement& element);
void deleteEmpty(QDomElement& element);
void processLayouts(QDomElement& element);
void fixSeparators(QDomElement& element);
bool loadDirectoryFile(const QString& fileName, QDomElement& element);
void prependChilds(QDomElement& srcElement, QDomElement& destElement);
void appendChilds(QDomElement& srcElement, QDomElement& destElement);
void saveLog(const QString& logFileName);
void load(const QString& fileName);
void clearWatcher();
QString mErrorString;
QStringList mEnvironments;
QString mMenuFileName;
QString mLogDir;
QDomDocument mXml;
QByteArray mHash;
QTimer mRebuildDelayTimer;
QFileSystemWatcher mWatcher;
bool mOutDated;
public Q_SLOTS:
void rebuild();
Q_SIGNALS:
void changed();
private:
XdgMenu* const q_ptr;
Q_DECLARE_PUBLIC(XdgMenu)
};

@ -1,253 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include "xdgmenuapplinkprocessor.h"
#include "xmlhelper.h"
#include "xdgdesktopfile.h"
#include <QDir>
XdgMenuApplinkProcessor::XdgMenuApplinkProcessor(QDomElement& element, XdgMenu* menu, XdgMenuApplinkProcessor *parent) :
QObject(parent)
{
mElement = element;
mParent = parent;
mMenu = menu;
mOnlyUnallocated = element.attribute(QLatin1String("onlyUnallocated")) == QLatin1String("1");
MutableDomElementIterator i(element, QLatin1String("Menu"));
while(i.hasNext())
{
QDomElement e = i.next();
mChilds.append(new XdgMenuApplinkProcessor(e, mMenu, this));
}
}
XdgMenuApplinkProcessor::~XdgMenuApplinkProcessor()
{
}
void XdgMenuApplinkProcessor::run()
{
step1();
step2();
}
void XdgMenuApplinkProcessor::step1()
{
fillAppFileInfoList();
createRules();
// Check Include rules & mark as allocated ............
XdgMenuAppFileInfoHashIterator i(mAppFileInfoHash);
while(i.hasNext())
{
i.next();
XdgDesktopFile* file = i.value()->desktopFile();
if (mRules.checkInclude(i.key(), *file))
{
if (!mOnlyUnallocated)
i.value()->setAllocated(true);
if (!mRules.checkExclude(i.key(), *file))
{
mSelected.append(i.value());
}
}
}
// Process childs menus ...............................
for (XdgMenuApplinkProcessor* child : const_cast<const QLinkedList<XdgMenuApplinkProcessor*>&>(mChilds))
child->step1();
}
void XdgMenuApplinkProcessor::step2()
{
// Create AppLinks elements ...........................
QDomDocument doc = mElement.ownerDocument();
for (XdgMenuAppFileInfo* fileInfo : const_cast<const QLinkedList<XdgMenuAppFileInfo*>&>(mSelected))
{
if (mOnlyUnallocated && fileInfo->allocated())
continue;
XdgDesktopFile* file = fileInfo->desktopFile();
bool show = false;
QStringList envs = mMenu->environments();
const int N = envs.size();
for (int i = 0; i < N; ++i)
{
if (file->isShown(envs.at(i)))
{
show = true;
break;
}
}
if (!show)
continue;
QDomElement appLink = doc.createElement(QLatin1String("AppLink"));
appLink.setAttribute(QLatin1String("id"), fileInfo->id());
appLink.setAttribute(QLatin1String("title"), file->localizedValue(QLatin1String("Name")).toString());
appLink.setAttribute(QLatin1String("comment"), file->localizedValue(QLatin1String("Comment")).toString());
appLink.setAttribute(QLatin1String("genericName"), file->localizedValue(QLatin1String("GenericName")).toString());
appLink.setAttribute(QLatin1String("exec"), file->value(QLatin1String("Exec")).toString());
appLink.setAttribute(QLatin1String("terminal"), file->value(QLatin1String("Terminal")).toBool());
appLink.setAttribute(QLatin1String("startupNoify"), file->value(QLatin1String("StartupNotify")).toBool());
appLink.setAttribute(QLatin1String("path"), file->value(QLatin1String("Path")).toString());
appLink.setAttribute(QLatin1String("icon"), file->value(QLatin1String("Icon")).toString());
appLink.setAttribute(QLatin1String("desktopFile"), file->fileName());
mElement.appendChild(appLink);
}
// Process childs menus ...............................
for (XdgMenuApplinkProcessor* child : const_cast<const QLinkedList<XdgMenuApplinkProcessor*>&>(mChilds))
child->step2();
}
/************************************************
For each <Menu> element, build a pool of desktop entries by collecting entries found
in each <AppDir> for the menu element. If two entries have the same desktop-file id,
the entry for the earlier (closer to the top of the file) <AppDir> must be discarded.
Next, add to the pool the entries for any <AppDir>s specified by ancestor <Menu>
elements. If a parent menu has a duplicate entry (same desktop-file id), the entry
for the child menu has priority.
************************************************/
void XdgMenuApplinkProcessor::fillAppFileInfoList()
{
// Build a pool by collecting entries found in <AppDir>
{
MutableDomElementIterator i(mElement, QLatin1String("AppDir"));
i.toBack();
while(i.hasPrevious())
{
QDomElement e = i.previous();
findDesktopFiles(e.text(), QString());
mElement.removeChild(e);
}
}
// Add the entries for ancestor <Menu> ................
if (mParent)
{
XdgMenuAppFileInfoHashIterator i(mParent->mAppFileInfoHash);
while(i.hasNext())
{
i.next();
//if (!mAppFileInfoHash.contains(i.key()))
mAppFileInfoHash.insert(i.key(), i.value());
}
}
}
void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QString& prefix)
{
QDir dir(dirName);
mMenu->addWatchPath(dir.absolutePath());
const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files);
for (const QFileInfo &file : files)
{
XdgDesktopFile* f = XdgDesktopFileCache::getFile(file.canonicalFilePath());
if (f)
mAppFileInfoHash.insert(prefix + file.fileName(), new XdgMenuAppFileInfo(f, prefix + file.fileName(), this));
}
// Working recursively ............
const QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &d : dirs)
{
QString dn = d.canonicalFilePath();
if (dn != dirName)
{
findDesktopFiles(dn, QString::fromLatin1("%1%2-").arg(prefix, d.fileName()));
}
}
}
void XdgMenuApplinkProcessor::createRules()
{
MutableDomElementIterator i(mElement, QString());
while(i.hasNext())
{
QDomElement e = i.next();
if (e.tagName()== QLatin1String("Include"))
{
mRules.addInclude(e);
mElement.removeChild(e);
}
else if (e.tagName()== QLatin1String("Exclude"))
{
mRules.addExclude(e);
mElement.removeChild(e);
}
}
}
/************************************************
Check if the program is actually installed.
************************************************/
bool XdgMenuApplinkProcessor::checkTryExec(const QString& progName)
{
if (progName.startsWith(QDir::separator()))
return QFileInfo(progName).isExecutable();
const QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':'));
for (const QString &dir : dirs)
{
if (QFileInfo(QDir(dir), progName).isExecutable())
return true;
}
return false;
}

@ -1,101 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENUAPPLINKPROCESSOR_H
#define QTXDG_XDGMENUAPPLINKPROCESSOR_H
#include "xdgmenurules.h"
#include <QObject>
#include <QtXml/QDomElement>
#include <QLinkedList>
#include <QString>
#include <QHash>
class XdgMenu;
class XdgMenuAppFileInfo;
class XdgDesktopFile;
typedef QLinkedList<XdgMenuAppFileInfo*> XdgMenuAppFileInfoList;
typedef QHash<QString, XdgMenuAppFileInfo*> XdgMenuAppFileInfoHash;
typedef QHashIterator<QString, XdgMenuAppFileInfo*> XdgMenuAppFileInfoHashIterator;
class XdgMenuApplinkProcessor : public QObject
{
Q_OBJECT
public:
explicit XdgMenuApplinkProcessor(QDomElement& element, XdgMenu* menu, XdgMenuApplinkProcessor *parent = 0);
virtual ~XdgMenuApplinkProcessor();
void run();
protected:
void step1();
void step2();
void fillAppFileInfoList();
void findDesktopFiles(const QString& dirName, const QString& prefix);
//bool loadDirectoryFile(const QString& fileName, QDomElement& element);
void createRules();
bool checkTryExec(const QString& progName);
private:
XdgMenuApplinkProcessor* mParent;
QLinkedList<XdgMenuApplinkProcessor*> mChilds;
XdgMenuAppFileInfoHash mAppFileInfoHash;
XdgMenuAppFileInfoList mSelected;
QDomElement mElement;
bool mOnlyUnallocated;
XdgMenu* mMenu;
XdgMenuRules mRules;
};
class XdgMenuAppFileInfo: public QObject
{
Q_OBJECT
public:
explicit XdgMenuAppFileInfo(XdgDesktopFile* desktopFile, const QString& id, QObject *parent)
: QObject(parent)
{
mDesktopFile = desktopFile;
mAllocated = false;
mId = id;
}
XdgDesktopFile* desktopFile() const { return mDesktopFile; }
bool allocated() const { return mAllocated; }
void setAllocated(bool value) { mAllocated = value; }
QString id() const { return mId; }
private:
XdgDesktopFile* mDesktopFile;
bool mAllocated;
QString mId;
};
#endif // QTXDG_XDGMENUAPPLINKPROCESSOR_H

@ -1,411 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenulayoutprocessor.h"
#include "xmlhelper.h"
#include <QDebug>
#include <QMap>
// Helper functions prototypes
QDomElement findLastElementByTag(const QDomElement element, const QString tagName);
int childsCount(const QDomElement& element);
QDomElement findLastElementByTag(const QDomElement element, const QString tagName)
{
QDomNodeList l = element.elementsByTagName(tagName);
if (l.isEmpty())
return QDomElement();
return l.at(l.length()-1).toElement();
}
/************************************************
If no default-layout has been specified then the layout as specified by
the following elements should be assumed:
<DefaultLayout
show_empty="false"
inline="false"
inline_limit="4"
inline_header="true"
inline_alias="false">
<Merge type="menus"/>
<Merge type="files"/>
</DefaultLayout>
************************************************/
XdgMenuLayoutProcessor::XdgMenuLayoutProcessor(QDomElement& element):
mElement(element)
{
mDefaultParams.mShowEmpty = false;
mDefaultParams.mInline = false;
mDefaultParams.mInlineLimit = 4;
mDefaultParams.mInlineHeader = true;
mDefaultParams.mInlineAlias = false;
mDefaultLayout = findLastElementByTag(element, QLatin1String("DefaultLayout"));
if (mDefaultLayout.isNull())
{
// Create DefaultLayout node
QDomDocument doc = element.ownerDocument();
mDefaultLayout = doc.createElement(QLatin1String("DefaultLayout"));
QDomElement menus = doc.createElement(QLatin1String("Merge"));
menus.setAttribute(QLatin1String("type"), QLatin1String("menus"));
mDefaultLayout.appendChild(menus);
QDomElement files = doc.createElement(QLatin1String("Merge"));
files.setAttribute(QLatin1String("type"), QLatin1String("files"));
mDefaultLayout.appendChild(files);
mElement.appendChild(mDefaultLayout);
}
setParams(mDefaultLayout, &mDefaultParams);
// If a menu does not contain a <Layout> element or if it contains an empty <Layout> element
// then the default layout should be used.
mLayout = findLastElementByTag(element, QLatin1String("Layout"));
if (mLayout.isNull() || !mLayout.hasChildNodes())
mLayout = mDefaultLayout;
}
XdgMenuLayoutProcessor::XdgMenuLayoutProcessor(QDomElement& element, XdgMenuLayoutProcessor *parent):
mElement(element)
{
mDefaultParams = parent->mDefaultParams;
// DefaultLayout ............................
QDomElement defaultLayout = findLastElementByTag(element, QLatin1String("DefaultLayout"));
if (defaultLayout.isNull())
mDefaultLayout = parent->mDefaultLayout;
else
mDefaultLayout = defaultLayout;
setParams(mDefaultLayout, &mDefaultParams);
// If a menu does not contain a <Layout> element or if it contains an empty <Layout> element
// then the default layout should be used.
mLayout = findLastElementByTag(element, QLatin1String("Layout"));
if (mLayout.isNull() || !mLayout.hasChildNodes())
mLayout = mDefaultLayout;
}
void XdgMenuLayoutProcessor::setParams(QDomElement defaultLayout, LayoutParams *result)
{
if (defaultLayout.hasAttribute(QLatin1String("show_empty")))
result->mShowEmpty = defaultLayout.attribute(QLatin1String("show_empty")) == QLatin1String("true");
if (defaultLayout.hasAttribute(QLatin1String("inline")))
result->mInline = defaultLayout.attribute(QLatin1String("inline")) == QLatin1String("true");
if (defaultLayout.hasAttribute(QLatin1String("inline_limit")))
result->mInlineLimit = defaultLayout.attribute(QLatin1String("inline_limit")).toInt();
if (defaultLayout.hasAttribute(QLatin1String("inline_header")))
result->mInlineHeader = defaultLayout.attribute(QLatin1String("inline_header")) == QLatin1String("true");
if (defaultLayout.hasAttribute(QLatin1String("inline_alias")))
result->mInlineAlias = defaultLayout.attribute(QLatin1String("inline_alias")) == QLatin1String("true");
}
QDomElement XdgMenuLayoutProcessor::searchElement(const QString &tagName, const QString &attributeName, const QString &attributeValue) const
{
DomElementIterator it(mElement, tagName);
while (it.hasNext())
{
QDomElement e = it.next();
if (e.attribute(attributeName) == attributeValue)
{
return e;
}
}
return QDomElement();
}
int childsCount(const QDomElement& element)
{
int count = 0;
DomElementIterator it(element);
while (it.hasNext())
{
QString tag = it.next().tagName();
if (tag == QLatin1String("AppLink") || tag == QLatin1String("Menu") || tag == QLatin1String("Separator"))
count ++;
}
return count;
}
void XdgMenuLayoutProcessor::run()
{
QDomDocument doc = mLayout.ownerDocument();
mResult = doc.createElement(QLatin1String("Result"));
mElement.appendChild(mResult);
// Process childs menus ...............................
{
DomElementIterator it(mElement, QLatin1String("Menu"));
while (it.hasNext())
{
QDomElement e = it.next();
XdgMenuLayoutProcessor p(e, this);
p.run();
}
}
// Step 1 ...................................
DomElementIterator it(mLayout);
it.toFront();
while (it.hasNext())
{
QDomElement e = it.next();
if (e.tagName() == QLatin1String("Filename"))
processFilenameTag(e);
else if (e.tagName() == QLatin1String("Menuname"))
processMenunameTag(e);
else if (e.tagName() == QLatin1String("Separator"))
processSeparatorTag(e);
else if (e.tagName() == QLatin1String("Merge"))
{
QDomElement merge = mResult.ownerDocument().createElement(QLatin1String("Merge"));
merge.setAttribute(QLatin1String("type"), e.attribute(QLatin1String("type")));
mResult.appendChild(merge);
}
}
// Step 2 ...................................
{
MutableDomElementIterator ri(mResult, QLatin1String("Merge"));
while (ri.hasNext())
{
processMergeTag(ri.next());
}
}
// Move result cilds to element .............
MutableDomElementIterator ri(mResult);
while (ri.hasNext())
{
mElement.appendChild(ri.next());
}
// Final ....................................
mElement.removeChild(mResult);
if (mLayout.parentNode() == mElement)
mElement.removeChild(mLayout);
if (mDefaultLayout.parentNode() == mElement)
mElement.removeChild(mDefaultLayout);
}
/************************************************
The <Filename> element is the most basic matching rule.
It matches a desktop entry if the desktop entry has the given desktop-file id
************************************************/
void XdgMenuLayoutProcessor::processFilenameTag(const QDomElement &element)
{
QString id = element.text();
QDomElement appLink = searchElement(QLatin1String("AppLink"), QLatin1String("id"), id);
if (!appLink.isNull())
mResult.appendChild(appLink);
}
/************************************************
Its contents references an immediate sub-menu of the current menu, as such it should never contain
a slash. If no such sub-menu exists the element should be ignored.
This element may have various attributes, the default values are taken from the DefaultLayout key.
show_empty [ bool ]
defines whether a menu that contains no desktop entries and no sub-menus
should be shown at all.
inline [ bool ]
If the inline attribute is "true" the menu that is referenced may be copied into the current
menu at the current point instead of being inserted as sub-menu of the current menu.
inline_limit [ int ]
defines the maximum number of entries that can be inlined. If the sub-menu has more entries
than inline_limit, the sub-menu will not be inlined. If the inline_limit is 0 (zero) there
is no limit.
inline_header [ bool ]
defines whether an inlined menu should be preceded with a header entry listing the caption of
the sub-menu.
inline_alias [ bool ]
defines whether a single inlined entry should adopt the caption of the inlined menu. In such
case no additional header entry will be added regardless of the value of the inline_header
attribute.
Example: if a menu has a sub-menu titled "WordProcessor" with a single entry "OpenOffice 4.2", and
both inline="true" and inline_alias="true" are specified then this would result in the
"OpenOffice 4.2" entry being inlined in the current menu but the "OpenOffice 4.2" caption of the
entry would be replaced with "WordProcessor".
************************************************/
void XdgMenuLayoutProcessor::processMenunameTag(const QDomElement &element)
{
QString id = element.text();
QDomElement menu = searchElement(QLatin1String("Menu"), QLatin1String("name"), id);
if (menu.isNull())
return;
LayoutParams params = mDefaultParams;
setParams(element, &params);
int count = childsCount(menu);
if (count == 0)
{
if (params.mShowEmpty)
{
menu.setAttribute(QLatin1String("keep"), QLatin1String("true"));
mResult.appendChild(menu);
}
return;
}
bool doInline = params.mInline &&
(!params.mInlineLimit || params.mInlineLimit > count);
bool doAlias = params.mInlineAlias &&
doInline && (count == 1);
bool doHeader = params.mInlineHeader &&
doInline && !doAlias;
if (!doInline)
{
mResult.appendChild(menu);
return;
}
// Header ....................................
if (doHeader)
{
QDomElement header = mLayout.ownerDocument().createElement(QLatin1String("Header"));
QDomNamedNodeMap attrs = menu.attributes();
for (int i=0; i < attrs.count(); ++i)
{
header.setAttributeNode(attrs.item(i).toAttr());
}
mResult.appendChild(header);
}
// Alias .....................................
if (doAlias)
{
menu.firstChild().toElement().setAttribute(QLatin1String("title"), menu.attribute(QLatin1String("title")));
}
// Inline ....................................
MutableDomElementIterator it(menu);
while (it.hasNext())
{
mResult.appendChild(it.next());
}
}
/************************************************
It indicates a suggestion to draw a visual separator at this point in the menu.
<Separator> elements at the start of a menu, at the end of a menu or that directly
follow other <Separator> elements may be ignored.
************************************************/
void XdgMenuLayoutProcessor::processSeparatorTag(const QDomElement &element)
{
QDomElement separator = element.ownerDocument().createElement(QLatin1String("Separator"));
mResult.appendChild(separator);
}
/************************************************
It indicates the point where desktop entries and sub-menus that are not explicitly mentioned
within the <Layout> or <DefaultLayout> element are to be inserted.
It has a type attribute that indicates which elements should be inserted:
type="menus"
means that all sub-menus that are not explicitly mentioned should be inserted in alphabetical
order of their visual caption at this point.
type="files" means that all desktop entries contained in this menu that are not explicitly
mentioned should be inserted in alphabetical order of their visual caption at this point.
type="all" means that a mix of all sub-menus and all desktop entries that are not explicitly
mentioned should be inserted in alphabetical order of their visual caption at this point.
************************************************/
void XdgMenuLayoutProcessor::processMergeTag(const QDomElement &element)
{
QString type = element.attribute(QLatin1String("type"));
QMap<QString, QDomElement> map;
MutableDomElementIterator it(mElement);
while (it.hasNext())
{
QDomElement e = it.next();
if (
((type == QLatin1String("menus") || type == QLatin1String("all")) && e.tagName() == QLatin1String("Menu" )) ||
((type == QLatin1String("files") || type == QLatin1String("all")) && e.tagName() == QLatin1String("AppLink"))
)
map.insert(e.attribute(QLatin1String("title")), e);
}
QMapIterator<QString, QDomElement> mi(map);
while (mi.hasNext()) {
mi.next();
mResult.insertBefore(mi.value(), element);
}
mResult.removeChild(element);
}

@ -1,114 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENULAYOUTPROCESSOR_H
#define QTXDG_XDGMENULAYOUTPROCESSOR_H
#include <QtXml/QDomElement>
#include <QList>
struct LayoutItem
{
enum Type{
Filename,
Menuname,
Separator,
MergeMenus,
MergeFiles,
MergeAll,
};
Type type;
bool showEmpty;
bool isInline;
bool inlineLimit;
bool inlineHeader;
bool inlineAlias;
QString fileId;
};
//class Layout: public QList<LayoutItem>
//{
//public:
/* Layout() {}
bool showEmpty() { return mShowEmpty; }
void setShowEmpty(bool value) { mShowEmpty = value; }
bool isInline() { return mInline; }
void setInline(bool value) { mInline = value; }
int inlineLimit() { return mInlineLimit; }
void setInlineLimit(int value) { mInlineLimit = value; }
bool inlineHeader() {return mInlineHeader; }
void setInlineHeader(bool value) { mInlineHeader = value; }
bool inlineAlias() { return mInlineAlias; }
void setInlineAlias(bool value) { mInlineAlias = value; }
private:
*/
struct LayoutParams
{
bool mShowEmpty;
bool mInline;
int mInlineLimit;
bool mInlineHeader;
bool mInlineAlias;
};
class XdgMenuLayoutProcessor
{
public:
XdgMenuLayoutProcessor(QDomElement& element);
void run();
protected:
XdgMenuLayoutProcessor(QDomElement& element, XdgMenuLayoutProcessor *parent);
private:
void setParams(QDomElement defaultLayout, LayoutParams *result);
QDomElement searchElement(const QString &tagName, const QString &attributeName, const QString &attributeValue) const;
void processFilenameTag(const QDomElement &element);
void processMenunameTag(const QDomElement &element);
void processSeparatorTag(const QDomElement &element);
void processMergeTag(const QDomElement &element);
LayoutParams mDefaultParams;
QDomElement& mElement;
QDomElement mDefaultLayout;
QDomElement mLayout;
QDomElement mResult;
};
#endif // QTXDG_XDGMENULAYOUTPROCESSOR_H

@ -1,436 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenureader.h"
#include "xdgmenu.h"
#include "xdgdirs.h"
#include "xmlhelper.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QString>
#include <QtXml/QDomNamedNodeMap>
#include <QtXml/QDomNode>
XdgMenuReader::XdgMenuReader(XdgMenu* menu, XdgMenuReader* parentReader, QObject *parent) :
QObject(parent),
mMenu(menu)
{
mParentReader = parentReader;
if (mParentReader)
mBranchFiles << mParentReader->mBranchFiles;
}
XdgMenuReader::~XdgMenuReader()
{
}
bool XdgMenuReader::load(const QString& fileName, const QString& baseDir)
{
if (fileName.isEmpty())
{
mErrorStr = QLatin1String("Menu file not defined.");
return false;
}
QFileInfo fileInfo(QDir(baseDir), fileName);
mFileName = fileInfo.canonicalFilePath();
mDirName = fileInfo.canonicalPath();
if (mBranchFiles.contains(mFileName))
return false; // Recursive loop detected
mBranchFiles << mFileName;
QFile file(mFileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
mErrorStr = QString::fromLatin1("%1 not loading: %2").arg(fileName, file.errorString());
return false;
}
//qDebug() << "Load file:" << mFileName;
mMenu->addWatchPath(mFileName);
QString errorStr;
int errorLine;
int errorColumn;
if (!mXml.setContent(&file, true, &errorStr, &errorLine, &errorColumn))
{
mErrorStr = QString::fromLatin1("Parse error at line %1, column %2:\n%3")
.arg(errorLine)
.arg(errorColumn)
.arg(errorStr);
return false;
}
QDomElement root = mXml.documentElement();
QDomElement debugElement = mXml.createElement(QLatin1String("FileInfo"));
debugElement.setAttribute(QLatin1String("file"), mFileName);
if (mParentReader)
debugElement.setAttribute(QLatin1String("parent"), mParentReader->fileName());
QDomNode null;
root.insertBefore(debugElement, null);
processMergeTags(root);
return true;
}
/************************************************
Duplicate <MergeXXX> elements (that specify the same file) are handled as with
duplicate <AppDir> elements (the last duplicate is used).
************************************************/
void XdgMenuReader::processMergeTags(QDomElement& element)
{
QDomElement n = element.lastChildElement();
QStringList mergedFiles;
while (!n.isNull())
{
QDomElement next = n.previousSiblingElement();
// MergeFile ..................
if (n.tagName() == QLatin1String("MergeFile"))
{
processMergeFileTag(n, &mergedFiles);
n.parentNode().removeChild(n);
}
// MergeDir ...................
else if(n.tagName() == QLatin1String("MergeDir"))
{
processMergeDirTag(n, &mergedFiles);
n.parentNode().removeChild(n);
}
// DefaultMergeDirs ...........
else if (n.tagName() == QLatin1String("DefaultMergeDirs"))
{
processDefaultMergeDirsTag(n, &mergedFiles);
n.parentNode().removeChild(n);
}
// AppDir ...................
else if(n.tagName() == QLatin1String("AppDir"))
{
processAppDirTag(n);
n.parentNode().removeChild(n);
}
// DefaultAppDirs .............
else if(n.tagName() == QLatin1String("DefaultAppDirs"))
{
processDefaultAppDirsTag(n);
n.parentNode().removeChild(n);
}
// DirectoryDir ...................
else if(n.tagName() == QLatin1String("DirectoryDir"))
{
processDirectoryDirTag(n);
n.parentNode().removeChild(n);
}
// DefaultDirectoryDirs ...........
else if(n.tagName() == QLatin1String("DefaultDirectoryDirs"))
{
processDefaultDirectoryDirsTag(n);
n.parentNode().removeChild(n);
}
// Menu .......................
else if(n.tagName() == QLatin1String("Menu"))
{
processMergeTags(n);
}
n = next;
}
}
/************************************************
Any number of <MergeFile> elements may be listed below a <Menu> element, giving
the name of another menu file to be merged into this one.
If fileName is not an absolute path then the file to be merged should be located
relative to the location of this menu.
If the type attribute is missing or set to "path" then the contents of the
<MergeFile> element indicates the file to be merged.
If the type attribute is set to "parent" and the file that contains this
<MergeFile> element is located under one of the paths specified by
$XDG_CONFIG_DIRS, the contents of the element should be ignored and the remaining
paths specified by $XDG_CONFIG_DIRS are searched for a file with the same relative
filename. The first file encountered should be merged. There should be no merging
at all if no matching file is found. ( Libmenu additional scans ~/.config/menus.)
************************************************/
void XdgMenuReader::processMergeFileTag(QDomElement& element, QStringList* mergedFiles)
{
//qDebug() << "Process " << element;// << "in" << mFileName;
if (element.attribute(QLatin1String("type")) != QLatin1String("parent"))
{
mergeFile(element.text(), element, mergedFiles);
}
else
{
QString relativeName;
QStringList configDirs = XdgDirs::configDirs();
for (const QString &configDir : const_cast<const QStringList&>(configDirs))
{
if (mFileName.startsWith(configDir))
{
relativeName = mFileName.mid(configDir.length());
configDirs.removeAll(configDir);
break;
}
}
if (relativeName.isEmpty())
{
QString configHome = XdgDirs::configHome();
if (mFileName.startsWith(configHome))
relativeName = mFileName.mid(configHome.length());
}
if (relativeName.isEmpty())
return;
for (const QString &configDir : configDirs)
{
if (QFileInfo::exists(configDir + relativeName))
{
mergeFile(configDir + relativeName, element, mergedFiles);
return;
}
}
}
}
/************************************************
A <MergeDir> contains the name of a directory. Each file in the given directory
which ends in the ".menu" extension should be merged in the same way that a
<MergeFile> would be. If the filename given as a <MergeDir> is not an absolute
path, it should be located relative to the location of the menu file being parsed.
The files inside the merged directory are not merged in any specified order.
Duplicate <MergeDir> elements (that specify the same directory) are handled as with
duplicate <AppDir> elements (the last duplicate is used).
KDE additional scans ~/.config/menus.
************************************************/
void XdgMenuReader::processMergeDirTag(QDomElement& element, QStringList* mergedFiles)
{
//qDebug() << "Process " << element;// << "in" << mFileName;
mergeDir(element.text(), element, mergedFiles);
element.parentNode().removeChild(element);
}
/************************************************
The element has no content. The element should be treated as if it were a list of
<MergeDir> elements containing the default merge directory locations. When expanding
<DefaultMergeDirs> to a list of <MergeDir>, the default locations that are earlier
in the search path go later in the <Menu> so that they have priority.
Note that a system that uses either gnome-applications.menu or kde-applications.menu
depending on the desktop environment in use must still use applications-merged as the
default merge directory in both cases.
Implementations may chose to use .menu files with names other than application.menu
for tasks or menus other than the main application menu. In that case the first part
of the name of the default merge directory is derived from the name of the .menu file.
************************************************/
void XdgMenuReader::processDefaultMergeDirsTag(QDomElement& element, QStringList* mergedFiles)
{
//qDebug() << "Process " << element;// << "in" << mFileName;
QString menuBaseName = QFileInfo(mMenu->menuFileName()).baseName();
int n = menuBaseName.lastIndexOf(QLatin1Char('-'));
if (n>-1)
menuBaseName = menuBaseName.mid(n+1);
QStringList dirs = XdgDirs::configDirs();
dirs << XdgDirs::configHome();
for (const QString &dir : const_cast<const QStringList&>(dirs))
{
mergeDir(QString::fromLatin1("%1/menus/%2-merged").arg(dir, menuBaseName), element, mergedFiles);
}
if (menuBaseName == QLatin1String("applications"))
mergeFile(QString::fromLatin1("%1/menus/applications-kmenuedit.menu").arg(XdgDirs::configHome()), element, mergedFiles);
}
/************************************************
If the filename given as an <AppDir> is not an absolute path, it should be located
relative to the location of the menu file being parsed.
************************************************/
void XdgMenuReader::processAppDirTag(QDomElement& element)
{
//qDebug() << "Process " << element;
addDirTag(element, QLatin1String("AppDir"), element.text());
}
/************************************************
The element has no content. The element should be treated as if it were a list of
<AppDir> elements containing the default app dir locations
($XDG_DATA_DIRS/applications/).
menu-cache additional prepends $XDG_DATA_HOME/applications.
************************************************/
void XdgMenuReader::processDefaultAppDirsTag(QDomElement& element)
{
//qDebug() << "Process " << element;
QStringList dirs = XdgDirs::dataDirs();
dirs.prepend(XdgDirs::dataHome(false));
for (const QString &dir : const_cast<const QStringList&> (dirs))
{
//qDebug() << "Add AppDir: " << dir + "/applications/";
addDirTag(element, QLatin1String("AppDir"), dir + QLatin1String("/applications/"));
}
}
/************************************************
If the filename given as a <DirectoryDir> is not an absolute path, it should be
located relative to the location of the menu file being parsed.
************************************************/
void XdgMenuReader::processDirectoryDirTag(QDomElement& element)
{
//qDebug() << "Process " << element;
addDirTag(element, QLatin1String("DirectoryDir"), element.text());
}
/************************************************
The element has no content. The element should be treated as if it were a list of
<DirectoryDir> elements containing the default desktop dir locations
($XDG_DATA_DIRS/desktop-directories/).
menu-cache additional prepends $XDG_DATA_HOME/applications.
************************************************/
void XdgMenuReader::processDefaultDirectoryDirsTag(QDomElement& element)
{
//qDebug() << "Process " << element;
QStringList dirs = XdgDirs::dataDirs();
dirs.prepend(XdgDirs::dataHome(false));
for (const QString &dir : const_cast<const QStringList&>(dirs))
addDirTag(element, QLatin1String("DirectoryDir"), dir + QLatin1String("/desktop-directories/"));
}
/************************************************
************************************************/
void XdgMenuReader::addDirTag(QDomElement& previousElement, const QString& tagName, const QString& dir)
{
QFileInfo dirInfo(mDirName, dir);
if (dirInfo.isDir())
{
// qDebug() << "\tAdding " + dirInfo.canonicalFilePath();
QDomElement element = mXml.createElement(tagName);
element.appendChild(mXml.createTextNode(dirInfo.canonicalFilePath()));
previousElement.parentNode().insertBefore(element, previousElement);
}
}
/*
If fileName is not an absolute path then the file to be merged should be located
relative to the location of this menu file.
************************************************/
void XdgMenuReader::mergeFile(const QString& fileName, QDomElement& element, QStringList* mergedFiles)
{
XdgMenuReader reader(mMenu, this);
QFileInfo fileInfo(QDir(mDirName), fileName);
if (!fileInfo.exists())
return;
if (mergedFiles->contains(fileInfo.canonicalFilePath()))
{
//qDebug() << "\tSkip: allredy merged";
return;
}
//qDebug() << "Merge file: " << fileName;
mergedFiles->append(fileInfo.canonicalFilePath());
if (reader.load(fileName, mDirName))
{
//qDebug() << "\tOK";
QDomElement n = reader.xml().firstChildElement().firstChildElement();
while (!n.isNull())
{
// As a special exception, remove the <Name> element from the root
// element of each file being merged.
if (n.tagName() != QLatin1String("Name"))
{
QDomNode imp = mXml.importNode(n, true);
element.parentNode().insertBefore(imp, element);
}
n = n.nextSiblingElement();
}
}
}
void XdgMenuReader::mergeDir(const QString& dirName, QDomElement& element, QStringList* mergedFiles)
{
QFileInfo dirInfo(mDirName, dirName);
if (dirInfo.isDir())
{
//qDebug() << "Merge dir: " << dirInfo.canonicalFilePath();
QDir dir = QDir(dirInfo.canonicalFilePath());
const QFileInfoList files = dir.entryInfoList(QStringList() << QLatin1String("*.menu"), QDir::Files | QDir::Readable);
for (const QFileInfo &file : files)
mergeFile(file.canonicalFilePath(), element, mergedFiles);
}
}

@ -1,80 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENUREADER_H
#define QTXDG_XDGMENUREADER_H
#include <QObject>
#include <QString>
#include <QStringList>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
class XdgMenu;
class XdgMenuReader : public QObject
{
Q_OBJECT
public:
explicit XdgMenuReader(XdgMenu* menu, XdgMenuReader* parentReader = 0, QObject *parent = 0);
virtual ~XdgMenuReader();
bool load(const QString& fileName, const QString& baseDir = QString());
QString fileName() const { return mFileName; }
QString errorString() const { return mErrorStr; }
QDomDocument& xml() { return mXml; }
Q_SIGNALS:
public Q_SLOTS:
protected:
void processMergeTags(QDomElement& element);
void processMergeFileTag(QDomElement& element, QStringList* mergedFiles);
void processMergeDirTag(QDomElement& element, QStringList* mergedFiles);
void processDefaultMergeDirsTag(QDomElement& element, QStringList* mergedFiles);
void processAppDirTag(QDomElement& element);
void processDefaultAppDirsTag(QDomElement& element);
void processDirectoryDirTag(QDomElement& element);
void processDefaultDirectoryDirsTag(QDomElement& element);
void addDirTag(QDomElement& previousElement, const QString& tagName, const QString& dir);
void mergeFile(const QString& fileName, QDomElement& element, QStringList* mergedFiles);
void mergeDir(const QString& dirName, QDomElement& element, QStringList* mergedFiles);
private:
QString mFileName;
QString mDirName;
QString mErrorStr;
QDomDocument mXml;
XdgMenuReader* mParentReader;
QStringList mBranchFiles;
XdgMenu* mMenu;
};
#endif // QTXDG_XDGMENUREADER_H

@ -1,234 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenurules.h"
#include "xmlhelper.h"
#include <QDebug>
#include <QStringList>
/**
* See: http://standards.freedesktop.org/desktop-entry-spec
*/
XdgMenuRule::XdgMenuRule(const QDomElement& element, QObject* parent) :
QObject(parent)
{
Q_UNUSED(element)
}
XdgMenuRule::~XdgMenuRule()
{
}
/************************************************
The <Or> element contains a list of matching rules. If any of the matching rules
inside the <Or> element match a desktop entry, then the entire <Or> rule matches
the desktop entry.
************************************************/
XdgMenuRuleOr::XdgMenuRuleOr(const QDomElement& element, QObject* parent) :
XdgMenuRule(element, parent)
{
//qDebug() << "Create OR rule";
DomElementIterator iter(element, QString());
while(iter.hasNext())
{
QDomElement e = iter.next();
if (e.tagName() == QLatin1String("Or"))
mChilds.append(new XdgMenuRuleOr(e, this));
else if (e.tagName() == QLatin1String("And"))
mChilds.append(new XdgMenuRuleAnd(e, this));
else if (e.tagName() == QLatin1String("Not"))
mChilds.append(new XdgMenuRuleNot(e, this));
else if (e.tagName() == QLatin1String("Filename"))
mChilds.append(new XdgMenuRuleFileName(e, this));
else if (e.tagName() == QLatin1String("Category"))
mChilds.append(new XdgMenuRuleCategory(e, this));
else if (e.tagName() == QLatin1String("All"))
mChilds.append(new XdgMenuRuleAll(e, this));
else
qWarning() << QString::fromLatin1("Unknown rule") << e.tagName();
}
}
bool XdgMenuRuleOr::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
for (QLinkedList<XdgMenuRule*>::Iterator i=mChilds.begin(); i!=mChilds.end(); ++i)
if ((*i)->check(desktopFileId, desktopFile)) return true;
return false;
}
/************************************************
The <And> element contains a list of matching rules. If each of the matching rules
inside the <And> element match a desktop entry, then the entire <And> rule matches
the desktop entry.
************************************************/
XdgMenuRuleAnd::XdgMenuRuleAnd(const QDomElement& element, QObject *parent) :
XdgMenuRuleOr(element, parent)
{
// qDebug() << "Create AND rule";
}
bool XdgMenuRuleAnd::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
for (QLinkedList<XdgMenuRule*>::Iterator i=mChilds.begin(); i!=mChilds.end(); ++i)
if (!(*i)->check(desktopFileId, desktopFile)) return false;
return mChilds.count();
}
/************************************************
The <Not> element contains a list of matching rules. If any of the matching rules
inside the <Not> element matches a desktop entry, then the entire <Not> rule does
not match the desktop entry. That is, matching rules below <Not> have a logical OR
relationship.
************************************************/
XdgMenuRuleNot::XdgMenuRuleNot(const QDomElement& element, QObject *parent) :
XdgMenuRuleOr(element, parent)
{
// qDebug() << "Create NOT rule";
}
bool XdgMenuRuleNot::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
return ! XdgMenuRuleOr::check(desktopFileId, desktopFile);
}
/************************************************
The <Filename> element is the most basic matching rule. It matches a desktop entry
if the desktop entry has the given desktop-file id. See Desktop-File Id.
************************************************/
XdgMenuRuleFileName::XdgMenuRuleFileName(const QDomElement& element, QObject *parent) :
XdgMenuRule(element, parent)
{
//qDebug() << "Create FILENAME rule";
mId = element.text();
}
bool XdgMenuRuleFileName::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
Q_UNUSED(desktopFile)
//qDebug() << "XdgMenuRuleFileName:" << desktopFileId << mId;
return desktopFileId == mId;
}
/************************************************
The <Category> element is another basic matching predicate. It matches a desktop entry
if the desktop entry has the given category in its Categories field.
************************************************/
XdgMenuRuleCategory::XdgMenuRuleCategory(const QDomElement& element, QObject *parent) :
XdgMenuRule(element, parent)
{
mCategory = element.text();
}
bool XdgMenuRuleCategory::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
Q_UNUSED(desktopFileId)
QStringList cats = desktopFile.categories();
return cats.contains(mCategory);
}
/************************************************
The <All> element is a matching rule that matches all desktop entries.
************************************************/
XdgMenuRuleAll::XdgMenuRuleAll(const QDomElement& element, QObject *parent) :
XdgMenuRule(element, parent)
{
}
bool XdgMenuRuleAll::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
Q_UNUSED(desktopFileId)
Q_UNUSED(desktopFile)
return true;
}
XdgMenuRules::XdgMenuRules(QObject* parent) :
QObject(parent)
{
}
XdgMenuRules::~XdgMenuRules()
{
}
void XdgMenuRules::addInclude(const QDomElement& element)
{
mIncludeRules.append(new XdgMenuRuleOr(element, this));
}
void XdgMenuRules::addExclude(const QDomElement& element)
{
mExcludeRules.append(new XdgMenuRuleOr(element, this));
}
bool XdgMenuRules::checkInclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
for (QLinkedList<XdgMenuRule*>::Iterator i=mIncludeRules.begin(); i!=mIncludeRules.end(); ++i)
if ((*i)->check(desktopFileId, desktopFile)) return true;
return false;
}
bool XdgMenuRules::checkExclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
for (QLinkedList<XdgMenuRule*>::Iterator i=mExcludeRules.begin(); i!=mExcludeRules.end(); ++i)
if ((*i)->check(desktopFileId, desktopFile)) return true;
return false;
}

@ -1,134 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENURULES_H
#define QTXDG_XDGMENURULES_H
#include <QObject>
#include <QtXml/QDomElement>
#include <QLinkedList>
#include "xdgdesktopfile.h"
/**
* See: http://standards.freedesktop.org/desktop-entry-spec
*/
class XdgMenuRule : public QObject
{
Q_OBJECT
public:
explicit XdgMenuRule(const QDomElement& element, QObject* parent = 0);
virtual ~XdgMenuRule();
virtual bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile) = 0;
};
class XdgMenuRuleOr : public XdgMenuRule
{
Q_OBJECT
public:
explicit XdgMenuRuleOr(const QDomElement& element, QObject* parent = 0);
bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
protected:
QLinkedList<XdgMenuRule*> mChilds;
};
class XdgMenuRuleAnd : public XdgMenuRuleOr
{
Q_OBJECT
public:
explicit XdgMenuRuleAnd(const QDomElement& element, QObject* parent = 0);
bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
};
class XdgMenuRuleNot : public XdgMenuRuleOr
{
Q_OBJECT
public:
explicit XdgMenuRuleNot(const QDomElement& element, QObject* parent = 0);
bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
};
class XdgMenuRuleFileName : public XdgMenuRule
{
Q_OBJECT
public:
explicit XdgMenuRuleFileName(const QDomElement& element, QObject* parent = 0);
bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
private:
QString mId;
};
class XdgMenuRuleCategory : public XdgMenuRule
{
Q_OBJECT
public:
explicit XdgMenuRuleCategory(const QDomElement& element, QObject* parent = 0);
bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
private:
QString mCategory;
};
class XdgMenuRuleAll : public XdgMenuRule
{
Q_OBJECT
public:
explicit XdgMenuRuleAll(const QDomElement& element, QObject* parent = 0);
bool check(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
};
class XdgMenuRules : public QObject
{
Q_OBJECT
public:
explicit XdgMenuRules(QObject* parent = 0);
virtual ~XdgMenuRules();
void addInclude(const QDomElement& element);
void addExclude(const QDomElement& element);
bool checkInclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
bool checkExclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile);
protected:
QLinkedList<XdgMenuRule*> mIncludeRules;
QLinkedList<XdgMenuRule*> mExcludeRules;
};
#endif // QTXDG_XDGMENURULES_H

@ -1,241 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenuwidget.h"
#include "xdgicon.h"
#include "xmlhelper.h"
#include "xdgaction.h"
#include "xdgmenu.h"
#include <QEvent>
#include <QDebug>
#include <QUrl>
#include <QMimeData>
#include <QtGui/QDrag>
#include <QtGui/QMouseEvent>
#include <QApplication>
class XdgMenuWidgetPrivate
{
private:
XdgMenuWidget* const q_ptr;
Q_DECLARE_PUBLIC(XdgMenuWidget)
public:
explicit XdgMenuWidgetPrivate(XdgMenuWidget* parent):
q_ptr(parent)
{}
void init(const QDomElement& xml);
void buildMenu();
QDomElement mXml;
void mouseMoveEvent(QMouseEvent *event);
QPoint mDragStartPosition;
private:
XdgAction* createAction(const QDomElement& xml);
static QString escape(QString string);
};
XdgMenuWidget::XdgMenuWidget(const XdgMenu& xdgMenu, const QString& title, QWidget* parent):
QMenu(parent),
d_ptr(new XdgMenuWidgetPrivate(this))
{
d_ptr->init(xdgMenu.xml().documentElement());
setTitle(XdgMenuWidgetPrivate::escape(title));
}
XdgMenuWidget::XdgMenuWidget(const QDomElement& menuElement, QWidget* parent):
QMenu(parent),
d_ptr(new XdgMenuWidgetPrivate(this))
{
d_ptr->init(menuElement);
}
XdgMenuWidget::XdgMenuWidget(const XdgMenuWidget& other, QWidget* parent):
QMenu(parent),
d_ptr(new XdgMenuWidgetPrivate(this))
{
d_ptr->init(other.d_ptr->mXml);
}
void XdgMenuWidgetPrivate::init(const QDomElement& xml)
{
Q_Q(XdgMenuWidget);
mXml = xml;
q->clear();
QString title;
if (! xml.attribute(QLatin1String("title")).isEmpty())
title = xml.attribute(QLatin1String("title"));
else
title = xml.attribute(QLatin1String("name"));
q->setTitle(escape(title));
q->setToolTip(xml.attribute(QLatin1String("comment")));
QIcon parentIcon;
QMenu* parentMenu = qobject_cast<QMenu*>(q->parent());
if (parentMenu)
parentIcon = parentMenu->icon();
q->setIcon(XdgIcon::fromTheme(mXml.attribute(QLatin1String("icon")), parentIcon));
buildMenu();
}
XdgMenuWidget::~XdgMenuWidget()
{
delete d_ptr;
}
XdgMenuWidget& XdgMenuWidget::operator=(const XdgMenuWidget& other)
{
Q_D(XdgMenuWidget);
d->init(other.d_ptr->mXml);
return *this;
}
bool XdgMenuWidget::event(QEvent* event)
{
Q_D(XdgMenuWidget);
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *e = static_cast<QMouseEvent*>(event);
if (e->button() == Qt::LeftButton)
d->mDragStartPosition = e->pos();
}
else if (event->type() == QEvent::MouseMove)
{
QMouseEvent *e = static_cast<QMouseEvent*>(event);
d->mouseMoveEvent(e);
}
return QMenu::event(event);
}
void XdgMenuWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
if ((event->pos() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance())
return;
Q_Q(XdgMenuWidget);
XdgAction *a = qobject_cast<XdgAction*>(q->actionAt(event->pos()));
if (!a)
return;
QList<QUrl> urls;
urls << QUrl(a->desktopFile().fileName());
QMimeData *mimeData = new QMimeData();
mimeData->setUrls(urls);
QDrag *drag = new QDrag(q);
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction | Qt::LinkAction);
}
void XdgMenuWidgetPrivate::buildMenu()
{
Q_Q(XdgMenuWidget);
QAction* first = 0;
if (!q->actions().isEmpty())
first = q->actions().constLast();
DomElementIterator it(mXml, QString());
while(it.hasNext())
{
QDomElement xml = it.next();
// Build submenu ........................
if (xml.tagName() == QLatin1String("Menu"))
q->insertMenu(first, new XdgMenuWidget(xml, q));
//Build application link ................
else if (xml.tagName() == QLatin1String("AppLink"))
q->insertAction(first, createAction(xml));
//Build separator .......................
else if (xml.tagName() == QLatin1String("Separator"))
q->insertSeparator(first);
}
}
XdgAction* XdgMenuWidgetPrivate::createAction(const QDomElement& xml)
{
Q_Q(XdgMenuWidget);
XdgAction* action = new XdgAction(xml.attribute(QLatin1String("desktopFile")), q);
QString title;
if (!xml.attribute(QLatin1String("title")).isEmpty())
title = xml.attribute(QLatin1String("title"));
else
title = xml.attribute(QLatin1String("name"));
if (!xml.attribute(QLatin1String("genericName")).isEmpty() &&
xml.attribute(QLatin1String("genericName")) != title)
title += QString::fromLatin1(" (%1)").arg(xml.attribute(QLatin1String("genericName")));
action->setText(escape(title));
return action;
}
/************************************************
This should be used when a menu item text is set
otherwise Qt uses the &'s for creating mnemonics
************************************************/
QString XdgMenuWidgetPrivate::escape(QString string)
{
return string.replace(QLatin1Char('&'), QLatin1String("&&"));
}

@ -1,88 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENUWIDGET_H
#define QTXDG_XDGMENUWIDGET_H
#include "xdgmacros.h"
#include <QMenu>
#include <QtXml/QDomElement>
class XdgMenu;
class QEvent;
class XdgMenuWidgetPrivate;
/*!
@brief The XdgMenuWidget class provides an QMenu widget for application menu or its part.
Example usage:
@code
QString menuFile = XdgMenu::getMenuFileName();
XdgMenu xdgMenu(menuFile);
bool res = xdgMenu.read();
if (res)
{
XdgMenuWidget menu(xdgMenu, QString(), this);
menu.exec(QCursor::pos());
}
else
{
QMessageBox::warning(this, "Parse error", xdgMenu.errorString());
}
@endcode
*/
class QTXDG_API XdgMenuWidget : public QMenu
{
Q_OBJECT
public:
/// Constructs a menu for root documentElement in xdgMenu with some text and parent.
XdgMenuWidget(const XdgMenu& xdgMenu, const QString& title = QString(), QWidget* parent=0);
/// Constructs a menu for menuElement with parent.
explicit XdgMenuWidget(const QDomElement& menuElement, QWidget* parent=0);
/// Constructs a copy of other.
XdgMenuWidget(const XdgMenuWidget& other, QWidget* parent=0);
/// Assigns other to this menu.
XdgMenuWidget& operator=(const XdgMenuWidget& other);
/// Destroys the menu.
virtual ~XdgMenuWidget();
protected:
bool event(QEvent* event);
private:
XdgMenuWidgetPrivate* const d_ptr;
Q_DECLARE_PRIVATE(XdgMenuWidget)
};
#endif // QTXDG_XDGMENUWIDGET_H

@ -1,114 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs
* Copyright (C) 2014 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "xdgmimetype.h"
#include "xdgicon.h"
class XdgMimeTypePrivate : public QSharedData {
public:
XdgMimeTypePrivate();
XdgMimeTypePrivate(const XdgMimeType& other);
void computeIconName();
QString iconName;
bool computed;
};
XdgMimeTypePrivate::XdgMimeTypePrivate()
: computed(false)
{
}
XdgMimeTypePrivate::XdgMimeTypePrivate(const XdgMimeType& other)
: iconName(other.dx->iconName),
computed(other.dx->computed)
{
}
XdgMimeType::XdgMimeType()
: QMimeType(),
dx(new XdgMimeTypePrivate())
{
}
XdgMimeType::XdgMimeType(const QMimeType& mime)
: QMimeType(mime),
dx(new XdgMimeTypePrivate())
{
}
XdgMimeType::XdgMimeType(const XdgMimeType& mime)
: QMimeType(mime),
dx(mime.dx)
{
}
XdgMimeType &XdgMimeType::operator=(const XdgMimeType &other)
{
QMimeType::operator =(other);
if (dx != other.dx)
dx = other.dx;
return *this;
}
XdgMimeType::~XdgMimeType()
{
}
QString XdgMimeType::iconName() const
{
if (dx->computed) {
return dx->iconName;
} else {
dx->iconName.clear();
QStringList names;
names.append(QMimeType::iconName());
names.append(QMimeType::genericIconName());
for (const QString &s : const_cast<const QStringList&>(names)) {
if (!XdgIcon::fromTheme(s).isNull()) {
dx->iconName = s;
break;
}
}
dx->computed = true;
return dx->iconName;
}
}
QIcon XdgMimeType::icon() const
{
return XdgIcon::fromTheme((iconName()));
}

@ -1,126 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs
* Copyright (C) 2014 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef QTXDG_MIMETYPE_H
#define QTXDG_MIMETYPE_H
#include "xdgmacros.h"
#include <QMimeType>
#include <QIcon>
#include <QString>
#include <QSharedData>
#include <QDebug>
class XdgMimeTypePrivate;
//! Describes types of file or data, represented by a MIME type string.
/*! This class is an QMimeType descendent. The differences are the icon() and
* iconName() methods. @see icon() @see iconName()
*
* Some parts of the documentation are based on QMimeType documentation.
* @see http://qt-project.org/doc/qt-5/qmimetype.html
*
* @author Luís Pereira (luis.artur.pereira@gmail.com)
*/
class QTXDG_API XdgMimeType : public QMimeType {
public:
/*! Constructs an XdgMimeType object initialized with default property
values that indicate an invalid MIME type.
@see QMimeType::QMimeType()
*/
XdgMimeType();
/*! Constructs an XdgMimeType object from an QMimeType object
* @see QMimeType
*/
XdgMimeType(const QMimeType& mime);
//! Constructs an XdgMimeType object from another XdgMimeType object
XdgMimeType(const XdgMimeType& mime);
/*! Assigns the data of other to this XdgMimeType object.
* @return a reference to this object.
*/
XdgMimeType &operator=(const XdgMimeType &other);
/*! Compares the other XdgMimeType object to this XdgMimeType object.
* @return true if other equals this XdgMimeType object, otherwise returns
* false. The name is the unique identifier for a mimetype, so two mimetypes
* with the same name, are equal.
* @see QMimeType::operator==()
*/
bool operator==(const XdgMimeType &other) const
{
return QMimeType::operator==(other);
}
inline bool operator!=(const XdgMimeType &other) const
{
return !QMimeType::operator==(other);
}
void swap(XdgMimeType &other)
{
QMimeType::swap(other);
qSwap(dx, other.dx);
}
//! Destructs the mimetype
~XdgMimeType();
//! Returns the name of the MIME type.
/*! The same as QMimeType::name(). Provided for compatibilty with deprecated
* XdgMimeInfo::mimeType().
* @see QMimeType::name()
*/
inline QString mimeType() const { return QMimeType::name(); }
//! Returns an icon associated with the mimetype.
/*! @return an icon from the current icon theme associated with the
* mimetype. If the icon theme doesn't provide one it returns QIcon().
* It gets the icon name from iconName() and then gives it to
* XdgIcon::fromTheme().
* @see iconName() @see XdgIcon::fromTheme()
*/
QIcon icon() const;
//! Returns an icon name associated with the mimetype.
/*! @return an icon name from the current icon theme associated with the
* mimetype. If the current icon theme doesn't provide one, it returns an
* empty QString.
* The returned icon name is suitable to be given to XdgIcon::fromTheme()
* to load the icon.
* @see XdgIcon::fromTheme()
*/
QString iconName() const;
protected:
friend class XdgMimeTypePrivate;
QExplicitlySharedDataPointer<XdgMimeTypePrivate> dx;
};
Q_DECLARE_SHARED(XdgMimeType)
#endif // QTXDG_MIMETYPE_H

@ -1,46 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xmlhelper.h"
#include <QDebug>
#include <QtXml/QDomElement>
#include <QtXml/QDomNode>
QDebug operator<<(QDebug dbg, const QDomElement &el)
{
QDomNamedNodeMap map = el.attributes();
QString args;
for (int i=0; i<map.count(); ++i)
args += QLatin1Char(' ') + map.item(i).nodeName() + QLatin1Char('=') + map.item(i).nodeValue() + QLatin1Char('\'');
dbg.nospace() << QString::fromLatin1("<%1%2>%3</%1>").arg(el.tagName(), args, el.text());
return dbg.space();
}

@ -1,161 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* Razor - a lightweight, Qt based, desktop toolset
* http://razor-qt.org
*
* Copyright: 2010-2011 Razor team
* Authors:
* Alexander Sokoloff <sokoloff.a@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XMLHELPER_H
#define QTXDG_XMLHELPER_H
#include "xdgmacros.h"
#include <QDebug>
#include <QtXml/QDomElement>
#include <QtXml/QDomNode>
class QTXDG_API DomElementIterator
{
public:
explicit DomElementIterator(const QDomNode& parentNode, const QString& tagName = QString())
{
mTagName = tagName;
mParent = parentNode;
toFront();
}
void toFront()
{
mNext = mParent.firstChildElement(mTagName);
}
bool hasNext()
{
return (!mNext.isNull());
}
const QDomElement& next()
{
mCur = mNext;
mNext = mNext.nextSiblingElement(mTagName);
return mCur;
}
void toBack()
{
mNext = mParent.lastChildElement(mTagName);
}
bool hasPrevious()
{
return (!mNext.isNull());
}
const QDomElement& previous()
{
mCur = mNext;
mNext = mNext.previousSiblingElement(mTagName);
return mCur;
}
const QDomElement& current() const
{
return mCur;
}
private:
QString mTagName;
QDomNode mParent;
QDomElement mCur;
QDomElement mNext;
};
class MutableDomElementIterator
{
public:
explicit MutableDomElementIterator(QDomNode& parentNode, const QString& tagName = QString())
{
mTagName = tagName;
mParent = parentNode;
toFront();
}
void toFront()
{
mNext = mParent.firstChildElement(mTagName);
}
bool hasNext()
{
return (!mNext.isNull());
}
QDomElement& next()
{
mCur = mNext;
mNext = mNext.nextSiblingElement(mTagName);
return mCur;
}
void toBack()
{
mNext = mParent.lastChildElement(mTagName);
}
bool hasPrevious()
{
return (!mNext.isNull());
}
QDomElement& previous()
{
mCur = mNext;
mNext = mNext.previousSiblingElement(mTagName);
return mCur;
}
QDomElement& current()
{
return mCur;
}
private:
QString mTagName;
QDomNode mParent;
QDomElement mCur;
QDomElement mNext;
};
QDebug operator<<(QDebug dbg, const QDomElement &el);
#endif // QTXDG_XMLHELPER_H

@ -1,31 +0,0 @@
remove_definitions(
-DQT_USE_QSTRINGBUILDER
-DQT_NO_CAST_FROM_ASCII
)
add_definitions(
-DQT_NO_KEYWORDS
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
macro(qtxdg_add_test)
foreach(_testname ${ARGN})
add_executable(${_testname} ${_testname}.cpp)
target_link_libraries(${_testname} Qt5::Test ${QTXDGX_LIBRARY_NAME})
target_include_directories(${_testname}
PRIVATE "${PROJECT_SOURCE_DIR}/qtxdg"
)
add_test(NAME ${_testname} COMMAND ${_testname})
endforeach()
endmacro()
set_property(DIRECTORY APPEND
PROPERTY COMPILE_DEFINITIONS "QTXDG_BUILDING_TESTS=\"1\""
)
qtxdg_add_test(
qtxdg_test
tst_xdgdirs
tst_xdgdesktopfile
)

@ -1,173 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2013~2015 LXQt team
* Authors:
* Christian Surlykke <christian@surlykke.dk>
* Jerome Leclanche <jerome@leclan.ch>
* Luís Pereira <luis.artur.pereira@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "qtxdg_test.h"
#include "xdgdesktopfile.h"
#include "xdgdesktopfile_p.h"
#include "xdgdirs.h"
#include <QtTest>
#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QDebug>
#include <QSettings>
void QtXdgTest::testDefaultApp()
{
QStringList mimedirs = XdgDirs::dataDirs();
mimedirs.prepend(XdgDirs::dataHome(false));
for (const QString &mimedir : const_cast<const QStringList&>(mimedirs))
{
QDir dir(mimedir + "/mime");
qDebug() << dir.path();
QStringList filters = (QStringList() << "*.xml");
const QFileInfoList &mediaDirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &mediaDir : mediaDirs)
{
qDebug() << " " << mediaDir.fileName();
const QStringList mimeXmlFileNames = QDir(mediaDir.absoluteFilePath()).entryList(filters, QDir::Files);
for (const QString &mimeXmlFileName : mimeXmlFileNames)
{
QString mimetype = mediaDir.fileName() + "/" + mimeXmlFileName.left(mimeXmlFileName.length() - 4);
QString xdg_utils_default = xdgUtilDefaultApp(mimetype);
QString desktop_file_default = xdgDesktopFileDefaultApp(mimetype);
if (xdg_utils_default != desktop_file_default)
{
qDebug() << mimetype;
qDebug() << "xdg-mime query default:" << xdg_utils_default;
qDebug() << "xdgdesktopfile default:" << desktop_file_default;
}
}
}
}
}
void QtXdgTest::compare(QString mimetype)
{
QString xdgUtilDefault = xdgUtilDefaultApp(mimetype);
QString xdgDesktopDefault = xdgDesktopFileDefaultApp(mimetype);
if (xdgUtilDefault != xdgDesktopDefault)
{
qDebug() << mimetype;
qDebug() << "xdg-mime default:" << xdgUtilDefault;
qDebug() << "xdgDesktopfile default:" << xdgDesktopDefault;
}
}
void QtXdgTest::testTextHtml()
{
compare("text/html");
}
void QtXdgTest::testMeldComparison()
{
compare("application/x-meld-comparison");
}
void QtXdgTest::testCustomFormat()
{
QSettings::Format desktopFormat = QSettings::registerFormat("list", readDesktopFile, writeDesktopFile);
QFile::remove("/tmp/test.list");
QFile::remove("/tmp/test2.list");
QSettings test("/tmp/test.list", desktopFormat);
test.beginGroup("Default Applications");
test.setValue("text/plain", QString("gvim.desktop"));
test.setValue("text/html", QString("firefox.desktop"));
test.endGroup();
test.beginGroup("Other Applications");
test.setValue("application/pdf", QString("qpdfview.desktop"));
test.setValue("image/svg+xml", QString("inkscape.desktop"));
test.sync();
QFile::copy("/tmp/test.list", "/tmp/test2.list");
QSettings test2("/tmp/test2.list", desktopFormat);
QVERIFY(test2.allKeys().size() == 4);
test2.beginGroup("Default Applications");
// qDebug() << test2.value("text/plain");
QVERIFY(test2.value("text/plain") == QString("gvim.desktop"));
// qDebug() << test2.value("text/html");
QVERIFY(test2.value("text/html") == QString("firefox.desktop"));
test2.endGroup();
test2.beginGroup("Other Applications");
// qDebug() << test2.value("application/pdf");
QVERIFY(test2.value("application/pdf") == QString("qpdfview.desktop"));
// qDebug() << test2.value("image/svg+xml");
QVERIFY(test2.value("image/svg+xml") == QString("inkscape.desktop"));
test2.endGroup();
}
QString QtXdgTest::xdgDesktopFileDefaultApp(QString mimetype)
{
XdgDesktopFile *defaultApp = XdgDesktopFileCache::getDefaultApp(mimetype);
QString defaultAppS;
if (defaultApp)
{
defaultAppS = QFileInfo(defaultApp->fileName()).fileName();
}
return defaultAppS;
}
QString QtXdgTest::xdgUtilDefaultApp(QString mimetype)
{
QProcess xdg_mime;
QString program = "xdg-mime";
QStringList args = (QStringList() << "query" << "default" << mimetype);
qDebug() << "running" << program << args.join(" ");
xdg_mime.start(program, args);
xdg_mime.waitForFinished(1000);
return QString(xdg_mime.readAll()).trimmed();
}
#if 0
int main(int argc, char** args)
{
// QtXdgTest().testDefaultApp();
// qDebug() << "Default for text/html:" << QtXdgTest().xdgDesktopFileDefaultApp("text/html");
// QtXdgTest().testMeldComparison();
qDebug() << QtXdgTest().testCustomFormat();
};
#endif // 0
QTEST_MAIN(QtXdgTest)

@ -1,58 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2013~2014 LXQt team
* Authors:
* Christian Surlykke <christian@surlykke.dk>
* Luís Pereira <luis.artur.pereira@gmail.com>
* Jerome Leclanche <jerome@leclan.ch>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_TEST_H
#define QTXDG_TEST_H
#include <QObject>
#include <QString>
#include <QDebug>
class QtXdgTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testCustomFormat();
private:
// Test that XdgDesktopFile and xdg-mime script agree on
// default application for each mime-type.
void testDefaultApp();
void testTextHtml();
void testMeldComparison();
void compare(QString mimetype);
QString xdgDesktopFileDefaultApp(QString mimetype);
QString xdgUtilDefaultApp(QString mimetype);
};
#endif /* QTXDG_TEST_H */

@ -1,118 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs.
* Copyright (C) 2016 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "tst_xdgdesktopfile.h"
#include "XdgDesktopFile"
#include <QtTest>
class Language
{
public:
Language (const QString& lang)
: mPreviousLang(QString::fromLocal8Bit(qgetenv("LC_MESSAGES")))
{
qputenv("LC_MESSAGES", lang.toLocal8Bit());
}
~Language()
{
qputenv("LC_MESSAGES", mPreviousLang.toLocal8Bit());
}
private:
QString mPreviousLang;
};
QTEST_MAIN(tst_xdgdesktopfile)
void tst_xdgdesktopfile::testRead()
{
QTemporaryFile file("testReadXXXXXX.desktop");
QVERIFY(file.open());
const QString fileName = file.fileName();
QTextStream ts(&file);
ts <<
"[Desktop Entry]\n"
"Type=Application\n"
"Name=MyApp\n"
"Icon=foobar\n"
"MimeType=text/plain;image/png;;\n"
"\n";
file.close();
QVERIFY(QFile::exists(fileName));
XdgDesktopFile df;
df.load(fileName);
QVERIFY(df.isValid());
QCOMPARE(df.type(), XdgDesktopFile::ApplicationType);
QCOMPARE(df.name(), QString::fromLatin1("MyApp"));
QCOMPARE(df.iconName(), QString::fromLatin1("foobar"));
QCOMPARE(df.mimeTypes(), QStringList() << QString::fromLatin1("text/plain")
<< QString::fromLatin1("image/png"));
QCOMPARE(df.fileName(), QFileInfo(fileName).canonicalFilePath());
}
void tst_xdgdesktopfile::testReadLocalized_data()
{
QTest::addColumn<QString>("locale");
QTest::addColumn<QString>("translation");
const QString pt = QString::fromUtf8("A Minha Aplicação");
const QString pt_BR = QString::fromUtf8("O Meu Aplicativo");
QTest::newRow("pt") << QStringLiteral("pt") << pt;
QTest::newRow("pt_PT") << QStringLiteral("pt_PT") << pt;
QTest::newRow("pt_BR") << QStringLiteral("pt_BR") << pt_BR;
QTest::newRow("de") << QStringLiteral("de") << QStringLiteral("My Application");
}
void tst_xdgdesktopfile::testReadLocalized()
{
QTemporaryFile file("testReadLocalizedXXXXXX.desktop");
QVERIFY(file.open());
const QString fileName = file.fileName();
QTextStream ts(&file);
ts << QString::fromUtf8(
"[Desktop Entry]\n"
"Type=Application\n"
"Name=My Application\n"
"Name[pt]=A Minha Aplicação\n"
"Name[pt_BR]=O Meu Aplicativo\n"
"Icon=foo\n"
"\n");
file.close();
QVERIFY(QFile::exists(fileName));
XdgDesktopFile df;
df.load(fileName);
QVERIFY(df.isValid());
QFETCH(QString, locale);
QFETCH(QString, translation);
Language lang(locale);
QCOMPARE(df.localizedValue("Name").toString(), translation);
}
#include "test/tst_xdgdesktopfile.moc"

@ -1,35 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs.
* Copyright (C) 2016 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef TST_XDGDESKTOPFILE_H
#define TST_XDGDESKTOPFILE_H
#include <QObject>
class tst_xdgdesktopfile : public QObject {
Q_OBJECT
private Q_SLOTS:
void testRead();
void testReadLocalized();
void testReadLocalized_data();
};
#endif // TST_XDGDESKTOPFILE_H

@ -1,227 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight, Qt based, desktop toolset
* http://lxqt.org
*
* Copyright: 2015 LXQt team
* Authors:
* Luís Pereira <luis.artur.pereira@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include <QObject>
#include "xdgdirs.h"
#include <QtTest>
#include <QTemporaryDir>
class tst_xdgdirs : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void testDataHome();
void testConfigHome();
void testDataDirs();
void testConfigDirs();
void testCacheHome();
void testAutostartHome();
void testAutostartDirs();
private:
void setDefaultLocations();
void setCustomLocations();
QString m_configHome;
QTemporaryDir m_configHomeTemp;
QString m_configDirs;
QTemporaryDir m_configDirsTemp;
QString m_dataHome;
QTemporaryDir m_dataHomeTemp;
QString m_dataDirs;
QTemporaryDir m_dataDirsTemp;
QString m_cacheHome;
QTemporaryDir m_cacheHomeTemp;
};
void tst_xdgdirs::initTestCase()
{
QCoreApplication::instance()->setOrganizationName("QtXdg");
QCoreApplication::instance()->setApplicationName("tst_xdgdirs");
}
void tst_xdgdirs::cleanupTestCase()
{
QCoreApplication::instance()->setOrganizationName(QString());
QCoreApplication::instance()->setApplicationName(QString());
}
void tst_xdgdirs::setDefaultLocations()
{
qputenv("XDG_CONFIG_HOME", QByteArray());
qputenv("XDG_CONFIG_DIRS", QByteArray());
qputenv("XDG_DATA_HOME", QByteArray());
qputenv("XDG_DATA_DIRS", QByteArray());
qputenv("XDG_CACHE_HOME", QByteArray());
}
void tst_xdgdirs::setCustomLocations()
{
m_configHome = m_configHomeTemp.path();
m_configDirs = m_configDirsTemp.path();
m_dataHome = m_dataHomeTemp.path();
m_dataDirs = m_dataDirsTemp.path();
m_cacheHome = m_cacheHomeTemp.path();
qputenv("XDG_CONFIG_HOME", QFile::encodeName(m_configHome));
qputenv("XDG_CONFIG_DIRS", QFile::encodeName(m_configDirs));
qputenv("XDG_DATA_HOME", QFile::encodeName(m_dataHome));
qputenv("XDG_DATA_DIRS", QFile::encodeName(m_dataDirs));
qputenv("XDG_CACHE_HOME", QFile::encodeName(m_cacheHome));
}
void tst_xdgdirs::testDataHome()
{
setDefaultLocations();
const QString expectedDataHome = QDir::homePath() + QString::fromLatin1("/.local/share");
QCOMPARE(XdgDirs::dataHome(), expectedDataHome);
QCOMPARE(XdgDirs::dataHome(false), expectedDataHome);
setCustomLocations();
QCOMPARE(XdgDirs::dataHome(), m_dataHome);
QCOMPARE(XdgDirs::dataHome(false), m_dataHome);
}
void tst_xdgdirs::testConfigHome()
{
setDefaultLocations();
const QString expectedConfigHome = QDir::homePath() + QString::fromLatin1("/.config");
QCOMPARE(XdgDirs::configHome(), expectedConfigHome);
QCOMPARE(XdgDirs::configHome(false), expectedConfigHome);
setCustomLocations();
QCOMPARE(XdgDirs::configHome(), m_configHome);
QCOMPARE(XdgDirs::configHome(false), m_configHome);
}
void tst_xdgdirs::testDataDirs()
{
const QString postfix = QString::fromLatin1("/") + QCoreApplication::applicationName();
setDefaultLocations();
const QStringList dataDirs = XdgDirs::dataDirs();
QCOMPARE(dataDirs.count(), 2);
QCOMPARE(dataDirs.at(0), QString::fromLatin1("/usr/local/share"));
QCOMPARE(dataDirs.at(1), QString::fromLatin1("/usr/share"));
const QStringList dataDirsWithPostfix = XdgDirs::dataDirs(postfix);
QCOMPARE(dataDirsWithPostfix.count(), 2);
QCOMPARE(dataDirsWithPostfix.at(0), QString::fromLatin1("/usr/local/share") + postfix);
QCOMPARE(dataDirsWithPostfix.at(1), QString::fromLatin1("/usr/share") + postfix);
setCustomLocations();
const QStringList dataDirsCustom = XdgDirs::dataDirs();
QCOMPARE(dataDirsCustom.count(), 1);
QCOMPARE(dataDirsCustom.at(0), m_dataDirs);
const QStringList dataDirsCustomWithPostfix = XdgDirs::dataDirs(postfix);
QCOMPARE(dataDirsCustomWithPostfix.count(), 1);
QCOMPARE(dataDirsCustomWithPostfix.at(0), m_dataDirs + postfix);
}
void tst_xdgdirs::testConfigDirs()
{
const QString postfix = QString::fromLatin1("/") + QCoreApplication::applicationName();
setDefaultLocations();
const QStringList configDirs = XdgDirs::configDirs();
QCOMPARE(configDirs.count(), 1);
QCOMPARE(configDirs.at(0), QString::fromLatin1("/etc/xdg"));
const QStringList configDirsWithPostfix = XdgDirs::configDirs(postfix);
QCOMPARE(configDirsWithPostfix.count(), 1);
QCOMPARE(configDirsWithPostfix.at(0), QString::fromLatin1("/etc/xdg") + postfix);
setCustomLocations();
const QStringList configDirsCustom = XdgDirs::configDirs();
QCOMPARE(configDirsCustom.count(), 1);
QCOMPARE(configDirsCustom.at(0), m_configDirs);
const QStringList configDirsCustomWithPostfix = XdgDirs::configDirs(postfix);
QCOMPARE(configDirsCustomWithPostfix.count(), 1);
QCOMPARE(configDirsCustomWithPostfix.at(0), m_configDirs + postfix);
}
void tst_xdgdirs::testCacheHome()
{
setDefaultLocations();
const QString expectedCacheHome = QDir::homePath() + QString("/.cache");
QCOMPARE(XdgDirs::cacheHome(), expectedCacheHome);
QCOMPARE(XdgDirs::cacheHome(false), expectedCacheHome);
setCustomLocations();
const QString expectedCacheHomeCustom = XdgDirs::cacheHome();
QCOMPARE(XdgDirs::cacheHome(), expectedCacheHomeCustom);
QCOMPARE(XdgDirs::cacheHome(false), expectedCacheHomeCustom);
}
void tst_xdgdirs::testAutostartHome()
{
setDefaultLocations();
const QString expectedAutoStartHome = QDir::homePath() + QString::fromLatin1("/.config/autostart");
QCOMPARE(XdgDirs::autostartHome(), expectedAutoStartHome);
QCOMPARE(XdgDirs::autostartHome(false), expectedAutoStartHome);
setCustomLocations();
const QString expectedAutostartHomeCustom = XdgDirs::configHome() + QString::fromLatin1("/autostart");
QCOMPARE(XdgDirs::autostartHome(), expectedAutostartHomeCustom);
QCOMPARE(XdgDirs::autostartHome(false), expectedAutostartHomeCustom);
}
void tst_xdgdirs::testAutostartDirs()
{
const QString postfix = QString::fromLatin1("/") + QCoreApplication::applicationName();
setDefaultLocations();
const QStringList autostartDirs = XdgDirs::autostartDirs();
QCOMPARE(autostartDirs.count(), 1);
QCOMPARE(autostartDirs.at(0), QString::fromLatin1("/etc/xdg/autostart"));
const QStringList autostartDirsWithPostfix = XdgDirs::autostartDirs(postfix);
QCOMPARE(autostartDirsWithPostfix.count(), 1);
QCOMPARE(autostartDirsWithPostfix.at(0), QString::fromLatin1("/etc/xdg/autostart") + postfix);
setCustomLocations();
const QStringList autostartDirsCustom = XdgDirs::autostartDirs();
QCOMPARE(autostartDirsCustom.count(), 1);
QCOMPARE(autostartDirsCustom.at(0), m_configDirs + QString::fromLatin1("/autostart"));
const QStringList autostartDirsCustomWithPostfix = XdgDirs::autostartDirs(postfix);
QCOMPARE(autostartDirsCustomWithPostfix.count(), 1);
QCOMPARE(autostartDirsCustomWithPostfix.at(0), m_configDirs + QString::fromLatin1("/autostart") + postfix);
}
QTEST_APPLESS_MAIN(tst_xdgdirs)
#include "tst_xdgdirs.moc"

@ -1,52 +0,0 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(QTXDG_DESKTOP_FILE_START_SRCS
qtxdg-desktop-file-start.cpp
)
set(QTXDG_ICONFINDER_SRCS
qtxdg-iconfinder.cpp
)
add_executable(qtxdg-desktop-file-start
${QTXDG_DESKTOP_FILE_START_SRCS}
)
add_executable(qtxdg-iconfinder
${QTXDG_ICONFINDER_SRCS}
)
target_include_directories(qtxdg-desktop-file-start
PRIVATE "${PROJECT_SOURCE_DIR}/qtxdg"
)
target_include_directories(qtxdg-iconfinder
PRIVATE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}"
)
target_compile_definitions(qtxdg-desktop-file-start
PRIVATE
"-DQTXDG_VERSION=\"${QTXDG_VERSION_STRING}\""
"QT_NO_KEYWORDS"
)
target_compile_definitions(qtxdg-iconfinder
PRIVATE
"-DQTXDG_VERSION=\"${QTXDG_VERSION_STRING}\""
"QT_NO_KEYWORDS"
)
target_link_libraries(qtxdg-desktop-file-start
${QTXDGX_LIBRARY_NAME}
)
target_link_libraries(qtxdg-iconfinder
${QTXDGX_ICONLOADER_LIBRARY_NAME}
)
install(TARGETS
qtxdg-desktop-file-start
qtxdg-iconfinder
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT Runtime
)

@ -1,71 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs
* Copyright (C) 2016 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QFileInfo>
#include <XdgDesktopFile>
#include <iostream>
static void printErr(const QString & out)
{
std::cerr << qPrintable(out);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName(QLatin1String("qtxdg-desktop-file-start"));
QCoreApplication::setApplicationVersion(QLatin1String(QTXDG_VERSION));
QCommandLineParser parser;
parser.setApplicationDescription(QLatin1String("QtXdg XdgDesktopFile start Tester"));
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument(QLatin1String("file [urls...]"), QLatin1String("desktop file to start and it's urls"),QLatin1String("file [urls...]"));
parser.process(app);
if (parser.positionalArguments().isEmpty()) {
parser.showHelp(EXIT_FAILURE);
}
QStringList userArgs = parser.positionalArguments();
const QString userFileName = userArgs.takeFirst();
const QFileInfo fileInfo(userFileName);
const QString canonicalFileName = fileInfo.canonicalFilePath();
if (!fileInfo.exists()) {
printErr(QString::fromLatin1("File %1 does not exist\n").arg(userFileName));
return EXIT_FAILURE;
}
XdgDesktopFile f;
const bool valid = f.load(canonicalFileName);
if (valid) {
f.startDetached(userArgs);
} else {
printErr(QString::fromLatin1("%1 is not a valid .desktop file\n").arg(canonicalFileName));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

@ -1,74 +0,0 @@
/*
* libqtxdg - An Qt implementation of freedesktop.org xdg specs
* Copyright (C) 2017 Luís Pereira <luis.artur.pereira@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <QGuiApplication> // XdgIconLoader needs a QGuiApplication
#include <QCommandLineParser>
#include <QElapsedTimer>
#include <private/xdgiconloader/xdgiconloader_p.h>
#include <iostream>
#include <QDebug>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
app.setApplicationName(QStringLiteral("qtxdg-iconfinder"));
app.setApplicationVersion(QStringLiteral(QTXDG_VERSION));
QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("QtXdg icon finder"));
parser.addPositionalArgument(QStringLiteral("iconnames"),
QStringLiteral("The icon names to search for"),
QStringLiteral("[iconnames...]"));
parser.addVersionOption();
parser.addHelpOption();
parser.process(app);
if (parser.positionalArguments().isEmpty())
parser.showHelp(EXIT_FAILURE);
qint64 totalElapsed = 0;
const auto icons = parser.positionalArguments();
for (const QString& iconName : icons) {
QElapsedTimer t;
t.start();
const auto info = XdgIconLoader::instance()->loadIcon(iconName);
qint64 elapsed = t.elapsed();
const auto icon = info.iconName;
const auto entries = info.entries;
std::cout << qPrintable(iconName) <<
qPrintable(QString::fromLatin1(":")) << qPrintable(icon) <<
qPrintable(QString::fromLatin1(":")) <<
qPrintable(QString::number(elapsed)) << "\n";
for (const auto &i : entries) {
std::cout << "\t" << qPrintable(i->filename) << "\n";
}
totalElapsed += elapsed;
}
std::cout << qPrintable(QString::fromLatin1("Total loadIcon() time: ")) <<
qPrintable(QString::number(totalElapsed)) <<
qPrintable(QString::fromLatin1(" ms")) << "\n";
return EXIT_SUCCESS;
}

@ -1,89 +0,0 @@
set(xdgiconloader_PUBLIC_H_FILES
)
set(xdgiconloader_PUBLIC_CLASSES
)
set(xdgiconloader_PRIVATE_H_FILES
)
set(xdgiconloader_CPP_FILES
xdgiconloader.cpp
)
set(xdgiconloader_MOCS
)
set(xdgiconloader_PRIVATE_INSTALLABLE_H_FILES
xdgiconloader_p.h
)
add_library(${QTXDGX_ICONLOADER_LIBRARY_NAME} SHARED
${xdgiconloader_CPP_FILES}
${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES}
)
generate_export_header(${QTXDGX_ICONLOADER_LIBRARY_NAME} BASE_NAME XdgIconLoader)
# Copy public headers (in tree building)
set(XDGICONLOADER_EXPORT_FILE "xdgiconloader_export.h")
configure_file(
"${CMAKE_CURRENT_BINARY_DIR}/${XDGICONLOADER_EXPORT_FILE}"
"${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${XDGICONLOADER_EXPORT_FILE}"
COPYONLY
)
target_compile_definitions(${QTXDGX_ICONLOADER_LIBRARY_NAME}
PRIVATE
"QT_NO_KEYWORDS"
)
target_include_directories(${QTXDGX_ICONLOADER_LIBRARY_NAME}
INTERFACE
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}>"
PUBLIC
"$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}>"
"$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}>"
"$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}>"
PRIVATE
${Qt5Gui_PRIVATE_INCLUDE_DIRS}
)
target_link_libraries(${QTXDGX_ICONLOADER_LIBRARY_NAME}
PUBLIC
Qt5::Gui
Qt5::Svg
)
set_target_properties(${QTXDGX_ICONLOADER_LIBRARY_NAME}
PROPERTIES
VERSION ${QTXDG_VERSION_STRING}
SOVERSION ${QTXDG_MAJOR_VERSION}
)
add_subdirectory(plugin)
install(TARGETS
${QTXDGX_ICONLOADER_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}"
EXPORT "${QTXDGX_ICONLOADER_FILE_NAME}-targets"
COMPONENT Runtime
)
install(FILES
${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}/private/xdgiconloader"
COMPONENT Devel
)
file(COPY
${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES}
DESTINATION "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}/private/xdgiconloader"
)
install(FILES
"${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${XDGICONLOADER_EXPORT_FILE}"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}"
)

@ -1,49 +0,0 @@
set(xdgiconengineplugin_CPP_FILES
xdgiconengineplugin.cpp
)
add_library(${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME} MODULE
${xdgiconengineplugin_CPP_FILES}
)
target_compile_definitions(${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME}
PRIVATE
"QT_NO_KEYWORDS"
)
target_link_libraries(${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME}
PUBLIC
Qt5::Gui
"${QTXDGX_ICONLOADER_LIBRARY_NAME}"
)
target_include_directories("${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME}"
PRIVATE
"${Qt5Gui_PRIVATE_INCLUDE_DIRS}"
)
mark_as_advanced(QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH)
if (NOT DEFINED QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH)
get_target_property(QT_QMAKE_EXECUTABLE ${Qt5Core_QMAKE_EXECUTABLE} IMPORTED_LOCATION)
if(NOT QT_QMAKE_EXECUTABLE)
message(FATAL_ERROR "qmake is not found.")
endif()
# execute the command "qmake -query QT_INSTALL_PLUGINS" to get the path of plugins dir.
execute_process(COMMAND "${QT_QMAKE_EXECUTABLE}" -query QT_INSTALL_PLUGINS
OUTPUT_VARIABLE QT_PLUGINS_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT QT_PLUGINS_DIR)
message(FATAL_ERROR "Qt5 plugin directory cannot be detected.")
endif()
set(QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH "${QT_PLUGINS_DIR}/iconengines")
endif()
message(STATUS "XdgIconEnginePlugin will be installed into: ${QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH}")
install(TARGETS
"${QTXDGX_ICONENGINEPLUGIN_LIBRARY_NAME}" DESTINATION "${QTXDGX_ICONENGINEPLUGIN_INSTALL_PATH}"
COMPONENT Runtime
)

@ -1,35 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight Qt based desktop
* http://lxqt.org
*
* Copyright: 2017 LXQt team
* Authors:
* Palo Kisa <palo.kisa@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgiconengineplugin.h"
#include "../xdgiconloader_p.h"
QIconEngine * XdgIconEnginePlugin::create(const QString & filename/* = QString{}*/)
{
return new XdgIconLoaderEngine{filename};
}

@ -1,38 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2+
*
* LXQt - a lightweight Qt based desktop
* http://lxqt.org
*
* Copyright: 2017 LXQt team
* Authors:
* Palo Kisa <palo.kisa@gmail.com>
*
* This program or library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* END_COMMON_COPYRIGHT_HEADER */
#include <QIconEnginePlugin>
class XdgIconEnginePlugin : public QIconEnginePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QIconEngineFactoryInterface" FILE "xdgiconengineplugin.json")
public:
using QIconEnginePlugin::QIconEnginePlugin;
virtual QIconEngine * create(const QString & filename = QString{}) override;
};

@ -1 +0,0 @@
{"Keys": ["XdgIconLoaderEngine"]}

@ -1,936 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QT_NO_ICON
#include "xdgiconloader_p.h"
#include <private/qguiapplication_p.h>
#include <private/qicon_p.h>
#include <QtGui/QIconEnginePlugin>
#include <QtGui/QPixmapCache>
#include <qpa/qplatformtheme.h>
#include <QtGui/QIconEngine>
#include <QtGui/QPalette>
#include <QtCore/qmath.h>
#include <QtCore/QList>
#include <QtCore/QDir>
#include <QtCore/QSettings>
#include <QtGui/QPainter>
#include <QImageReader>
#include <QXmlStreamReader>
#ifdef Q_DEAD_CODE_FROM_QT4_MAC
#include <private/qt_cocoa_helpers_mac_p.h>
#endif
#include <private/qhexstring_p.h>
//QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(XdgIconLoader, iconLoaderInstance)
/* Theme to use in last resort, if the theme does not have the icon, neither the parents */
static QString fallbackTheme()
{
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconFallbackThemeName);
if (themeHint.isValid()) {
const QString theme = themeHint.toString();
if (theme != QLatin1String("hicolor"))
return theme;
}
}
return QString();
}
#ifdef QT_NO_LIBRARY
static bool gSupportsSvg = false;
#else
static bool gSupportsSvg = true;
#endif //QT_NO_LIBRARY
void XdgIconLoader::setFollowColorScheme(bool enable)
{
if (m_followColorScheme != enable)
{
QIconLoader::instance()->invalidateKey();
m_followColorScheme = enable;
}
}
XdgIconLoader *XdgIconLoader::instance()
{
QIconLoader::instance()->ensureInitialized();
return iconLoaderInstance();
}
/*!
\class QIconCacheGtkReader
\internal
Helper class that reads and looks up into the icon-theme.cache generated with
gtk-update-icon-cache. If at any point we detect a corruption in the file
(because the offsets point at wrong locations for example), the reader
is marked as invalid.
*/
class QIconCacheGtkReader
{
public:
explicit QIconCacheGtkReader(const QString &themeDir);
QVector<const char *> lookup(const QStringRef &);
bool isValid() const { return m_isValid; }
private:
QFile m_file;
const unsigned char *m_data;
quint64 m_size;
bool m_isValid;
quint16 read16(uint offset)
{
if (offset > m_size - 2 || (offset & 0x1)) {
m_isValid = false;
return 0;
}
return m_data[offset+1] | m_data[offset] << 8;
}
quint32 read32(uint offset)
{
if (offset > m_size - 4 || (offset & 0x3)) {
m_isValid = false;
return 0;
}
return m_data[offset+3] | m_data[offset+2] << 8
| m_data[offset+1] << 16 | m_data[offset] << 24;
}
};
QIconCacheGtkReader::QIconCacheGtkReader(const QString &dirName)
: m_isValid(false)
{
QFileInfo info(dirName + QLatin1String("/icon-theme.cache"));
if (!info.exists() || info.lastModified() < QFileInfo(dirName).lastModified())
return;
m_file.setFileName(info.absoluteFilePath());
if (!m_file.open(QFile::ReadOnly))
return;
m_size = m_file.size();
m_data = m_file.map(0, m_size);
if (!m_data)
return;
if (read16(0) != 1) // VERSION_MAJOR
return;
m_isValid = true;
// Check that all the directories are older than the cache
auto lastModified = info.lastModified();
quint32 dirListOffset = read32(8);
quint32 dirListLen = read32(dirListOffset);
for (uint i = 0; i < dirListLen; ++i) {
quint32 offset = read32(dirListOffset + 4 + 4 * i);
if (!m_isValid || offset >= m_size || lastModified < QFileInfo(dirName + QLatin1Char('/')
+ QString::fromUtf8(reinterpret_cast<const char*>(m_data + offset))).lastModified()) {
m_isValid = false;
return;
}
}
}
static quint32 icon_name_hash(const char *p)
{
quint32 h = static_cast<signed char>(*p);
for (p += 1; *p != '\0'; p++)
h = (h << 5) - h + *p;
return h;
}
/*! \internal
lookup the icon name and return the list of subdirectories in which an icon
with this name is present. The char* are pointers to the mapped data.
For example, this would return { "32x32/apps", "24x24/apps" , ... }
*/
QVector<const char *> QIconCacheGtkReader::lookup(const QStringRef &name)
{
QVector<const char *> ret;
if (!isValid())
return ret;
QByteArray nameUtf8 = name.toUtf8();
quint32 hash = icon_name_hash(nameUtf8.data());
quint32 hashOffset = read32(4);
quint32 hashBucketCount = read32(hashOffset);
if (!isValid() || hashBucketCount == 0) {
m_isValid = false;
return ret;
}
quint32 bucketIndex = hash % hashBucketCount;
quint32 bucketOffset = read32(hashOffset + 4 + bucketIndex * 4);
while (bucketOffset > 0 && bucketOffset <= m_size - 12) {
quint32 nameOff = read32(bucketOffset + 4);
if (nameOff < m_size && strcmp(reinterpret_cast<const char*>(m_data + nameOff), nameUtf8.constData()) == 0) {
quint32 dirListOffset = read32(8);
quint32 dirListLen = read32(dirListOffset);
quint32 listOffset = read32(bucketOffset+8);
quint32 listLen = read32(listOffset);
if (!m_isValid || listOffset + 4 + 8 * listLen > m_size) {
m_isValid = false;
return ret;
}
ret.reserve(listLen);
for (uint j = 0; j < listLen && m_isValid; ++j) {
quint32 dirIndex = read16(listOffset + 4 + 8 * j);
quint32 o = read32(dirListOffset + 4 + dirIndex*4);
if (!m_isValid || dirIndex >= dirListLen || o >= m_size) {
m_isValid = false;
return ret;
}
ret.append(reinterpret_cast<const char*>(m_data) + o);
}
return ret;
}
bucketOffset = read32(bucketOffset);
}
return ret;
}
XdgIconTheme::XdgIconTheme(const QString &themeName)
: m_valid(false)
, m_followsColorScheme(false)
{
QFile themeIndex;
const QStringList iconDirs = QIcon::themeSearchPaths();
for ( int i = 0 ; i < iconDirs.size() ; ++i) {
QDir iconDir(iconDirs[i]);
QString themeDir = iconDir.path() + QLatin1Char('/') + themeName;
QFileInfo themeDirInfo(themeDir);
if (themeDirInfo.isDir()) {
m_contentDirs << themeDir;
m_gtkCaches << QSharedPointer<QIconCacheGtkReader>::create(themeDir);
}
if (!m_valid) {
themeIndex.setFileName(themeDir + QLatin1String("/index.theme"));
if (themeIndex.exists())
m_valid = true;
}
}
#ifndef QT_NO_SETTINGS
if (themeIndex.exists()) {
const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
m_followsColorScheme = indexReader.value(QStringLiteral("Icon Theme/FollowsColorScheme"), false).toBool();
const QStringList keys = indexReader.allKeys();
for (auto const &key : keys) {
if (key.endsWith(QLatin1String("/Size"))) {
// Note the QSettings ini-format does not accept
// slashes in key names, hence we have to cheat
if (int size = indexReader.value(key).toInt()) {
QString directoryKey = key.left(key.size() - 5);
QIconDirInfo dirInfo(directoryKey);
dirInfo.size = size;
QString type = indexReader.value(directoryKey +
QLatin1String("/Type")
).toString();
if (type == QLatin1String("Fixed"))
dirInfo.type = QIconDirInfo::Fixed;
else if (type == QLatin1String("Scalable"))
dirInfo.type = QIconDirInfo::Scalable;
else
dirInfo.type = QIconDirInfo::Threshold;
dirInfo.threshold = indexReader.value(directoryKey +
QLatin1String("/Threshold"),
2).toInt();
dirInfo.minSize = indexReader.value(directoryKey +
QLatin1String("/MinSize"),
size).toInt();
dirInfo.maxSize = indexReader.value(directoryKey +
QLatin1String("/MaxSize"),
size).toInt();
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
dirInfo.scale = indexReader.value(directoryKey +
QLatin1String("/Scale"),
1).toInt();
#endif
m_keyList.append(dirInfo);
}
}
}
// Parent themes provide fallbacks for missing icons
m_parents = indexReader.value(
QLatin1String("Icon Theme/Inherits")).toStringList();
m_parents.removeAll(QString());
m_parents.removeAll(QLatin1String("hicolor"));
// Ensure a default platform fallback for all themes
if (m_parents.isEmpty()) {
const QString fallback = fallbackTheme();
if (!fallback.isEmpty())
m_parents.append(fallback);
}
}
#endif //QT_NO_SETTINGS
}
/* WARNING:
*
* https://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
*
* <cite>
* The dash - character is used to separate levels of specificity in icon
* names, for all contexts other than MimeTypes. For instance, we use
* input-mouse as the generic item for all mouse devices, and we use
* input-mouse-usb for a USB mouse device. However, if the more specific
* item does not exist in the current theme, and does exist in a parent
* theme, the generic icon from the current theme is preferred, in order
* to keep consistent style.
* </cite>
*
* But we believe, that using the more specific icon (even from parents)
* is better for user experience. So we are violating the standard
* intentionally.
*
* Ref.
* https://github.com/lxde/lxqt/issues/1252
* https://github.com/lxde/libqtxdg/pull/116
*/
QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited,
bool dashFallback) const
{
QThemeIconInfo info;
Q_ASSERT(!themeName.isEmpty());
// Used to protect against potential recursions
visited << themeName;
XdgIconTheme &theme = themeList[themeName];
if (!theme.isValid()) {
theme = XdgIconTheme(themeName);
if (!theme.isValid()) {
const QString fallback = fallbackTheme();
if (!fallback.isEmpty())
theme = XdgIconTheme(fallback);
}
}
const QStringList contentDirs = theme.contentDirs();
const QString svgext(QLatin1String(".svg"));
const QString pngext(QLatin1String(".png"));
const QString xpmext(QLatin1String(".xpm"));
QStringRef iconNameFallback(&iconName);
// Iterate through all icon's fallbacks in current theme
while (info.entries.isEmpty()) {
const QString svgIconName = iconNameFallback + svgext;
const QString pngIconName = iconNameFallback + pngext;
const QString xpmIconName = iconNameFallback + xpmext;
// Add all relevant files
for (int i = 0; i < contentDirs.size(); ++i) {
QVector<QIconDirInfo> subDirs = theme.keyList();
// Try to reduce the amount of subDirs by looking in the GTK+ cache in order to save
// a massive amount of file stat (especially if the icon is not there)
auto cache = theme.m_gtkCaches.at(i);
if (cache->isValid()) {
const auto result = cache->lookup(iconNameFallback);
if (cache->isValid()) {
const QVector<QIconDirInfo> subDirsCopy = subDirs;
subDirs.clear();
subDirs.reserve(result.count());
for (const char *s : result) {
QString path = QString::fromUtf8(s);
auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(),
[&](const QIconDirInfo &info) {
return info.path == path; } );
if (it != subDirsCopy.cend()) {
subDirs.append(*it);
}
}
}
}
QString contentDir = contentDirs.at(i) + QLatin1Char('/');
for (int j = 0; j < subDirs.size() ; ++j) {
const QIconDirInfo &dirInfo = subDirs.at(j);
const QString subDir = contentDir + dirInfo.path + QLatin1Char('/');
const QString pngPath = subDir + pngIconName;
if (QFile::exists(pngPath)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = pngPath;
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
info.entries.prepend(iconEntry);
} else {
const QString svgPath = subDir + svgIconName;
if (gSupportsSvg && QFile::exists(svgPath)) {
ScalableEntry *iconEntry = (followColorScheme() && theme.followsColorScheme()) ? new ScalableFollowsColorEntry : new ScalableEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = svgPath;
info.entries.append(iconEntry);
}
}
const QString xpmPath = subDir + xpmIconName;
if (QFile::exists(xpmPath)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = xpmPath;
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
info.entries.append(iconEntry);
}
}
}
if (!info.entries.isEmpty())
info.iconName = iconNameFallback.toString();
break;
}
if (info.entries.isEmpty()) {
const QStringList parents = theme.parents();
// Search recursively through inherited themes
for (int i = 0 ; i < parents.size() ; ++i) {
const QString parentTheme = parents.at(i).trimmed();
if (!visited.contains(parentTheme)) // guard against recursion
info = findIconHelper(parentTheme, iconName, visited);
if (!info.entries.isEmpty()) // success
break;
}
}
if (dashFallback && info.entries.isEmpty()) {
// If it's possible - find next fallback for the icon
const int indexOfDash = iconNameFallback.lastIndexOf(QLatin1Char('-'));
if (indexOfDash != -1) {
iconNameFallback.truncate(indexOfDash);
QStringList _visited;
info = findIconHelper(themeName, iconNameFallback.toString(), _visited, true);
}
}
return info;
}
QThemeIconInfo XdgIconLoader::unthemedFallback(const QString &iconName, const QStringList &searchPaths) const
{
QThemeIconInfo info;
const QString svgext(QLatin1String(".svg"));
const QString pngext(QLatin1String(".png"));
const QString xpmext(QLatin1String(".xpm"));
for (const auto &contentDir : searchPaths) {
QDir currentDir(contentDir);
if (currentDir.exists(iconName + pngext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->filename = currentDir.filePath(iconName + pngext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
info.entries.prepend(iconEntry);
} else if (gSupportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->filename = currentDir.filePath(iconName + svgext);
info.entries.append(iconEntry);
} else if (currentDir.exists(iconName + xpmext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->filename = currentDir.filePath(iconName + xpmext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
info.entries.append(iconEntry);
}
}
return info;
}
QThemeIconInfo XdgIconLoader::loadIcon(const QString &name) const
{
const QString theme_name = QIconLoader::instance()->themeName();
if (!theme_name.isEmpty()) {
QStringList visited;
auto info = findIconHelper(theme_name, name, visited, true);
if (info.entries.isEmpty()) {
const auto hicolorInfo = findIconHelper(QLatin1String("hicolor"), name, visited, true);
if (hicolorInfo.entries.isEmpty()) {
const auto unthemedInfo = unthemedFallback(name, QIcon::themeSearchPaths());
if (unthemedInfo.entries.isEmpty()) {
/* Freedesktop standard says to look in /usr/share/pixmaps last */
const QStringList pixmapPath = (QStringList() << QString::fromLatin1("/usr/share/pixmaps"));
const auto pixmapInfo = unthemedFallback(name, pixmapPath);
if (pixmapInfo.entries.isEmpty()) {
return QThemeIconInfo();
} else {
return pixmapInfo;
}
} else {
return unthemedInfo;
}
} else {
return hicolorInfo;
}
} else {
return info;
}
}
return QThemeIconInfo();
}
// -------- Icon Loader Engine -------- //
XdgIconLoaderEngine::XdgIconLoaderEngine(const QString& iconName)
: m_iconName(iconName), m_key(0)
{
}
XdgIconLoaderEngine::~XdgIconLoaderEngine()
{
qDeleteAll(m_info.entries);
}
XdgIconLoaderEngine::XdgIconLoaderEngine(const XdgIconLoaderEngine &other)
: QIconEngine(other),
m_iconName(other.m_iconName),
m_key(0)
{
}
QIconEngine *XdgIconLoaderEngine::clone() const
{
return new XdgIconLoaderEngine(*this);
}
bool XdgIconLoaderEngine::read(QDataStream &in) {
in >> m_iconName;
return true;
}
bool XdgIconLoaderEngine::write(QDataStream &out) const
{
out << m_iconName;
return true;
}
bool XdgIconLoaderEngine::hasIcon() const
{
return !(m_info.entries.isEmpty());
}
// Lazily load the icon
void XdgIconLoaderEngine::ensureLoaded()
{
if (!(QIconLoader::instance()->themeKey() == m_key)) {
qDeleteAll(m_info.entries);
m_info.entries.clear();
m_info.iconName.clear();
Q_ASSERT(m_info.entries.size() == 0);
m_info = XdgIconLoader::instance()->loadIcon(m_iconName);
m_key = QIconLoader::instance()->themeKey();
}
}
void XdgIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
QIcon::Mode mode, QIcon::State state)
{
QSize pixmapSize = rect.size();
#if defined(Q_DEAD_CODE_FROM_QT4_MAC)
pixmapSize *= qt_mac_get_scalefactor();
#endif
painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
}
/*
* This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/
static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int iconscale)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
if (dir.scale != iconscale)
return false;
#endif
if (dir.type == QIconDirInfo::Fixed) {
return dir.size == iconsize;
} else if (dir.type == QIconDirInfo::Scalable) {
return iconsize <= dir.maxSize &&
iconsize >= dir.minSize;
} else if (dir.type == QIconDirInfo::Threshold) {
return iconsize >= dir.size - dir.threshold &&
iconsize <= dir.size + dir.threshold;
}
Q_ASSERT(1); // Not a valid value
return false;
}
/*
* This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/
static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
const int scaledIconSize = iconsize * iconscale;
if (dir.type == QIconDirInfo::Fixed) {
return qAbs(dir.size * dir.scale - scaledIconSize);
} else if (dir.type == QIconDirInfo::Scalable) {
if (scaledIconSize < dir.minSize * dir.scale)
return dir.minSize * dir.scale - scaledIconSize;
else if (scaledIconSize > dir.maxSize * dir.scale)
return scaledIconSize - dir.maxSize * dir.scale;
else
return 0;
} else if (dir.type == QIconDirInfo::Threshold) {
if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
return dir.minSize * dir.scale - scaledIconSize;
else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
return scaledIconSize - dir.maxSize * dir.scale;
else return 0;
}
#else
if (dir.type == QIconDirInfo::Fixed) {
return qAbs(dir.size - iconsize);
} else if (dir.type == QIconDirInfo::Scalable) {
if (iconsize < dir.minSize)
return dir.minSize - iconsize;
else if (iconsize > dir.maxSize)
return iconsize - dir.maxSize;
else
return 0;
} else if (dir.type == QIconDirInfo::Threshold) {
if (iconsize < dir.size - dir.threshold)
return dir.minSize - iconsize;
else if (iconsize > dir.size + dir.threshold)
return iconsize - dir.maxSize;
else return 0;
}
#endif
Q_ASSERT(1); // Not a valid value
return INT_MAX;
}
QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int scale)
{
int iconsize = qMin(size.width(), size.height());
// Note that m_info.entries are sorted so that png-files
// come first
const int numEntries = m_info.entries.size();
// Search for exact matches first
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_info.entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize, scale)) {
return entry;
}
}
// Find the minimum distance icon
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_info.entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize, scale);
if (distance < minimalSize) {
minimalSize = distance;
closestMatch = entry;
}
}
return closestMatch;
}
/*
* Returns the actual icon size. For scalable svg's this is equivalent
* to the requested size. Otherwise the closest match is returned but
* we can never return a bigger size than the requested size.
*
*/
QSize XdgIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
QIcon::State state)
{
ensureLoaded();
QIconLoaderEngineEntry *entry = entryForSize(size);
if (entry) {
const QIconDirInfo &dir = entry->dir;
if (dir.type == QIconDirInfo::Scalable || dynamic_cast<ScalableEntry *>(entry))
return size;
else {
int dir_size = dir.size;
//Note: fallback for directories that don't have its content size defined
// -> get the actual size based on the image if possible
PixmapEntry * pix_e;
if (0 == dir_size && nullptr != (pix_e = dynamic_cast<PixmapEntry *>(entry)))
{
QSize pix_size = pix_e->basePixmap.size();
dir_size = qMin(pix_size.width(), pix_size.height());
}
int result = qMin(dir_size, qMin(size.width(), size.height()));
return QSize(result, result);
}
}
return {0, 0};
}
// XXX: duplicated from qiconloader.cpp, because this symbol isn't exported :(
QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
{
Q_UNUSED(state);
// Ensure that basePixmap is lazily initialized before generating the
// key, otherwise the cache key is not unique
if (basePixmap.isNull())
basePixmap.load(filename);
QSize actualSize = basePixmap.size();
// If the size of the best match we have (basePixmap) is larger than the
// requested size, we downscale it to match.
if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio);
QString key = QLatin1String("$qt_theme_")
% HexString<qint64>(basePixmap.cacheKey())
% HexString<int>(mode)
% HexString<qint64>(QGuiApplication::palette().cacheKey())
% HexString<int>(actualSize.width())
% HexString<int>(actualSize.height());
QPixmap cachedPixmap;
if (QPixmapCache::find(key, &cachedPixmap)) {
return cachedPixmap;
} else {
if (basePixmap.size() != actualSize)
cachedPixmap = basePixmap.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
else
cachedPixmap = basePixmap;
if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
cachedPixmap = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, cachedPixmap);
QPixmapCache::insert(key, cachedPixmap);
}
return cachedPixmap;
}
// XXX: duplicated from qiconloader.cpp, because this symbol isn't exported :(
QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
{
if (svgIcon.isNull())
svgIcon = QIcon(filename);
// Simply reuse svg icon engine
return svgIcon.pixmap(size, mode, state);
}
// XXX: duplicated from qicon.cpp, because the symbol qt_iconEngineFactoryLoader isn't exported :(
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qt_iconEngineFactoryLoader,
(QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive))
//extern QFactoryLoader *qt_iconEngineFactoryLoader(); // qicon.cpp
QPixmap ScalableFollowsColorEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
{
QIcon & icon = QIcon::Selected == mode ? svgSelectedIcon : svgIcon;
if (icon.isNull())
{
// The following lines are adapted and updated from KDE's "kiconloader.cpp" ->
// KIconLoaderPrivate::processSvg() and KIconLoaderPrivate::createIconImage().
// They read the SVG color scheme of SVG icons and give images based on the icon mode.
QByteArray processedContents;
QFile device{filename};;
if (device.open(QIODevice::ReadOnly))
{
const QPalette pal = qApp->palette();
QString styleSheet = QStringLiteral(".ColorScheme-Text{color:%1;}")
.arg(mode == QIcon::Selected
? pal.highlightedText().color().name()
: pal.windowText().color().name());
QXmlStreamReader xmlReader(&device);
QXmlStreamWriter writer(&processedContents);
while (!xmlReader.atEnd())
{
if (xmlReader.readNext() == QXmlStreamReader::StartElement
&& xmlReader.qualifiedName() == QLatin1String("style")
&& xmlReader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme"))
{
writer.writeStartElement(QLatin1String("style"));
writer.writeAttributes(xmlReader.attributes());
writer.writeCharacters(styleSheet);
writer.writeEndElement();
while (xmlReader.tokenType() != QXmlStreamReader::EndElement)
xmlReader.readNext();
}
else if (xmlReader.tokenType() != QXmlStreamReader::Invalid)
writer.writeCurrentToken(xmlReader);
}
}
// use the QSvgIconEngine
// - assemble the content as it is done by the QSvgIconEngine::write() (operator <<)
// - create the QIcon with QSvgIconEngine initialized from the content
const int index = qt_iconEngineFactoryLoader()->indexOf(QStringLiteral("svg"));
if (index != -1)
{
if (QIconEnginePlugin * factory = qobject_cast<QIconEnginePlugin*>(qt_iconEngineFactoryLoader()->instance(index)))
{
if (QIconEngine * engine = factory->create())
{
QByteArray engine_arr;
QDataStream str{&engine_arr, QIODevice::WriteOnly};
str.setVersion(QDataStream::Qt_4_4);
QHash<int, QString> filenames;
filenames[0] = filename;
QHash<int, QByteArray> svg_buffers;
svg_buffers[0] = processedContents;
str << filenames << static_cast<int>(0)/*isCompressed*/ << svg_buffers << static_cast<int>(0)/*hasAddedPimaps*/;
QDataStream str_read{&engine_arr, QIODevice::ReadOnly};
str_read.setVersion(QDataStream::Qt_4_4);
engine->read(str_read);
icon = QIcon{engine};
}
}
}
// load the icon directly from file, if still null
if (icon.isNull())
icon = QIcon(filename);
}
return icon.pixmap(size, mode, state);
}
QPixmap XdgIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
QIcon::State state)
{
ensureLoaded();
QIconLoaderEngineEntry *entry = entryForSize(size);
if (entry)
return entry->pixmap(size, mode, state);
return QPixmap();
}
QString XdgIconLoaderEngine::key() const
{
return QLatin1String("XdgIconLoaderEngine");
}
void XdgIconLoaderEngine::virtual_hook(int id, void *data)
{
ensureLoaded();
switch (id) {
case QIconEngine::AvailableSizesHook:
{
QIconEngine::AvailableSizesArgument &arg
= *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data);
const int N = m_info.entries.size();
QList<QSize> sizes;
sizes.reserve(N);
// Gets all sizes from the DirectoryInfo entries
for (int i = 0; i < N; ++i) {
int size = m_info.entries.at(i)->dir.size;
sizes.append(QSize(size, size));
}
arg.sizes.swap(sizes); // commit
}
break;
case QIconEngine::IconNameHook:
{
QString &name = *reinterpret_cast<QString*>(data);
name = m_info.iconName;
}
break;
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
case QIconEngine::IsNullHook:
{
*reinterpret_cast<bool*>(data) = m_info.entries.isEmpty();
}
break;
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
case QIconEngine::ScaledPixmapHook:
{
QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(data);
// QIcon::pixmap() multiplies size by the device pixel ratio.
const int integerScale = qCeil(arg.scale);
QIconLoaderEngineEntry *entry = entryForSize(arg.size / integerScale, integerScale);
arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap();
}
break;
#endif
default:
QIconEngine::virtual_hook(id, data);
}
}
//QT_END_NAMESPACE
#endif //QT_NO_ICON

@ -1,160 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef XDGICONLOADER_P_H
#define XDGICONLOADER_P_H
#include <QtCore/qglobal.h>
#ifndef QT_NO_ICON
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <xdgiconloader_export.h>
#include <QtGui/QIcon>
#include <QtGui/QIconEngine>
#include <private/qicon_p.h>
#include <private/qiconloader_p.h>
#include <QtCore/QHash>
#include <QtCore/QVector>
//QT_BEGIN_NAMESPACE
class XdgIconLoader;
struct ScalableFollowsColorEntry : public ScalableEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIcon svgSelectedIcon;
};
//class QIconLoaderEngine : public QIconEngine
class XDGICONLOADER_EXPORT XdgIconLoaderEngine : public QIconEngine
{
public:
XdgIconLoaderEngine(const QString& iconName = QString());
~XdgIconLoaderEngine();
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIconEngine *clone() const Q_DECL_OVERRIDE;
bool read(QDataStream &in) Q_DECL_OVERRIDE;
bool write(QDataStream &out) const Q_DECL_OVERRIDE;
private:
QString key() const Q_DECL_OVERRIDE;
bool hasIcon() const;
void ensureLoaded();
void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
QIconLoaderEngineEntry *entryForSize(const QSize &size, int scale = 1);
XdgIconLoaderEngine(const XdgIconLoaderEngine &other);
QThemeIconInfo m_info;
QString m_iconName;
uint m_key;
friend class XdgIconLoader;
};
class QIconCacheGtkReader;
// Note: We can't simply reuse the QIconTheme from Qt > 5.7 because
// the QIconTheme constructor symbol isn't exported.
class XdgIconTheme
{
public:
XdgIconTheme(const QString &name);
XdgIconTheme() = default;
QStringList parents() { return m_parents; }
QVector <QIconDirInfo> keyList() { return m_keyList; }
QStringList contentDirs() { return m_contentDirs; }
bool isValid() const { return m_valid; }
bool followsColorScheme() const { return m_followsColorScheme; }
private:
QStringList m_contentDirs;
QVector <QIconDirInfo> m_keyList;
QStringList m_parents;
bool m_valid = false;
bool m_followsColorScheme = false;
public:
QVector<QSharedPointer<QIconCacheGtkReader>> m_gtkCaches;
};
class XDGICONLOADER_EXPORT XdgIconLoader
{
public:
QThemeIconInfo loadIcon(const QString &iconName) const;
/* TODO: deprecate & remove all QIconLoader wrappers */
inline uint themeKey() const { return QIconLoader::instance()->themeKey(); }
inline QString themeName() const { return QIconLoader::instance()->themeName(); }
inline void setThemeName(const QString &themeName) { QIconLoader::instance()->setThemeName(themeName); }
inline void setThemeSearchPath(const QStringList &searchPaths) { QIconLoader::instance()->setThemeSearchPath(searchPaths); }
inline QIconDirInfo dirInfo(int dirindex) { return QIconLoader::instance()->dirInfo(dirindex); }
inline QStringList themeSearchPaths() const { return QIconLoader::instance()->themeSearchPaths(); }
inline void updateSystemTheme() { QIconLoader::instance()->updateSystemTheme(); }
inline void invalidateKey() { QIconLoader::instance()->invalidateKey(); }
inline void ensureInitialized() { QIconLoader::instance()->ensureInitialized(); }
inline bool hasUserTheme() const { return QIconLoader::instance()->hasUserTheme(); }
/*!
* Flag if the "FollowsColorScheme" hint (the KDE extension to XDG
* themes) should be honored.
*/
inline bool followColorScheme() const { return m_followColorScheme; }
void setFollowColorScheme(bool enable);
XdgIconTheme theme() { return themeList.value(QIconLoader::instance()->themeName()); }
static XdgIconLoader *instance();
private:
QThemeIconInfo findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited,
bool dashFallback = false) const;
QThemeIconInfo unthemedFallback(const QString &iconName, const QStringList &searchPaths) const;
mutable QHash <QString, XdgIconTheme> themeList;
bool m_followColorScheme = true;
};
#endif // QT_NO_ICON
#endif // XDGICONLOADER_P_H
Loading…
Cancel
Save