Compare commits

...

5 Commits

Author SHA1 Message Date
Alf Gaida
7abe319414
Adding upstream version 3.0.0.
Signed-off-by: Alf Gaida <agaida@siduction.org>
2017-09-23 00:51:06 +02:00
Alf Gaida
1e3819068c Adding upstream version 2.0.0. 2016-09-18 02:03:11 +02:00
Alf Gaida
7aa602d177 Adding upstream version 1.3.1~50-g4fde773. 2016-07-09 19:45:19 +02:00
Alf Gaida
9e92aa7936 Adding upstream version 1.3.0. 2015-10-28 17:29:46 +01:00
Andrew Lee (李健秋)
f0d36ad500
Adding upstream version 1.2.0+20150807.
Signed-off-by: Andrew Lee (李健秋) <ajqlee@debian.org>
2015-08-14 04:01:38 +08:00
76 changed files with 4137 additions and 4320 deletions

34
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,34 @@
<!--- Provide a general summary of the issue in the Title above -->
<!--- You could delete sections and/or questions irrelevant to your report --->
##### Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
##### Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
##### Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
##### Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
##### Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
##### System Information
<!--- Include as many relevant details about the system you experienced the bug in -->
* Distribution & Version:
* Kernel:
* Qt Version:
* cmake Version:
* Package version:

8
.gitignore vendored
View File

@ -1,8 +0,0 @@
build*
*.qm
*~
*.autosave
*-swp
*.swp
CMakeLists.txt.user*
nbproject/

View File

@ -4,7 +4,8 @@ Upstream Authors:
Copyright:
Copyright (c) 2010-2012 Razor team
Copyright (c) 2012-2014 LXQt team
Copyright (c) 2012-2017 LXQt team
License: GPL-2 and LGPL-2.1+
The full text of the licenses can be found in the 'COPYING' file.
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.

424
CHANGELOG Normal file
View File

@ -0,0 +1,424 @@
libqtxdg-3.0.0 / 2017-09-22
===========================
* 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

View File

@ -1,331 +1,82 @@
cmake_minimum_required( VERSION 2.8.5 )
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
project(libqtxdg)
# Support different versions of Qt
option(USE_QT4 "Build with Qt4." $ENV{USE_QT4})
option(BUILD_TESTS "Builds tests" OFF)
if (USE_QT4)
set(USE_QT5 FALSE)
else()
set(USE_QT5 TRUE)
endif()
# The Qt4 version can be compiled with libmagic or with QtMimeTypes
# QtMimeTypes is the preferred way and also the default. libmagic will be
# dropped in future releases.
if (NOT USE_QT5)
option(USE_QTMIMETYPES "Use QtMimeTypes library" ON)
endif()
# Standard directories for installation
include(GNUInstallDirs)
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")
set (MAJOR_VERSION 1)
set (MINOR_VERSION 2)
set (PATCH_VERSION 0)
set(QTXDG_VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION})
add_definitions(-Wall -DQTXDG_COMPILATION=1)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(QTXDG_COMPILER_IS_CLANGCXX 1)
endif()
if (CMAKE_COMPILER_IS_GNUCXX OR QTXDG_COMPILER_IS_CLANGCXX)
# set visibility to hidden to hide symbols, unless they're exported manually in the code
set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden -fno-exceptions ${CMAKE_CXX_FLAGS}")
endif()
find_package(PkgConfig)
if (USE_QT5)
cmake_minimum_required(VERSION 2.8.11)
find_package(Qt5Widgets REQUIRED QUIET)
find_package(Qt5Xml REQUIRED QUIET)
find_package(Qt5DBus REQUIRED QUIET)
if (BUILD_TESTS)
find_package(Qt5Test REQUIRED QUIET)
endif()
# if both Qt4 and Qt5 are installed we must check what version was found
if (NOT ${Qt5Core_VERSION_MAJOR} EQUAL 5)
message(FATAL_ERROR "Qt was found, but NOT Qt5.")
endif()
set(QTXDGX_LIBRARY_NAME "Qt5Xdg")
set(QTXDGX_FILE_NAME "qt5xdg")
set(QTXDGX_PKG_CONFIG_DESCRIPTION "Qt5Xdg, a Qt5 implementation of XDG standards")
set(QTXDGX_PKG_CONFIG_REQUIRES "Qt5Core, Qt5Xml, Qt5Widgets, Qt5DBus")
include_directories(
"${Qt5Widgets_INCLUDE_DIRS}"
"${Qt5Gui_PRIVATE_INCLUDE_DIRS}"
"${Qt5Xml_INCLUDE_DIRS}"
)
add_definitions(${Qt5Core_DEFINITIONS})
# set(CMAKE_CXX_FLAGS
# "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}"
# )
# QMimeDatabase and QMimeType are part of Qt5Core
# We just use that as an mimetype provider.
# An empty MIMETYPES_PROVIDER_LIBRARY means we are using Qt internal
# mimetypes support
set(MIMETYPES_PROVIDER_LIBRARY "")
add_definitions("-DHAVE_QTMIMETYPES")
set(QTX_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5Xml_LIBRARIES} ${Qt5DBus_LIBRARIES})
message(STATUS "Building with Qt ${Qt5Core_VERSION_STRING}")
else()
find_package(Qt4 REQUIRED QtCore QtGui QtXml QtDBus QUIET)
if (BUILD_TESTS)
find_package(Qt4 REQUIRED QtTest QUIET)
endif()
# if both Qt4 and Qt5 are installed we must check what version was found
if (NOT ${QT_VERSION_MAJOR} EQUAL 4)
message(FATAL_ERROR "Qt was found, but NOT Qt4")
endif()
set(QTXDGX_LIBRARY_NAME "qtxdg")
set(QTXDGX_FILE_NAME "qtxdg")
set(QTXDGX_PKG_CONFIG_DESCRIPTION "QtXdg, a Qt4 implementation of XDG standards")
include(${QT_USE_FILE})
set(QTX_LIBRARIES
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${QT_QTXML_LIBRARY}
${QT_QTDBUS_LIBRARY}
)
message(STATUS "Building with Qt ${QTVERSION}")
endif()
set(libqtxdg_PUBLIC_H_FILES
xdgaction.h
xdgdesktopfile.h
xdgdirs.h
xdgicon.h
xdgmenu.h
xdgmenuwidget.h
xmlhelper.h
xdgautostart.h
xdgmacros.h
)
set(libqtxdg_PUBLIC_CLASSES
XdgAction
XdgDesktopFile
XdgDirs
XdgIcon
XdgMenu
XdgMenuWidget
XmlHelper
XdgAutoStart
)
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
)
set(libqtxdg_MOCS
xdgaction.h
xdgmenuapplinkprocessor.h
xdgmenu.h
xdgmenu_p.h
xdgmenureader.h
xdgmenurules.h
xdgmenuwidget.h
)
if (USE_QT5)
list(APPEND libqtxdg_PRIVATE_INSTALLABLE_H_FILES qiconfix/qiconloader_p.h)
list(APPEND libqtxdg_CPP_FILES qiconfix/qiconloader.cpp)
else()
list(APPEND libqtxdg_PRIVATE_H_FILES qiconfix/qiconloader_p_qt4.h)
list(APPEND libqtxdg_CPP_FILES qiconfix/qiconloader_qt4.cpp)
endif()
if (NOT USE_QT5)
if (USE_QTMIMETYPES)
# Using QtMimeTypes to provide a better mimetype support on Qt4
# Project repo: https://qt.gitorious.org/qtplayground/mimetypes
pkg_check_modules(QTMIMETYPES REQUIRED
QtMimeTypes
)
include_directories("${QTMIMETYPES_INCLUDE_DIRS}")
set(QTXDGX_PKG_CONFIG_REQUIRES "QtCore, QtXml, QtDbus, QtMimeTypes")
set(MIMETYPES_PROVIDER_LIBRARY ${QTMIMETYPES_LIBRARIES})
link_directories("${QTMIMETYPES_LIBRARY_DIRS}")
add_definitions("-DHAVE_QTMIMETYPES")
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()
# Use libmagic
find_package(LibMagic REQUIRED QUIET)
set(MIMETYPES_PROVIDER_LIBRARY ${LIBMAGIC_LIBRARY})
set(QTXDGX_PKG_CONFIG_REQUIRES "QtCore, QtXml, QtDBus")
list(APPEND libqtxdg_PUBLIC_H_FILES xdgmime.h)
list(APPEND libqtxdg_PUBLIC_CLASSES XdgMime)
list(APPEND libqtxdg_CPP_FILES xdgmime.cpp)
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()
endif()
if (USE_QTMIMETYPES OR USE_QT5)
list(APPEND libqtxdg_PUBLIC_H_FILES xdgmimetype.h)
list(APPEND libqtxdg_PUBLIC_CLASSES XdgMimeType)
list(APPEND libqtxdg_CPP_FILES xdgmimetype.cpp)
endif()
set(APP_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/lib${QTXDGX_FILE_NAME}")
add_definitions(-DTRANSLATIONS_DIR=\"${APP_SHARE_DIR}\")
#************************************************
# Build 2 config.cmake files
# One for in-tree build and second for normal one.
#************************************************
set(QTXDG_MAJOR_VERSION ${MAJOR_VERSION})
set(QTXDG_MINOR_VERSION ${MINOR_VERSION})
set(QTXDG_PATCH_VERSION ${PATCH_VERSION})
# In tree compilation ......................
set(QTXDG_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}")
if (USE_QT5)
set(QTXDG_PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/qiconfix")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt5xdg-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/${QTXDGX_FILE_NAME}-config.cmake"
@ONLY
)
else()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/qtxdg-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/${QTXDGX_FILE_NAME}-config.cmake"
@ONLY
)
set(CMAKE_CXX_STANDARD 11)
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/${QTXDGX_FILE_NAME}_use.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/${QTXDGX_FILE_NAME}_use.cmake"
@ONLY
)
set(QTXDG_MAJOR_VERSION 3)
set(QTXDG_MINOR_VERSION 0)
set(QTXDG_PATCH_VERSION 0)
set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION})
# Instalable ...............................
set(QTXDG_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}")
set(QT_MINIMUM_VERSION "5.6.1")
if (USE_QT5)
set(QTXDG_PRIVATE_INCLUDE_DIR "${QTXDG_INCLUDE_DIR}/${QTXDG_VERSION_STRING}")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt5xdg-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake"
@ONLY
)
else()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/qtxdg-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake"
@ONLY
)
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()
#**********************************************************
include(FindLibSuffix)
set(QTXDGX_LIBRARY_NAME "Qt5Xdg")
set(QTXDGX_FILE_NAME "qt5xdg")
if(USE_QT5)
QT5_WRAP_CPP(libqtxdg_CXX_FILES ${libqtxdg_MOCS})
else()
QT4_WRAP_CPP(libqtxdg_CXX_FILES ${libqtxdg_MOCS})
endif()
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_library(${QTXDGX_LIBRARY_NAME} SHARED
${libqtxdg_PUBLIC_H_FILES}
${libqtxdg_PRIVATE_H_FILES}
${libqtxdg_PRIVATE_INSTALLABLE_H_FILES}
${libqtxdg_PRIVATE_H_FILES}
${libqtxdg_CPP_FILES}
${libqtxdg_CXX_FILES}
)
target_link_libraries(${QTXDGX_LIBRARY_NAME}
${QTX_LIBRARIES}
${MIMETYPES_PROVIDER_LIBRARY}
)
set_target_properties(${QTXDGX_LIBRARY_NAME} PROPERTIES
VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}
SOVERSION ${MAJOR_VERSION}
)
# create the portable headers
include(create_portable_headers)
create_portable_headers(libqtxdg_PORTABLE_HEADERS ${libqtxdg_PUBLIC_CLASSES})
install(TARGETS ${QTXDGX_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES ${libqtxdg_PUBLIC_H_FILES} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}")
if (USE_QT5)
install(FILES
${libqtxdg_PRIVATE_INSTALLABLE_H_FILES}
DESTINATION
"${QTXDG_PRIVATE_INCLUDE_DIR}/private/qtxdg"
)
endif()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${QTXDGX_FILE_NAME}-config.cmake" DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/${QTXDGX_FILE_NAME}_use.cmake" DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTXDGX_FILE_NAME}")
install(FILES ${libqtxdg_PORTABLE_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}")
include(create_pkgconfig_file)
create_pkgconfig_file(${QTXDGX_LIBRARY_NAME}
${QTXDGX_PKG_CONFIG_DESCRIPTION}
${QTXDGX_PKG_CONFIG_REQUIRES}
${QTXDGX_FILE_NAME}
${QTXDG_VERSION_STRING}
)
add_subdirectory(xdgiconloader)
add_subdirectory(qtxdg)
if(BUILD_TESTS)
enable_testing()
add_definitions(-DQTXDG_TESTS=1)
target_compile_definitions(${QTXDGX_LIBRARY_NAME}
PRIVATE "QTXDG_TESTS=\"1\""
)
add_subdirectory(test)
else()
message(STATUS "")
@ -333,22 +84,90 @@ else()
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")
# building tarball with CPack -------------------------------------------------
include (InstallRequiredSystemLibraries)
set (CPACK_PACKAGE_VERSION_MAJOR ${MAJOR_VERSION})
set (CPACK_PACKAGE_VERSION_MINOR ${MINOR_VERSION})
set (CPACK_PACKAGE_VERSION_PATCH ${PATCH_VERSION})
set (CPACK_GENERATOR TBZ2)
set (CPACK_SOURCE_GENERATOR TBZ2)
set (CPACK_SOURCE_IGNORE_FILES /build/;.gitignore;.*~;.git;.kdev4;temp)
include (CPack)
#add_custom_target(uninstall
# COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

View File

@ -0,0 +1,22 @@
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.

43
README
View File

@ -1,43 +0,0 @@
Overview
========
libqtxdg is An Qt implementation of freedesktop.org xdg specifications.
It can be built with Qt4 and Qt5
Dependencies
============
Qt4 build:
Qt4
libmagic OR QtMimeTypes
QtMimeTypes the preffered. libmagic is deprecated and may be dropped in future
releases.
QtMimeTypes can be found at: https://qt.gitorious.org/qtplayground/mimetypes
Qt5 build:
Qt5
Configuration
============
libqtxdg uses the CMake build system. Everything that applies to CMake also
applies here.
Configuration options:
USE_QT5 Builds with Qt5, defaults to then environment variable
with the same name.
USE_QTMIMETYPES It only affects the Qt4 build. Builds using QtMimeTypes.
Defaults to On. If set to OFF libmagic will be used.
BUILD_TESTS Builds tests, defaults to OFF
Configuration Examples:
Build with Qt5 and build self tests:
cmake -DUSE_QT5=ON -DBUILD_TESTS=ON ..
Build with Qt4 and no tests using QtMimeTypes
cmake -DUSE_QT5=OFF ..
Build with Qt4, no tests and using libmagic
cmake -DUSE_QT5=OFF -DUSE_QTMIMETYPES=OFF ..

27
README.md Normal file
View File

@ -0,0 +1,27 @@
# 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`.

View File

@ -1,23 +0,0 @@
FIND_PATH(LIBMAGIC_INCLUDE_DIR magic.h)
FIND_LIBRARY(LIBMAGIC_LIBRARY NAMES magic)
IF (LIBMAGIC_INCLUDE_DIR AND LIBMAGIC_LIBRARY)
SET(LIBMAGIC_FOUND TRUE)
ENDIF (LIBMAGIC_INCLUDE_DIR AND LIBMAGIC_LIBRARY)
IF (LIBMAGIC_FOUND)
IF (NOT LibMagic_FIND_QUIETLY)
MESSAGE(STATUS "Found libmagic: ${LIBMAGIC_LIBRARY}")
MESSAGE(STATUS " includes: ${LIBMAGIC_INCLUDE_DIR}")
ENDIF (NOT LibMagic_FIND_QUIETLY)
ELSE (LIBMAGIC_FOUND)
IF (LibMagic_FIND_REQUIRED)
MESSAGE(STATUS "")
MESSAGE(STATUS "libmagic development package cannot be found. Install it, please")
MESSAGE(STATUS "For example in (open)SUSE it's file-devel package")
MESSAGE(STATUS "")
MESSAGE(FATAL_ERROR "Could not find libmagic")
ENDIF (LibMagic_FIND_REQUIRED)
ENDIF (LIBMAGIC_FOUND)

View File

@ -1,26 +0,0 @@
# some system (rpm builds) setup LIB_SUFFIX for cmake. If there is no set, try to get it from system
IF(NOT DEFINED LIB_SUFFIX AND LIB_SUFFIX_ALREADY_SET)
MESSAGE(STATUS "*********************************************************************")
MESSAGE(STATUS "LIB_SUFFIX variable is not defined. It will be autodetected now")
MESSAGE(STATUS "You can set it manually with -DLIB_SUFFIX=<value> (64 for example)")
# All 32bit system have empty lib suffix
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# If there is lib64 dir, set suffix to 64
if(IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib64")
set(LIB_SUFFIX 64)
elseif(IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib")
set(LIB_SUFFIX "")
else()
message(WARNING "LIB_SUFFIX cannot be autodetected. No \"${CMAKE_INSTALL_PREFIX}/lib\" neither \"${CMAKE_INSTALL_PREFIX}/lib64\" found.")
set(LIB_SUFFIX "")
endif()
else()
set(LIB_SUFFIX "")
endif()
set(LIB_SUFFIX_ALREADY_SET 1)
message(STATUS "LIB_SUFFIX autodetected as '${LIB_SUFFIX}', libraries will be installed into \"${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}\"")
MESSAGE(STATUS "*********************************************************************")
ENDIF(NOT DEFINED LIB_SUFFIX AND LIB_SUFFIX_ALREADY_SET)

View File

@ -0,0 +1,171 @@
#=============================================================================
# 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()

View File

@ -1,36 +1,245 @@
#=============================================================================
# Copyright 2015 Luís Pereira <luis.artur.pereira@gmail.com>
#
# Write a pkg-config pc file for given "name" with "decription"
# Arguments:
# name: a library name (withoud "lib" prefix and "so" suffixes
# desc: a desription string
# requires: required libraries
# include_rel_dir: include directory, relative to includedir
# version: package version
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
macro (create_pkgconfig_file name desc requires include_rel_dir version)
set(_pkgfname "${CMAKE_CURRENT_BINARY_DIR}/${name}.pc")
message(STATUS "${name}: writing pkgconfig file ${_pkgfname}")
# 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.
#=============================================================================#
file(WRITE "${_pkgfname}"
"# file generated by razor-qt cmake build\n"
"prefix=${CMAKE_INSTALL_PREFIX}\n"
"libdir=\${prefix}/${CMAKE_INSTALL_LIBDIR}\n"
"includedir=\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\n"
"\n"
"Name: ${name}\n"
"Description: ${desc}\n"
"Version: ${version}\n"
"Requires: ${requires}\n"
"Libs: -L\${libdir} -l${name}\n"
"Cflags: -I\${includedir} -I\${includedir}/${include_rel_dir}\n"
"\n"
# 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")
install(FILES ${_pkgfname} DESTINATION libdata/pkgconfig)
set(_PKGCONFIG_INSTALL_DESTINATION "libdata/pkgconfig")
else()
install(FILES ${_pkgfname} DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
set(_PKGCONFIG_INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
endmacro()
# Make the COMPONENT an parameter ?
install(FILES "${_PKGCONFIG_FILE}"
DESTINATION "${_PKGCONFIG_INSTALL_DESTINATION}"
COMPONENT Devel)
endif()
endfunction()

View File

@ -1,8 +1,51 @@
#=============================================================================
# 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})
@ -11,18 +54,39 @@
function(create_portable_headers outfiles)
set(options)
set(oneValueArgs)
set(multiValueArgs)
set(oneValueArgs OUTPUT_DIR)
set(multiValueArgs HEADER_NAMES)
cmake_parse_arguments(_CREATE_PORTABLE_HEADERS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(class_list ${_CREATE_PORTABLE_HEADERS_UNPARSED_ARGUMENTS})
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 "${CMAKE_CURRENT_BINARY_DIR}/${f}"
file(WRITE "${_OUTPUT_DIR}/${f}"
"#include \"${_filename}\"")
list(APPEND ${outfiles} "${CMAKE_CURRENT_BINARY_DIR}/${f}")
list(APPEND ${outfiles} "${_OUTPUT_DIR}/${f}")
endforeach()
set(${outfiles} ${${outfiles}} PARENT_SCOPE)

View File

@ -1,54 +1,15 @@
# - Find the QtXdg include and library dirs and define a some macros
#
# The module defines the following variables
# QTXDG_FOUND - Set to TRUE if all of the above has been found
#
# QTXDG_INCLUDE_DIR - The QtXdg include directory
#
# QTXDG_INCLUDE_DIRS - The QtXdg lib and it's dependencies include directories
#
# QTXDG_LIBRARY_DIRS - The QtXdg lib and it's dependencies linker search paths
#
# QTXDG_LIBRARY - The QtXdg library itself
# QTXDG_LIBRARIES - The QtXdg library and all it's dependencies
#
# QTXDG_USE_FILE - The variable QTXDG_USE_FILE is set which is the path
# to a CMake file that can be included to compile qtxdg
# applications and libraries. It sets up the compilation
# environment for include directories and populates a
# QTXDG_LIBRARIES variable.
#
# QTXDG_QT_LIBRARIES - The QtXdg Qt dependencies libraries
#
# Typical usage:
# option(USE_QT5 "Build using Qt5. Default off" OFF)
# if (USE_QT5)
# find_package(QT5XDG)
# else()
# find_package(QTXDG)
# endif()
#
# include(${QTXDG_USE_FILE})
# add_executable(use-qtxdg main.cpp)
# target_link_libraries(use-qtxdg ${QTXDG_LIBRARIES})
@PACKAGE_INIT@
set(QTXDG_INCLUDE_DIR "@QTXDG_INCLUDE_DIR@")
set(QTXDG_LIBRARY @QTXDGX_LIBRARY_NAME@)
set(QTXDG_PRIVATE_INCLUDE_DIR "@QTXDG_PRIVATE_INCLUDE_DIR@" CACHE PATH "Qt5Xdg private include dir")
if (NOT TARGET @QTXDGX_LIBRARY_NAME@)
include(CMakeFindDependencyMacro)
set(QTXDG_LIBRARIES ${QTXDG_LIBRARY})
set(QTXDG_INCLUDE_DIRS "${QTXDG_INCLUDE_DIR}")
set(QTXDG_PRIVATE_INCLUDE_DIRS "${QTXDG_PRIVATE_INCLUDE_DIR}")
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)
set(QTXDG_LIBRARY_DIRS "@CMAKE_INSTALL_FULL_LIBDIR@")
set(QTXDG_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/@QTXDGX_FILE_NAME@_use.cmake")
set(QTXDG_FOUND 1)
set(QTXDG_QTMIMETYPES @USE_QTMIMETYPES@)
set(QTXDG_MAJOR_VERSION @QTXDG_MAJOR_VERSION@)
set(QTXDG_MINOR_VERSION @QTXDG_MINOR_VERSION@)
set(QTXDG_PATCH_VERSION @QTXDG_PATCH_VERSION@)
set(QTXDG_VERSION @QTXDG_MAJOR_VERSION@.@QTXDG_MINOR_VERSION@.@QTXDG_PATCH_VERSION@)
mark_as_advanced(QTXDG_LIBRARY QTXDG_INCLUDE_DIR QTXDG_PRIVATE_INCLUDE_DIR)
if (CMAKE_VERSION VERSION_GREATER 2.8.12)
cmake_policy(SET CMP0024 NEW)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/qt5xdg-targets.cmake")
endif()

View File

@ -1,23 +0,0 @@
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Xml REQUIRED)
find_package(Qt5DBus REQUIRED)
if (QTXDG_QTMIMETYPES)
add_definitions("-DQT_MIMETYPES")
endif()
add_definitions(${Qt5Core_DEFINITIONS})
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}"
)
set(QTXDG_QT_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5Xml_LIBRARIES} ${Qt5DBus_LIBRARIES})
set(QTXDG_LIBRARIES ${QTXDG_LIBRARIES} ${QTXDG_QT_LIBRARIES})
set(QTXDG_INCLUDE_DIRS
"${QTXDG_INCLUDE_DIRS}"
"${Qt5Widgets_INCLUDE_DIRS}"
"${Qt5Xml_INCLUDE_DIRS}"
"${Qt5DBus_INCLUDE_DIRS}"
)
link_directories("${QTXDG_LIBRARY_DIRS}")
include_directories("${QTXDG_INCLUDE_DIRS}")

View File

@ -0,0 +1,13 @@
@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()

View File

@ -1,53 +0,0 @@
# - Find the QtXdg include and library dirs and define a some macros
#
# The module defines the following variables
# QTXDG_FOUND - Set to TRUE if all of the above has been found
#
# QTXDG_INCLUDE_DIR - The QtXdg include directory
#
# QTXDG_INCLUDE_DIRS - The QtXdg lib and it's dependencies include directories
#
# QTXDG_LIBRARY_DIRS - The QtXdg lib and it's dependencies linker search paths
#
# QTXDG_LIBRARY - The QtXdg library itself
# QTXDG_LIBRARIES - The QtXdg library and all it's dependencies
#
# QTXDG_USE_FILE - The variable QTXDG_USE_FILE is set which is the path
# to a CMake file that can be included to compile qtxdg
# applications and libraries. It sets up the compilation
# environment for include directories and populates a
# QTXDG_LIBRARIES variable.
#
# QTXDG_QT_LIBRARIES - The QtXdg Qt dependencies libraries
#
# Typical usage:
# option(USE_QT5 "Build using Qt5. Default off" OFF)
# if (USE_QT5)
# find_package(QT5XDG)
# else()
# find_package(QTXDG)
# endif()
#
# include(${QTXDG_USE_FILE})
# add_executable(use-qtxdg main.cpp)
# target_link_libraries(use-qtxdg ${QTXDG_LIBRARIES})
set(QTXDG_INCLUDE_DIR "@QTXDG_INCLUDE_DIR@")
set(QTXDG_PRIVATE_INCLUDE_DIR "@QTXDG_PRIVATE_INCLUDE_DIR@")
set(QTXDG_LIBRARY @QTXDGX_LIBRARY_NAME@)
set(QTXDG_LIBRARIES ${QTXDG_LIBRARY})
set(QTXDG_INCLUDE_DIRS "${QTXDG_INCLUDE_DIR}")
set(QTXDG_LIBRARY_DIRS "@CMAKE_INSTALL_FULL_LIBDIR@")
set(QTXDG_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/@QTXDGX_FILE_NAME@_use.cmake")
set(QTXDG_FOUND 1)
set(QTXDG_QTMIMETYPES @USE_QTMIMETYPES@)
set(QTXDG_MAJOR_VERSION @QTXDG_MAJOR_VERSION@)
set(QTXDG_MINOR_VERSION @QTXDG_MINOR_VERSION@)
set(QTXDG_PATCH_VERSION @QTXDG_PATCH_VERSION@)
set(QTXDG_VERSION @QTXDG_MAJOR_VERSION@.@QTXDG_MINOR_VERSION@.@QTXDG_PATCH_VERSION@)
mark_as_advanced(QTXDG_LIBRARY QTXDG_INCLUDE_DIR)

View File

@ -1,42 +0,0 @@
# - Find the Razor-qt include and library dirs and define a some macros
#
find_package(Qt4 REQUIRED QtCore QtGui QtXml QtDBus QUIET)
include(${QT_USE_FILE})
set(QTXDG_QT_LIBRARIES
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${QT_QTXML_LIBRARY}
${QT_DBUS_LIBRARY}
)
set(QTXDG_LIBRARIES ${QTXDG_LIBRARY} ${QTXDG_QT_LIBRARIES})
set(QTXDG_INCLUDE_DIRS
${QTXDG_INCLUDE_DIRS}
${QT_QTCORE_INCLUDE_DIR}
${QT_QTGUI_INCLUDE_DIR}
${QT_QTXML_INCLUDE_DIR}
${QT_QTDBUS_INCLUDE_DIR}
)
set(QTXDG_DEFINITIONS ${QT_DEFINITIONS})
if (QTXDG_QTMIMETYPES)
find_package(PkgConfig)
pkg_check_modules(QTMIMETYPES REQUIRED
QtMimeTypes
)
set(QTXDG_LIBRARIES ${QTXDG_LIBRARY} ${QTMIMETYPES_LIBRARIES})
set(QTXDG_LIBRARY_DIRS ${QTXDG_LIBRARY_DIRS} ${QTMIMETYPES_LIBRARY_DIRS})
set(QTXDG_DEFINITIONS ${QTXDG_DEFINITIONS} "-DQT_MIMETYPES")
include_directories(${QTXDG_INCLUDE_DIR} ${QTMIMETYPES_INCLUDE_DIRS})
link_directories(${QTXDG_LIBRARY_DIRS})
add_definitions("-DQT_MIMETYPES")
else()
include_directories(${QTXDG_INCLUDE_DIR} ${QTMIMETYPES_INCLUDE_DIRS})
link_directories(${QTXDG_LIBRARY_DIRS})
endif()

View File

@ -1,11 +0,0 @@
#include <QtCore/QByteArray>
static inline QByteArray detectDesktopEnvironment()
{
const QByteArray _desktop = qgetenv("XDG_CURRENT_DESKTOP");
if (!_desktop.isEmpty()) {
return _desktop.toUpper();
}
return QByteArray("UNKNOWN");
}

View File

@ -1,18 +1,6 @@
project(use-qtxdg)
cmake_minimum_required(VERSION 2.6)
option(USE_QT5 "Build using Qt5. Default off" OFF)
if (USE_QT5)
find_package(QT5XDG)
else()
find_package(QTXDG)
endif()
include(${QTXDG_USE_FILE})
cmake_minimum_required(VERSION 2.8.12)
find_package(QT5XDG)
add_executable(use-qtxdg main.cpp)
# The QTXDG_QT_LIBRARIES variable contains the needed Qt libraries. They are
# set taking in account the choosed Qt version.
target_link_libraries(use-qtxdg ${QTXDG_QT_LIBRARIES} ${QTXDG_LIBRARIES})
target_link_libraries(use-qtxdg Qt5Xdg)

View File

@ -1,9 +1,4 @@
An example of how to write an CMakeLists.txt to use libqtxdg in a portable
way.
An example of how to write an CMakeLists.txt to use libqtxdg.
Building with Qt4 is the default. Ex:
cmake..
To build with Qt5 just pass to set the USE_QT5 to Yes. Ex:
cmake -DUSE_QT5=On ..
To build this example just use:
cmake ..

View File

@ -1,677 +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 "qiconloader_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/QList>
#include <QtCore/QHash>
#include <QtCore/QDir>
#include <QtCore/QSettings>
#include <QtGui/QPainter>
#ifdef Q_WS_MAC
#include <private/qt_cocoa_helpers_mac_p.h>
#endif
#include <private/qhexstring_p.h>
//QT_BEGIN_NAMESPACE
namespace QtXdg {
Q_GLOBAL_STATIC(QIconLoader, 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())
return themeHint.toString();
}
return QString("hicolor");
}
QIconLoader::QIconLoader() :
m_themeKey(1), m_supportsSvg(false), m_initialized(false)
{
}
// We lazily initialize the loader to make static icons
// work. Though we do not officially support this.
static inline QString systemThemeName()
{
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconThemeName);
if (themeHint.isValid())
return themeHint.toString();
}
return QIcon::themeName();
}
static inline QStringList systemIconSearchPaths()
{
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
const QVariant themeHint = theme->themeHint(QPlatformTheme::IconThemeSearchPaths);
if (themeHint.isValid())
return themeHint.toStringList();
}
return QIcon::themeSearchPaths();
}
#ifndef QT_NO_LIBRARY
//extern QFactoryLoader *qt_iconEngineFactoryLoader(); // qicon.cpp
#endif
void QIconLoader::ensureInitialized()
{
if (!m_initialized) {
m_initialized = true;
Q_ASSERT(qApp);
m_systemTheme = systemThemeName();
if (m_systemTheme.isEmpty())
m_systemTheme = fallbackTheme();
#ifndef QT_NO_LIBRARY
// if (qt_iconEngineFactoryLoader()->keyMap().key(QLatin1String("svg"), -1) != -1)
m_supportsSvg = true;
#endif //QT_NO_LIBRARY
}
}
QIconLoader *QIconLoader::instance()
{
iconLoaderInstance()->ensureInitialized();
return iconLoaderInstance();
}
// Queries the system theme and invalidates existing
// icons if the theme has changed.
void QIconLoader::updateSystemTheme()
{
// Only change if this is not explicitly set by the user
if (m_userTheme.isEmpty()) {
QString theme = systemThemeName();
if (theme.isEmpty())
theme = fallbackTheme();
if (theme != m_systemTheme) {
m_systemTheme = theme;
invalidateKey();
}
}
}
void QIconLoader::setThemeName(const QString &themeName)
{
m_userTheme = themeName;
invalidateKey();
}
void QIconLoader::setThemeSearchPath(const QStringList &searchPaths)
{
m_iconDirs = searchPaths;
themeList.clear();
invalidateKey();
}
QStringList QIconLoader::themeSearchPaths() const
{
if (m_iconDirs.isEmpty()) {
m_iconDirs = systemIconSearchPaths();
// Always add resource directory as search path
m_iconDirs.append(QLatin1String(":/icons"));
}
return m_iconDirs;
}
QIconTheme::QIconTheme(const QString &themeName)
: m_valid(false)
{
QFile themeIndex;
QStringList iconDirs = QIcon::themeSearchPaths();
for ( int i = 0 ; i < iconDirs.size() ; ++i) {
QDir iconDir(iconDirs[i]);
QString themeDir = iconDir.path() + QLatin1Char('/') + themeName;
themeIndex.setFileName(themeDir + QLatin1String("/index.theme"));
if (themeIndex.exists()) {
m_contentDir = themeDir;
m_valid = true;
QStringList themeSearchPaths = QIcon::themeSearchPaths();
foreach (QString path, themeSearchPaths)
{
if (!path.startsWith(':') && QFileInfo(path).isDir())
m_contentDirs.append(path + QLatin1Char('/') + themeName);
}
break;
}
}
#ifndef QT_NO_SETTINGS
if (themeIndex.exists()) {
const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
QStringListIterator keyIterator(indexReader.allKeys());
while (keyIterator.hasNext()) {
const QString key = keyIterator.next();
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();
m_keyList.append(dirInfo);
}
}
}
// Parent themes provide fallbacks for missing icons
m_parents = indexReader.value(
QLatin1String("Icon Theme/Inherits")).toStringList();
m_parents.removeAll(QString());
// Ensure a default platform fallback for all themes
if (m_parents.isEmpty()) {
const QString fallback = fallbackTheme();
if (!fallback.isEmpty())
m_parents.append(fallback);
}
// Ensure that all themes fall back to hicolor
if (!m_parents.contains(QLatin1String("hicolor")))
m_parents.append(QLatin1String("hicolor"));
}
#endif //QT_NO_SETTINGS
}
QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited) const
{
QThemeIconEntries entries;
Q_ASSERT(!themeName.isEmpty());
QPixmap pixmap;
// Used to protect against potential recursions
visited << themeName;
QIconTheme theme = themeList.value(themeName);
if (!theme.isValid()) {
theme = QIconTheme(themeName);
if (!theme.isValid())
theme = QIconTheme(fallbackTheme());
themeList.insert(themeName, theme);
}
QStringList contentDirs = theme.contentDirs();
const QVector<QIconDirInfo> subDirs = theme.keyList();
const QString svgext(QLatin1String(".svg"));
const QString pngext(QLatin1String(".png"));
const QString xpmext(QLatin1String(".xpm"));
// Add all relevant files
for (int i = 0; i < subDirs.size() ; ++i) {
const QIconDirInfo &dirInfo = subDirs.at(i);
QString subdir = dirInfo.path;
foreach (QString contentDir, contentDirs) {
QDir currentDir(contentDir + '/' + subdir);
if (currentDir.exists(iconName + pngext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + pngext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.prepend(iconEntry);
} else if (m_supportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + svgext);
entries.append(iconEntry);
break;
} else if (currentDir.exists(iconName + xpmext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + xpmext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.append(iconEntry);
break;
}
}
}
if (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
entries = findIconHelper(parentTheme, iconName, visited);
if (!entries.isEmpty()) // success
break;
}
}
/*********************************************************************
Author: Kaitlin Rupert <kaitlin.rupert@intel.com>
Date: Aug 12, 2010
Description: Make it so that the QIcon loader honors /usr/share/pixmaps
directory. This is a valid directory per the Freedesktop.org
icon theme specification.
Bug: https://bugreports.qt.nokia.com/browse/QTBUG-12874
*********************************************************************/
#ifdef Q_OS_LINUX
/* Freedesktop standard says to look in /usr/share/pixmaps last */
if (entries.isEmpty()) {
const QString pixmaps(QLatin1String("/usr/share/pixmaps"));
QDir currentDir(pixmaps);
QIconDirInfo dirInfo(pixmaps);
if (currentDir.exists(iconName + pngext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + pngext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.prepend(iconEntry);
} else if (m_supportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + svgext);
entries.append(iconEntry);
} else if (currentDir.exists(iconName + xpmext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + xpmext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.append(iconEntry);
}
}
#endif
if (entries.isEmpty()) {
// Search for unthemed icons in main dir of search paths
QStringList themeSearchPaths = QIcon::themeSearchPaths();
foreach (QString contentDir, themeSearchPaths) {
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
entries.prepend(iconEntry);
} else if (m_supportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->filename = currentDir.filePath(iconName + svgext);
entries.append(iconEntry);
break;
} 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
entries.append(iconEntry);
break;
}
}
}
return entries;
}
QThemeIconEntries QIconLoader::loadIcon(const QString &name) const
{
if (!themeName().isEmpty()) {
QStringList visited;
return findIconHelper(themeName(), name, visited);
}
return QThemeIconEntries();
}
// -------- Icon Loader Engine -------- //
QIconLoaderEngineFixed::QIconLoaderEngineFixed(const QString& iconName)
: m_iconName(iconName), m_key(0)
{
}
QIconLoaderEngineFixed::~QIconLoaderEngineFixed()
{
qDeleteAll(m_entries);
}
QIconLoaderEngineFixed::QIconLoaderEngineFixed(const QIconLoaderEngineFixed &other)
: QIconEngine(other),
m_iconName(other.m_iconName),
m_key(0)
{
}
QIconEngine *QIconLoaderEngineFixed::clone() const
{
return new QIconLoaderEngineFixed(*this);
}
bool QIconLoaderEngineFixed::read(QDataStream &in) {
in >> m_iconName;
return true;
}
bool QIconLoaderEngineFixed::write(QDataStream &out) const
{
out << m_iconName;
return true;
}
bool QIconLoaderEngineFixed::hasIcon() const
{
return !(m_entries.isEmpty());
}
// Lazily load the icon
void QIconLoaderEngineFixed::ensureLoaded()
{
if (!(QIconLoader::instance()->themeKey() == m_key)) {
qDeleteAll(m_entries);
m_entries = QIconLoader::instance()->loadIcon(m_iconName);
m_key = QIconLoader::instance()->themeKey();
}
}
void QIconLoaderEngineFixed::paint(QPainter *painter, const QRect &rect,
QIcon::Mode mode, QIcon::State state)
{
QSize pixmapSize = rect.size();
#if defined(Q_WS_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)
{
if (dir.type == QIconDirInfo::Fixed) {
return dir.size == iconsize;
} else if (dir.type == QIconDirInfo::Scalable) {
return dir.size <= 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)
{
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;
}
Q_ASSERT(1); // Not a valid value
return INT_MAX;
}
QIconLoaderEngineEntry *QIconLoaderEngineFixed::entryForSize(const QSize &size)
{
int iconsize = qMin(size.width(), size.height());
// Note that m_entries are sorted so that png-files
// come first
const int numEntries = m_entries.size();
// Search for exact matches first
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize)) {
return entry;
}
}
// Find the minimum distance icon
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize);
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 QIconLoaderEngineFixed::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)
return size;
else {
int result = qMin<int>(dir.size, qMin(size.width(), size.height()));
return QSize(result, result);
}
}
return QIconEngine::actualSize(size, mode, state);
}
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 (!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;
}
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);
}
QPixmap QIconLoaderEngineFixed::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 QIconLoaderEngineFixed::key() const
{
return QLatin1String("QIconLoaderEngineFixed");
}
void QIconLoaderEngineFixed::virtual_hook(int id, void *data)
{
ensureLoaded();
switch (id) {
case QIconEngine::AvailableSizesHook:
{
QIconEngine::AvailableSizesArgument &arg
= *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data);
const int N = m_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_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_iconName;
}
break;
default:
QIconEngine::virtual_hook(id, data);
}
}
} // QtXdg
//QT_END_NAMESPACE
#endif //QT_NO_ICON

View File

@ -1,199 +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 QICONLOADER_P_H
#define QICONLOADER_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 <QtGui/QIcon>
#include <QtGui/QIconEngine>
#include <QtGui/QPixmapCache>
#include <private/qicon_p.h>
#include <private/qfactoryloader_p.h>
#include <QtCore/QHash>
#include <QtCore/QVector>
#include <QtCore/QTypeInfo>
//QT_BEGIN_NAMESPACE
namespace QtXdg {
class QIconLoader;
struct QIconDirInfo
{
enum Type { Fixed, Scalable, Threshold };
QIconDirInfo(const QString &_path = QString()) :
path(_path),
size(0),
maxSize(0),
minSize(0),
threshold(0),
type(Threshold) {}
QString path;
short size;
short maxSize;
short minSize;
short threshold;
Type type : 4;
};
class QIconLoaderEngineEntry
{
public:
virtual ~QIconLoaderEngineEntry() {}
virtual QPixmap pixmap(const QSize &size,
QIcon::Mode mode,
QIcon::State state) = 0;
QString filename;
QIconDirInfo dir;
static int count;
};
struct ScalableEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIcon svgIcon;
};
struct PixmapEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QPixmap basePixmap;
};
typedef QList<QIconLoaderEngineEntry*> QThemeIconEntries;
//class QIconLoaderEngine : public QIconEngine
class QIconLoaderEngineFixed : public QIconEngine
{
public:
QIconLoaderEngineFixed(const QString& iconName = QString());
~QIconLoaderEngineFixed();
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
QIconEngine *clone() const;
bool read(QDataStream &in);
bool write(QDataStream &out) const;
private:
QString key() const;
bool hasIcon() const;
void ensureLoaded();
void virtual_hook(int id, void *data);
QIconLoaderEngineEntry *entryForSize(const QSize &size);
QIconLoaderEngineFixed(const QIconLoaderEngineFixed &other);
QThemeIconEntries m_entries;
QString m_iconName;
uint m_key;
friend class QIconLoader;
};
class QIconTheme
{
public:
QIconTheme(const QString &name);
QIconTheme() : m_valid(false) {}
QStringList parents() { return m_parents; }
QVector <QIconDirInfo> keyList() { return m_keyList; }
QString contentDir() { return m_contentDir; }
QStringList contentDirs() { return m_contentDirs; }
bool isValid() { return m_valid; }
private:
QString m_contentDir;
QStringList m_contentDirs;
QVector <QIconDirInfo> m_keyList;
QStringList m_parents;
bool m_valid;
};
class Q_GUI_EXPORT QIconLoader
{
public:
QIconLoader();
QThemeIconEntries loadIcon(const QString &iconName) const;
uint themeKey() const { return m_themeKey; }
QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; }
void setThemeName(const QString &themeName);
QIconTheme theme() { return themeList.value(themeName()); }
void setThemeSearchPath(const QStringList &searchPaths);
QStringList themeSearchPaths() const;
QIconDirInfo dirInfo(int dirindex);
static QIconLoader *instance();
void updateSystemTheme();
void invalidateKey() { m_themeKey++; }
void ensureInitialized();
private:
QThemeIconEntries findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited) const;
uint m_themeKey;
bool m_supportsSvg;
bool m_initialized;
mutable QString m_userTheme;
mutable QString m_systemTheme;
mutable QStringList m_iconDirs;
mutable QHash <QString, QIconTheme> themeList;
};
} // QtXdg
// Note: class template specialization of 'QTypeInfo' must occur at
// global scope
Q_DECLARE_TYPEINFO(QtXdg::QIconDirInfo, Q_MOVABLE_TYPE);
//QT_END_NAMESPACE
#endif // QT_NO_ICON
#endif // QICONLOADER_P_H

View File

@ -1,216 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//END_COMMON_COPYRIGHT_HEADER
/*************************************************************************
It's fixes the following bugs:
* QIcon::fromTheme returns pixmaps that are bigger than requested
https://bugreports.qt.nokia.com/browse/QTBUG-17953
* Qt should honor /usr/share/pixmaps as a valid icon directory on Linux
https://bugreports.qt.nokia.com/browse/QTBUG-12874
*************************************************************************/
#ifndef QDESKTOPICON_P_H
#define QDESKTOPICON_P_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 <QtGui/QIcon>
#include <QtGui/QIconEngine>
#include <QtGui/QPixmapCache>
//#include "qt/qicon_p.h"
//#include "qt/qfactoryloader_p.h"
#include <QHash>
namespace QtXdg {
class QIconLoader;
struct QIconDirInfo
{
enum Type { Fixed, Scalable, Threshold };
QIconDirInfo(const QString &_path = QString()) :
path(_path),
size(0),
maxSize(0),
minSize(0),
threshold(0),
type(Threshold) {}
QString path;
short size;
short maxSize;
short minSize;
short threshold;
Type type : 4;
};
class QIconLoaderEngineEntry
{
public:
virtual ~QIconLoaderEngineEntry() {}
virtual QPixmap pixmap(const QSize &size,
QIcon::Mode mode,
QIcon::State state) = 0;
QString filename;
QIconDirInfo dir;
static int count;
};
struct ScalableEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QIcon svgIcon;
};
struct PixmapEntry : public QIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QPixmap basePixmap;
};
typedef QList<QIconLoaderEngineEntry*> QThemeIconEntries;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
class QIconLoaderEngineFixed : public QIconEngineV2
#else
class QIconLoaderEngineFixed : public QIconEngine
#endif
{
public:
QIconLoaderEngineFixed(const QString& iconName = QString());
~QIconLoaderEngineFixed();
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QIconEngineV2 *clone() const;
#else
QIconEngine *clone() const;
#endif
bool read(QDataStream &in);
bool write(QDataStream &out) const;
private:
QString key() const;
bool hasIcon() const;
void ensureLoaded();
void virtual_hook(int id, void *data);
QIconLoaderEngineEntry *entryForSize(const QSize &size);
QIconLoaderEngineFixed(const QIconLoaderEngineFixed &other);
QThemeIconEntries m_entries;
QString m_iconName;
uint m_key;
friend class QIconLoader;
};
class QIconTheme
{
public:
QIconTheme(const QString &name);
QIconTheme() : m_valid(false) {}
QStringList parents() { return m_parents; }
QList <QIconDirInfo> keyList() { return m_keyList; }
QString contentDir() { return m_contentDir; }
QStringList contentDirs() { return m_contentDirs; }
bool isValid() { return m_valid; }
private:
QString m_contentDir;
QStringList m_contentDirs;
QList <QIconDirInfo> m_keyList;
QStringList m_parents;
bool m_valid;
};
class QIconLoader : public QObject
{
public:
QIconLoader();
QThemeIconEntries loadIcon(const QString &iconName) const;
uint themeKey() const { return m_themeKey; }
QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; }
void setThemeName(const QString &themeName);
QIconTheme theme() { return themeList.value(themeName()); }
void setThemeSearchPath(const QStringList &searchPaths);
QStringList themeSearchPaths() const;
QIconDirInfo dirInfo(int dirindex);
static QIconLoader *instance();
void updateSystemTheme();
void invalidateKey() { m_themeKey++; }
void ensureInitialized();
private:
QThemeIconEntries findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited) const;
uint m_themeKey;
bool m_supportsSvg;
bool m_initialized;
mutable QString m_userTheme;
mutable QString m_systemTheme;
mutable QStringList m_iconDirs;
mutable QHash <QString, QIconTheme> themeList;
};
} // QtXdg
#endif // QDESKTOPICON_P_H
#endif //QT_NO_ICON

View File

@ -1,737 +0,0 @@
/* BEGIN_COMMON_COPYRIGHT_HEADER
* (c)LGPL2
*/
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
//END_COMMON_COPYRIGHT_HEADER
#ifndef QT_NO_ICON
#include "qiconloader_p_qt4.h"
//#include "qt/qapplication_p.h"
//#include <qt/qicon_p.h>
//#include <qt/qguiplatformplugin_p.h>
#include <QtGui/QIconEnginePlugin>
#include <QtGui/QPixmapCache>
#include <QtGui/QIconEngine>
#include <QStyleOption>
#include <QList>
#include <QHash>
#include <QDir>
#include <QSettings>
#include <QtGui/QPainter>
#include <QApplication>
#include <QLatin1Literal>
//#ifdef Q_WS_MAC
//#include <private/qt_cocoa_helpers_mac_p.h>
//#endif
//#ifdef Q_WS_X11
//#include "qt/qt_x11_p.h"
//#endif
#include <QDebug>
#if QT_VERSION < 0x040700
#include <limits.h>
#endif
namespace QtXdg {
Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance)
/* Theme to use in last resort, if the theme does not have the icon, neither the parents */
/*static QString fallbackTheme()
{
#ifdef Q_WS_X11
if (X11->desktopEnvironment == DE_GNOME) {
return QLatin1String("gnome");
} else if (X11->desktopEnvironment == DE_KDE) {
return X11->desktopVersion >= 4
? QString::fromLatin1("oxygen")
: QString::fromLatin1("crystalsvg");
} else {
return QLatin1String("hicolor");
}
#endif
return QString();
}
*/
QIconLoader::QIconLoader() :
m_themeKey(1), m_supportsSvg(false), m_initialized(false)
{
}
// We lazily initialize the loader to make static icons
// work. Though we do not officially support this.
void QIconLoader::ensureInitialized()
{
if (!m_initialized) {
m_initialized = true;
Q_ASSERT(qApp);
m_systemTheme = QIcon::themeName();
#ifndef QT_NO_LIBRARY
// QFactoryLoader iconFactoryLoader(QIconEngineFactoryInterfaceV2_iid,
// QLatin1String("/iconengines"),
// Qt::CaseInsensitive);
// if (iconFactoryLoader.keys().contains(QLatin1String("svg")))
m_supportsSvg = true;
#endif //QT_NO_LIBRARY
}
}
QIconLoader *QIconLoader::instance()
{
return iconLoaderInstance();
}
// Queries the system theme and invalidates existing
// icons if the theme has changed.
void QIconLoader::updateSystemTheme()
{
// Only change if this is not explicitly set by the user
if (m_userTheme.isEmpty()) {
QString theme = QIcon::themeName();//qt_guiPlatformPlugin()->systemIconThemeName();
//if (theme.isEmpty())
// theme = fallbackTheme();
if (theme != m_systemTheme) {
m_systemTheme = theme;
invalidateKey();
}
}
}
void QIconLoader::setThemeName(const QString &themeName)
{
m_userTheme = themeName;
invalidateKey();
}
void QIconLoader::setThemeSearchPath(const QStringList &searchPaths)
{
m_iconDirs = searchPaths;
themeList.clear();
invalidateKey();
}
QStringList QIconLoader::themeSearchPaths() const
{
if (m_iconDirs.isEmpty())
{
m_iconDirs = QIcon::themeSearchPaths();//qt_guiPlatformPlugin()->iconThemeSearchPaths();
// Always add resource directory as search path
m_iconDirs.append(QLatin1String(":/icons"));
}
return m_iconDirs;
}
QIconTheme::QIconTheme(const QString &themeName)
: m_valid(false)
{
QFile themeIndex;
QList <QIconDirInfo> keyList;
QStringList iconDirs = QIcon::themeSearchPaths();
for ( int i = 0 ; i < iconDirs.size() ; ++i) {
QDir iconDir(iconDirs[i]);
QString themeDir = iconDir.path() + QLatin1Char('/') + themeName;
themeIndex.setFileName(themeDir + QLatin1String("/index.theme"));
if (themeIndex.exists()) {
m_contentDir = themeDir;
m_valid = true;
QStringList themeSearchPaths = QIcon::themeSearchPaths();
foreach (QString path, themeSearchPaths)
{
if (!path.startsWith(':') && QFileInfo(path).isDir())
m_contentDirs.append(path + QLatin1Char('/') + themeName);
}
break;
}
}
#ifndef QT_NO_SETTINGS
if (themeIndex.exists()) {
const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
QStringListIterator keyIterator(indexReader.allKeys());
while (keyIterator.hasNext()) {
const QString key = keyIterator.next();
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();
m_keyList.append(dirInfo);
}
}
}
// Parent themes provide fallbacks for missing icons
m_parents = indexReader.value(
QLatin1String("Icon Theme/Inherits")).toStringList();
// Ensure a default platform fallback for all themes
if (m_parents.isEmpty())
m_parents.append(QIcon::themeName());//fallbackTheme());
// Ensure that all themes fall back to hicolor
if (!m_parents.contains(QLatin1String("hicolor")))
m_parents.append(QLatin1String("hicolor"));
}
#endif //QT_NO_SETTINGS
}
QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName,
const QString &iconName,
QStringList &visited) const
{
QThemeIconEntries entries;
Q_ASSERT(!themeName.isEmpty());
QPixmap pixmap;
// Used to protect against potential recursions
visited << themeName;
QIconTheme theme = themeList.value(themeName);
if (!theme.isValid()) {
theme = QIconTheme(themeName);
if (!theme.isValid())
theme = QIconTheme(QIcon::themeName());//fallbackTheme());
themeList.insert(themeName, theme);
}
QStringList contentDirs = theme.contentDirs();
QList<QIconDirInfo> subDirs = theme.keyList();
const QString svgext(QLatin1String(".svg"));
const QString pngext(QLatin1String(".png"));
const QString xpmext(QLatin1String(".xpm"));
// Add all relevant files
for (int i = 0; i < subDirs.size() ; ++i)
{
const QIconDirInfo &dirInfo = subDirs.at(i);
QString subdir = dirInfo.path;
foreach (QString contentDir, contentDirs)
{
QDir currentDir(contentDir + '/' + subdir);
if (currentDir.exists(iconName + pngext))
{
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + pngext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.prepend(iconEntry);
break;
}
else if (m_supportsSvg &&
currentDir.exists(iconName + svgext))
{
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + svgext);
entries.append(iconEntry);
break;
}
else if (currentDir.exists(iconName + xpmext))
{
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + xpmext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.append(iconEntry);
break;
}
}
}
if (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
entries = findIconHelper(parentTheme, iconName, visited);
if (!entries.isEmpty()) // success
break;
}
}
/*********************************************************************
Author: Kaitlin Rupert <kaitlin.rupert@intel.com>
Date: Aug 12, 2010
Description: Make it so that the QIcon loader honors /usr/share/pixmaps
directory. This is a valid directory per the Freedesktop.org
icon theme specification.
Bug: https://bugreports.qt.nokia.com/browse/QTBUG-12874
*********************************************************************/
#ifdef Q_OS_LINUX
/* Freedesktop standard says to look in /usr/share/pixmaps last */
if (entries.isEmpty()) {
const QString pixmaps(QLatin1String("/usr/share/pixmaps"));
QDir currentDir(pixmaps);
QIconDirInfo dirInfo(pixmaps);
if (currentDir.exists(iconName + pngext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + pngext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.prepend(iconEntry);
} else if (m_supportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + svgext);
entries.append(iconEntry);
} else if (currentDir.exists(iconName + xpmext)) {
PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + xpmext);
// Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards
entries.append(iconEntry);
}
}
#endif
if (entries.isEmpty()) {
// Search for unthemed icons in main dir of search paths
QStringList themeSearchPaths = QIcon::themeSearchPaths();
foreach (QString contentDir, themeSearchPaths) {
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
entries.prepend(iconEntry);
} else if (m_supportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->filename = currentDir.filePath(iconName + svgext);
entries.append(iconEntry);
break;
} 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
entries.append(iconEntry);
break;
}
}
}
return entries;
}
QThemeIconEntries QIconLoader::loadIcon(const QString &name) const
{
if (!themeName().isEmpty()) {
QStringList visited;
return findIconHelper(themeName(), name, visited);
}
return QThemeIconEntries();
}
// -------- Icon Loader Engine -------- //
QIconLoaderEngineFixed::QIconLoaderEngineFixed(const QString& iconName)
: m_iconName(iconName), m_key(0)
{
}
QIconLoaderEngineFixed::~QIconLoaderEngineFixed()
{
while (!m_entries.isEmpty())
delete m_entries.takeLast();
Q_ASSERT(m_entries.size() == 0);
}
QIconLoaderEngineFixed::QIconLoaderEngineFixed(const QIconLoaderEngineFixed &other)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
: QIconEngineV2(other),
#else
: QIconEngine(other),
#endif
m_iconName(other.m_iconName),
m_key(0)
{
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QIconEngineV2 *QIconLoaderEngineFixed::clone() const
#else
QIconEngine *QIconLoaderEngineFixed::clone() const
#endif
{
return new QIconLoaderEngineFixed(*this);
}
bool QIconLoaderEngineFixed::read(QDataStream &in) {
in >> m_iconName;
return true;
}
bool QIconLoaderEngineFixed::write(QDataStream &out) const
{
out << m_iconName;
return true;
}
bool QIconLoaderEngineFixed::hasIcon() const
{
return !(m_entries.isEmpty());
}
// Lazily load the icon
void QIconLoaderEngineFixed::ensureLoaded()
{
iconLoaderInstance()->ensureInitialized();
if (!(iconLoaderInstance()->themeKey() == m_key)) {
while (!m_entries.isEmpty())
delete m_entries.takeLast();
Q_ASSERT(m_entries.size() == 0);
m_entries = iconLoaderInstance()->loadIcon(m_iconName);
m_key = iconLoaderInstance()->themeKey();
}
}
void QIconLoaderEngineFixed::paint(QPainter *painter, const QRect &rect,
QIcon::Mode mode, QIcon::State state)
{
QSize pixmapSize = rect.size();
#if defined(Q_WS_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)
{
if (dir.type == QIconDirInfo::Fixed) {
return dir.size == iconsize;
} else if (dir.type == QIconDirInfo::Scalable) {
return dir.size <= 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)
{
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;
}
Q_ASSERT(1); // Not a valid value
return INT_MAX;
}
QIconLoaderEngineEntry *QIconLoaderEngineFixed::entryForSize(const QSize &size)
{
int iconsize = qMin(size.width(), size.height());
// Note that m_entries are sorted so that png-files
// come first
// Search for exact matches first
for (int i = 0; i < m_entries.count(); ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize)) {
return entry;
}
}
// Find the minimum distance icon
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < m_entries.count(); ++i) {
QIconLoaderEngineEntry *entry = m_entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize);
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 QIconLoaderEngineFixed::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)
{
return size;
}
else {
if (dir.size == 0)
{
entry->dir.size = QPixmap(entry->filename).size().width();
entry->dir.minSize = dir.size;
entry->dir.maxSize = dir.size;
}
int result = qMin<int>(dir.size, qMin(size.width(), size.height()));
return QSize(result, result);
}
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
return QIconEngineV2::actualSize(size, mode, state);
#else
return QIconEngine::actualSize(size, mode, state);
#endif
}
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 (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio);
QString key = QString("$qt_theme_%1%2%3%4%5")
.arg(basePixmap.cacheKey(), 16, 16, QChar('0'))
.arg(mode, 8, 16, QChar('0'))
.arg(qApp->palette().cacheKey(),16, 16, QChar('0'))
.arg(actualSize.width(), 8, 16, QChar('0'))
.arg(actualSize.height(), 8, 16, QChar('0'));
QPixmap cachedPixmap;
if (QPixmapCache::find(key, &cachedPixmap)) {
return cachedPixmap;
} else {
if (basePixmap.size() != actualSize)
basePixmap = basePixmap.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
QStyleOption opt(0);
opt.palette = qApp->palette();
cachedPixmap = qApp->style()->generatedIconPixmap(mode, basePixmap, &opt);
QPixmapCache::insert(key, cachedPixmap);
}
return cachedPixmap;
}
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);
}
QPixmap QIconLoaderEngineFixed::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 QIconLoaderEngineFixed::key() const
{
return QLatin1String("QIconLoaderEngineFixed");
}
void QIconLoaderEngineFixed::virtual_hook(int id, void *data)
{
ensureLoaded();
switch (id) {
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
case QIconEngineV2::AvailableSizesHook:
#else
case QIconEngine::AvailableSizesHook:
#endif
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QIconEngineV2::AvailableSizesArgument &arg
= *reinterpret_cast<QIconEngineV2::AvailableSizesArgument*>(data);
#else
QIconEngine::AvailableSizesArgument &arg
= *reinterpret_cast<QIconEngine::AvailableSizesArgument*>(data);
#endif
const QList<QIconDirInfo> directoryKey = iconLoaderInstance()->theme().keyList();
arg.sizes.clear();
// Gets all sizes from the DirectoryInfo entries
for (int i = 0 ; i < m_entries.size() ; ++i) {
int size = m_entries.at(i)->dir.size;
arg.sizes.append(QSize(size, size));
}
}
break;
#if (QT_VERSION >= 0x040700) && (QT_VERSION < 0x050000)
case QIconEngineV2::IconNameHook:
{
QString &name = *reinterpret_cast<QString*>(data);
name = m_iconName;
}
break;
#elif QT_VERSION > QT_VERSION_CHECK(5,0,0)
case QIconEngine::IconNameHook:
{
QString &name = *reinterpret_cast<QString*>(data);
name = m_iconName;
}
break;
#else// QT_VERSION > QT_VERSION_CHECK(5,0,0)
#warning QIconEngineV2::IconNameHook is ignored due Qt version. Upgrade to 4.7.x
#endif
default:
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QIconEngineV2::virtual_hook(id, data);
#else
QIconEngine::virtual_hook(id, data);
#endif
}
}
} // QtXdg
#endif //QT_NO_ICON

138
qtxdg/CMakeLists.txt Normal file
View File

@ -0,0 +1,138 @@
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
)

View File

@ -0,0 +1,37 @@
/* 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");
}

View File

@ -25,25 +25,18 @@
*
* 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)
{
@ -51,9 +44,6 @@ XdgAction::XdgAction(const XdgDesktopFile& desktopFile, QObject *parent):
}
/************************************************
************************************************/
XdgAction::XdgAction(const XdgDesktopFile* desktopFile, QObject *parent):
QAction(parent)
{
@ -61,9 +51,6 @@ XdgAction::XdgAction(const XdgDesktopFile* desktopFile, QObject *parent):
}
/************************************************
************************************************/
XdgAction::XdgAction(const QString& desktopFileName, QObject *parent):
QAction(parent)
{
@ -73,9 +60,6 @@ XdgAction::XdgAction(const QString& desktopFileName, QObject *parent):
}
/************************************************
************************************************/
XdgAction::XdgAction(const XdgAction& other, QObject *parent):
QAction(parent)
{
@ -83,17 +67,11 @@ XdgAction::XdgAction(const XdgAction& other, QObject *parent):
}
/************************************************
************************************************/
XdgAction::~XdgAction()
{
}
/************************************************
************************************************/
XdgAction& XdgAction::operator=(const XdgAction& other)
{
load(other.mDesktopFile);
@ -101,25 +79,19 @@ XdgAction& XdgAction::operator=(const XdgAction& other)
}
/************************************************
************************************************/
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('&', QLatin1String("&&")));
setText(mDesktopFile.name().replace(QLatin1Char('&'), QLatin1String("&&")));
setToolTip(mDesktopFile.comment());
connect(this, SIGNAL(triggered()), this, SLOT(runConmmand()));
@ -134,9 +106,6 @@ void XdgAction::load(const XdgDesktopFile& desktopFile)
}
/************************************************
************************************************/
void XdgAction::runConmmand() const
{
if (mDesktopFile.isValid())
@ -144,13 +113,10 @@ void XdgAction::runConmmand() const
}
/************************************************
************************************************/
void XdgAction::updateIcon()
{
setIcon(mDesktopFile.icon());
if (icon().isNull())
setIcon(XdgIcon::fromTheme("application-x-executable"));
setIcon(XdgIcon::fromTheme(QLatin1String("application-x-executable")));
QCoreApplication::processEvents();
}

View File

@ -25,8 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGACTION_H
#define QTXDG_XDGACTION_H
@ -73,7 +71,7 @@ public:
const XdgDesktopFile& desktopFile() const { return mDesktopFile; }
private slots:
private Q_SLOTS:
void runConmmand() const;
void updateIcon();

View File

@ -25,23 +25,24 @@
*
* 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.
************************************************/
/**
* 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;
@ -56,14 +57,14 @@ XdgDesktopFileList XdgAutoStart::desktopFileList(QStringList dirs, bool excludeH
QSet<QString> processed;
XdgDesktopFileList ret;
foreach (QString dirName, dirs)
for (const QString &dirName : const_cast<const QStringList&>(dirs))
{
QDir dir(dirName);
if (!dir.exists())
continue;
QFileInfoList files = dir.entryInfoList(QStringList("*.desktop"), QDir::Files | QDir::Readable);
foreach (QFileInfo fi, files)
const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files | QDir::Readable);
for (const QFileInfo &fi : files)
{
if (processed.contains(fi.fileName()))
continue;
@ -87,5 +88,5 @@ XdgDesktopFileList XdgAutoStart::desktopFileList(QStringList dirs, bool excludeH
QString XdgAutoStart::localPath(const XdgDesktopFile& file)
{
QFileInfo fi(file.fileName());
return QString("%1/%2").arg(XdgDirs::autostartHome(), fi.fileName());
return QString::fromLatin1("%1/%2").arg(XdgDirs::autostartHome(), fi.fileName());
}

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGAUTOSTART_H
#define QTXDG_XDGAUTOSTART_H

File diff suppressed because it is too large Load Diff

View File

@ -25,15 +25,12 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGDESKTOPFILE_H
#define QTXDG_XDGDESKTOPFILE_H
#include "xdgmacros.h"
#include <QSharedDataPointer>
//#include <QObject>
#include <QString>
#include <QVariant>
#include <QStringList>
@ -82,7 +79,7 @@ public:
- 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 = 0);
XdgDesktopFile(XdgDesktopFile::Type type, const QString& name, const QString& value = QString());
//! Destroys the object.
virtual ~XdgDesktopFile();
@ -93,6 +90,12 @@ public:
//! 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);
@ -143,11 +146,18 @@ public:
//! Returns an icon name specified in this file.
QString const iconName() 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("Name").toString(); }
QString name() const { return localizedValue(QLatin1String("Name")).toString(); }
//! This function is provided for convenience. It's equivalent to calling localizedValue("Comment").toString().
QString comment() const { return localizedValue("Comment").toString(); }
QString comment() const { return localizedValue(QLatin1String("Comment")).toString(); }
/*! Returns the desktop file type.
@see XdgDesktopFile::Type */
@ -174,9 +184,16 @@ public:
/*! Returns the URL for the Link desktop file; otherwise an empty string is returned. */
QString url() const;
/*! The desktop entry specification defines a number of fields to control the visibility of the application menu. This function
checks whether to display a this application or not. */
QTXDG_DEPRECATED bool isShow(const QString& environment = "Razor") 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
@ -189,12 +206,6 @@ public:
*/
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 */
QTXDG_DEPRECATED bool isApplicable(bool excludeHidden = true, const QString& environment = "Razor") const;
/*! This fuction returns true if the desktop file is applicable to the
current environment.
@par excludeHidden - if set to true (default), files with
@ -210,7 +221,7 @@ public:
bool isSuitable(bool excludeHidden = true, const QString &environment = QString()) const;
protected:
virtual QString prefix() const { return "Desktop Entry"; }
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.
@ -258,5 +269,3 @@ private:
#endif // QTXDG_XDGDESKTOPFILE_H

34
qtxdg/xdgdesktopfile_p.h Normal file
View File

@ -0,0 +1,34 @@
/* 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

View File

@ -25,26 +25,23 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgdirs.h"
#include <stdlib.h>
#include <QDir>
#include <QStringBuilder> // for the % operator
#include <QDebug>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QStandardPaths>
#endif
static const QString userDirectoryString[8] =
{
"Desktop",
"Download",
"Templates",
"Publicshare",
"Documents",
"Music",
"Pictures",
"Videos"
QLatin1String("Desktop"),
QLatin1String("Download"),
QLatin1String("Templates"),
QLatin1String("Publicshare"),
QLatin1String("Documents"),
QLatin1String("Music"),
QLatin1String("Pictures"),
QLatin1String("Videos")
};
// Helper functions prototypes
@ -52,14 +49,8 @@ void fixBashShortcuts(QString &s);
void removeEndingSlash(QString &s);
QString createDirectory(const QString &dir);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
void cleanAndAddPostfix(QStringList &dirs, const QString& postfix);
#endif
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QString xdgSingleDir(const QString &envVar, const QString &def, bool createDir);
QStringList xdgDirList(const QString &envVar, const QString &postfix);
#endif
QString userDirFallback(XdgDirs::UserDirectory dir);
/************************************************
Helper func.
@ -67,9 +58,10 @@ QStringList xdgDirList(const QString &envVar, const QString &postfix);
void fixBashShortcuts(QString &s)
{
if (s.startsWith(QLatin1Char('~')))
s = QString(getenv("HOME")) + (s).mid(1);
s = QFile::decodeName(qgetenv("HOME")) + (s).mid(1);
}
void removeEndingSlash(QString &s)
{
// We don't check for empty strings. Caller must check it.
@ -79,14 +71,15 @@ void removeEndingSlash(QString &s)
s.chop(1);
}
QString createDirectory(const QString &dir)
{
QDir d(dir);
if (!d.exists())
{
if (!d.mkpath("."))
if (!d.mkpath(QLatin1String(".")))
{
qWarning() << QString("Can't create %1 directory.").arg(d.absolutePath());
qWarning() << QString::fromLatin1("Can't create %1 directory.").arg(d.absolutePath());
}
}
QString r = d.absolutePath();
@ -94,6 +87,7 @@ QString createDirectory(const QString &dir)
return r;
}
void cleanAndAddPostfix(QStringList &dirs, const QString& postfix)
{
const int N = dirs.count();
@ -105,78 +99,54 @@ void cleanAndAddPostfix(QStringList &dirs, const QString& postfix)
}
}
/************************************************
Helper func.
************************************************/
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QString xdgSingleDir(const QString &envVar, const QString &def, bool createDir)
{
QString s(getenv(envVar.toAscii()));
if (!s.isEmpty())
fixBashShortcuts(s);
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
s = QString("%1/%2").arg(getenv("HOME"), def);
fallback = home;
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
return fallback;
}
#endif
/************************************************
Helper func.
************************************************/
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QStringList xdgDirList(const QString &envVar, const QString &postfix)
QString XdgDirs::userDirDefault(XdgDirs::UserDirectory dir)
{
QStringList dirs = QString(getenv(envVar.toAscii())).split(':', QString::SkipEmptyParts);
// possible values for UserDirectory
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return QString();
QMutableStringListIterator i(dirs);
while(i.hasNext()) {
i.next();
QString s = i.value();
if (s.isEmpty()) {
i.remove();
} else {
fixBashShortcuts(s);
removeEndingSlash(s);
i.setValue(s % postfix);
}
}
return dirs;
return userDirFallback(dir);
}
#endif
/************************************************
************************************************/
QString XdgDirs::userDir(XdgDirs::UserDirectory dir)
{
// possible values for UserDirectory
if (dir < 0 || dir > 7)
Q_ASSERT(!(dir < XdgDirs::Desktop || dir > XdgDirs::Videos));
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return QString();
QString folderName = userDirectoryString[dir];
QString fallback;
if (getenv("HOME") == NULL)
return QString("/tmp");
else if (dir == XdgDirs::Desktop)
fallback = QString("%1/%2").arg(getenv("HOME")).arg("Desktop");
else
fallback = QString(getenv("HOME"));
const QString fallback = userDirFallback(dir);
QString configDir(configHome());
QFile configFile(configDir + "/user-dirs.dirs");
QFile configFile(configDir + QLatin1String("/user-dirs.dirs"));
if (!configFile.exists())
return fallback;
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text))
return fallback;
QString userDirVar("XDG_" + folderName.toUpper() + "_DIR");
QString userDirVar(QLatin1String("XDG_") + folderName.toUpper() + QLatin1String("_DIR"));
QTextStream in(&configFile);
QString line;
while (!in.atEnd())
@ -188,6 +158,8 @@ QString XdgDirs::userDir(XdgDirs::UserDirectory dir)
// get path between quotes
line = line.section(QLatin1Char('"'), 1, 1);
if (line.isEmpty())
return fallback;
line.replace(QLatin1String("$HOME"), QLatin1String("~"));
fixBashShortcuts(line);
return line;
@ -199,24 +171,24 @@ QString XdgDirs::userDir(XdgDirs::UserDirectory dir)
}
/************************************************
************************************************/
bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool createDir)
{
// possible values for UserDirectory
if (dir < 0 || dir > 7)
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(QString(getenv("HOME")))))
|| value.startsWith(home)
|| value.startsWith(QDir(home).canonicalPath())))
return false;
QString folderName = userDirectoryString[dir];
QString configDir(configHome());
QFile configFile(configDir % QLatin1String("/user-dirs.dirs"));
QFile configFile(configDir + QLatin1String("/user-dirs.dirs"));
// create the file if doesn't exist and opens it
if (!configFile.open(QIODevice::ReadWrite | QIODevice::Text))
@ -245,10 +217,10 @@ bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool
stream.reset();
configFile.resize(0);
if (!foundVar)
stream << QString("XDG_%1_DIR=\"%2\"\n").arg(folderName.toUpper()).arg(value);
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 << "\n";
stream << *i << QLatin1Char('\n');
configFile.close();
@ -262,31 +234,20 @@ bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool
}
/************************************************
************************************************/
QString XdgDirs::dataHome(bool createDir)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QString s = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
fixBashShortcuts(s);
if (createDir)
return createDirectory(s);
removeEndingSlash(s);
return s;
#else
return xdgSingleDir("XDG_DATA_HOME", QLatin1String(".local/share"), createDir);
#endif
}
/************************************************
************************************************/
QString XdgDirs::configHome(bool createDir)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
fixBashShortcuts(s);
if (createDir)
@ -294,51 +255,35 @@ QString XdgDirs::configHome(bool createDir)
removeEndingSlash(s);
return s;
#else
return xdgSingleDir("XDG_CONFIG_HOME", QLatin1String(".config"), createDir);
#endif
}
/************************************************
************************************************/
QStringList XdgDirs::dataDirs(const QString &postfix)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
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;
#else
QStringList dirs = xdgDirList("XDG_DATA_DIRS", postfix);
if (dirs.isEmpty())
{
dirs << QLatin1String("/usr/local/share") % postfix;
dirs << QLatin1String("/usr/share") % postfix;
}
return dirs;
#endif
}
/************************************************
************************************************/
QStringList XdgDirs::configDirs(const QString &postfix)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QStringList dirs;
const QString env = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
if (env.isEmpty())
@ -348,24 +293,11 @@ QStringList XdgDirs::configDirs(const QString &postfix)
cleanAndAddPostfix(dirs, postfix);
return dirs;
#else
QStringList dirs = xdgDirList("XDG_CONFIG_DIRS", postfix);
if (dirs.isEmpty())
{
dirs << QLatin1String("/etc/xdg") % postfix;
}
return dirs;
#endif
}
/************************************************
************************************************/
QString XdgDirs::cacheHome(bool createDir)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QString s = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
fixBashShortcuts(s);
if (createDir)
@ -373,37 +305,21 @@ QString XdgDirs::cacheHome(bool createDir)
removeEndingSlash(s);
return s;
#else
return xdgSingleDir("XDG_CACHE_HOME", QLatin1String(".cache"), createDir);
#endif
}
/************************************************
************************************************/
QString XdgDirs::runtimeDir()
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QString result = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
fixBashShortcuts(result);
removeEndingSlash(result);
return result;
#else
QString result(getenv("XDG_RUNTIME_DIR"));
fixBashShortcuts(result);
return result;
#endif
}
/************************************************
************************************************/
QString XdgDirs::autostartHome(bool createDir)
{
QString s = QString("%1/autostart").arg(configHome(createDir));
QString s = QString::fromLatin1("%1/autostart").arg(configHome(createDir));
fixBashShortcuts(s);
if (createDir)
@ -416,15 +332,12 @@ QString XdgDirs::autostartHome(bool createDir)
}
/************************************************
************************************************/
QStringList XdgDirs::autostartDirs(const QString &postfix)
{
QStringList dirs;
QStringList s = configDirs();
foreach(QString dir, s)
dirs << QString("%1/autostart").arg(dir) + postfix;
const QStringList s = configDirs();
for (const QString &dir : s)
dirs << QString::fromLatin1("%1/autostart").arg(dir) + postfix;
return dirs;
}

View File

@ -25,8 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGDIRS_H
#define QTXDG_XDGDIRS_H
@ -64,6 +62,14 @@ public:
*/
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.

View File

@ -25,8 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgicon.h"
#include <QString>
@ -35,18 +33,11 @@
#include <QStringList>
#include <QFileInfo>
#include <QCache>
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
#include "qiconfix/qiconloader_p_qt4.h"
#else
#include "qiconfix/qiconloader_p.h"
#endif
#include "../xdgiconloader/xdgiconloader_p.h"
#include <QCoreApplication>
#define DEFAULT_APP_ICON "application-x-executable"
static const QLatin1String DEFAULT_APP_ICON("application-x-executable");
/************************************************
************************************************/
static void qt_cleanup_icon_cache();
typedef QCache<QString, QIcon> IconCache;
@ -59,7 +50,7 @@ struct QtIconCache: public IconCache
}
};
}
Q_GLOBAL_STATIC(IconCache, qtIconCache);
Q_GLOBAL_STATIC(IconCache, qtIconCache)
static void qt_cleanup_icon_cache()
{
@ -67,42 +58,16 @@ static void qt_cleanup_icon_cache()
}
/************************************************
************************************************/
XdgIcon::XdgIcon()
{
}
/************************************************
************************************************/
XdgIcon::~XdgIcon()
{
}
/************************************************
Returns the name of the current icon theme.
************************************************/
QString XdgIcon::themeName()
{
return QIcon::themeName();
}
/************************************************
Sets the current icon theme to name.
************************************************/
void XdgIcon::setThemeName(const QString& themeName)
{
QIcon::setThemeName(themeName);
QtXdg::QIconLoader::instance()->updateSystemTheme();
}
/************************************************
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.
@ -112,12 +77,12 @@ QIcon XdgIcon::fromTheme(const QString& iconName, const QIcon& fallback)
if (iconName.isEmpty())
return fallback;
bool isAbsolute = (iconName[0] == '/');
bool isAbsolute = (iconName[0] == QLatin1Char('/'));
QString name = QFileInfo(iconName).fileName();
if (name.endsWith(".png", Qt::CaseInsensitive) ||
name.endsWith(".svg", Qt::CaseInsensitive) ||
name.endsWith(".xpm", Qt::CaseInsensitive))
if (name.endsWith(QLatin1String(".png"), Qt::CaseInsensitive) ||
name.endsWith(QLatin1String(".svg"), Qt::CaseInsensitive) ||
name.endsWith(QLatin1String(".xpm"), Qt::CaseInsensitive))
{
name.truncate(name.length() - 4);
}
@ -129,11 +94,12 @@ QIcon XdgIcon::fromTheme(const QString& iconName, const QIcon& fallback)
} else {
QIcon *cachedIcon;
if (!isAbsolute)
cachedIcon = new QIcon(new QtXdg::QIconLoaderEngineFixed(name));
cachedIcon = new QIcon(new XdgIconLoaderEngine(name));
else
cachedIcon = new QIcon(iconName);
qtIconCache()->insert(name, cachedIcon);
icon = *cachedIcon;
qtIconCache()->insert(name, cachedIcon);
}
// Note the qapp check is to allow lazy loading of static icons
@ -152,7 +118,7 @@ QIcon XdgIcon::fromTheme(const QString& iconName, const QIcon& fallback)
************************************************/
QIcon XdgIcon::fromTheme(const QStringList& iconNames, const QIcon& fallback)
{
foreach (QString iconName, iconNames)
for (const QString &iconName : iconNames)
{
QIcon icon = fromTheme(iconName);
if (!icon.isNull())
@ -163,9 +129,6 @@ QIcon XdgIcon::fromTheme(const QStringList& iconNames, const QIcon& fallback)
}
/************************************************
************************************************/
QIcon XdgIcon::fromTheme(const QString &iconName,
const QString &fallbackIcon1,
const QString &fallbackIcon2,
@ -182,18 +145,24 @@ QIcon XdgIcon::fromTheme(const QString &iconName,
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;

View File

@ -25,8 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGICON_H
#define QTXDG_XDGICON_H
@ -46,8 +44,19 @@ public:
const QString &fallbackIcon4 = QString());
static QIcon fromTheme(const QStringList& iconNames, const QIcon& fallback = QIcon());
static QString themeName();
static void setThemeName(const QString& themeName);
/*!
* 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();

View File

@ -34,12 +34,12 @@
#define QTXDG_API Q_DECL_IMPORT
#endif
#if defined(QTXDG_COMPILATION) && defined(QTXDG_BUILDING_TESTS)
#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
#elif defined(QTXDG_COMPILATION) && defined(QTXDG_TESTS)
# define QTXDG_AUTOTEST Q_DECL_EXPORT
#else
# define QTXDG_AUTOTEST
# define QTXDG_AUTOTEST /* Building library, tests disabled */
#endif
#endif // QTXDG_MACROS_H

View File

@ -25,8 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include "xdgmenu_p.h"
#include "xdgmenureader.h"
@ -40,12 +38,12 @@
#include <QtXml/QDomElement>
#include <QtXml/QDomNamedNodeMap>
#include <QFile>
#include <QSettings>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QSettings>
#include <QDir>
#include <QHash>
#include <QLocale>
#include <QFileSystemWatcher>
#include <QTranslator>
#include <QCoreApplication>
#include <QCryptographicHash>
@ -55,36 +53,14 @@
void installTranslation(const QString &name);
bool isParent(const QDomElement& parent, const QDomElement& child);
void installTranslation(const QString &name)
{
static bool alreadyLoaded = false;
if (alreadyLoaded)
return;
QString locale = QLocale::system().name();
QTranslator *translator = new QTranslator(qApp);
translator->load(QString("%1/%2_%3.qm").arg(TRANSLATIONS_DIR, name, locale));
QCoreApplication::installTranslator(translator);
alreadyLoaded = true;
}
/************************************************
************************************************/
XdgMenu::XdgMenu(QObject *parent) :
QObject(parent),
d_ptr(new XdgMenuPrivate(this))
{
installTranslation("libqtxdg");
}
/************************************************
************************************************/
XdgMenu::~XdgMenu()
{
Q_D(XdgMenu);
@ -92,9 +68,6 @@ XdgMenu::~XdgMenu()
}
/************************************************
************************************************/
XdgMenuPrivate::XdgMenuPrivate(XdgMenu *parent):
mOutDated(true),
q_ptr(parent)
@ -111,9 +84,6 @@ XdgMenuPrivate::XdgMenuPrivate(XdgMenu *parent):
}
/************************************************
************************************************/
const QString XdgMenu::logDir() const
{
Q_D(const XdgMenu);
@ -121,9 +91,6 @@ const QString XdgMenu::logDir() const
}
/************************************************
************************************************/
void XdgMenu::setLogDir(const QString& directory)
{
Q_D(XdgMenu);
@ -131,9 +98,6 @@ void XdgMenu::setLogDir(const QString& directory)
}
/************************************************
************************************************/
const QDomDocument XdgMenu::xml() const
{
Q_D(const XdgMenu);
@ -141,9 +105,6 @@ const QDomDocument XdgMenu::xml() const
}
/************************************************
************************************************/
QString XdgMenu::menuFileName() const
{
Q_D(const XdgMenu);
@ -151,28 +112,26 @@ QString XdgMenu::menuFileName() const
}
/************************************************
************************************************/
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);
@ -180,9 +139,6 @@ const QString XdgMenu::errorString() const
}
/************************************************
************************************************/
bool XdgMenu::read(const QString& menuFileName)
{
Q_D(XdgMenu);
@ -201,37 +157,37 @@ bool XdgMenu::read(const QString& menuFileName)
d->mXml = reader.xml();
QDomElement root = d->mXml.documentElement();
d->saveLog("00-reader.xml");
d->saveLog(QLatin1String("00-reader.xml"));
d->simplify(root);
d->saveLog("01-simplify.xml");
d->saveLog(QLatin1String("01-simplify.xml"));
d->mergeMenus(root);
d->saveLog("02-mergeMenus.xml");
d->saveLog(QLatin1String("02-mergeMenus.xml"));
d->moveMenus(root);
d->saveLog("03-moveMenus.xml");
d->saveLog(QLatin1String("03-moveMenus.xml"));
d->mergeMenus(root);
d->saveLog("04-mergeMenus.xml");
d->saveLog(QLatin1String("04-mergeMenus.xml"));
d->deleteDeletedMenus(root);
d->saveLog("05-deleteDeletedMenus.xml");
d->saveLog(QLatin1String("05-deleteDeletedMenus.xml"));
d->processDirectoryEntries(root, QStringList());
d->saveLog("06-processDirectoryEntries.xml");
d->saveLog(QLatin1String("06-processDirectoryEntries.xml"));
d->processApps(root);
d->saveLog("07-processApps.xml");
d->saveLog(QLatin1String("07-processApps.xml"));
d->processLayouts(root);
d->saveLog("08-processLayouts.xml");
d->saveLog(QLatin1String("08-processLayouts.xml"));
d->deleteEmpty(root);
d->saveLog("09-deleteEmpty.xml");
d->saveLog(QLatin1String("09-deleteEmpty.xml"));
d->fixSeparators(root);
d->saveLog("10-fixSeparators.xml");
d->saveLog(QLatin1String("10-fixSeparators.xml"));
d->mOutDated = false;
@ -241,9 +197,6 @@ bool XdgMenu::read(const QString& menuFileName)
}
/************************************************
************************************************/
void XdgMenu::save(const QString& fileName)
{
Q_D(const XdgMenu);
@ -251,9 +204,8 @@ void XdgMenu::save(const QString& fileName)
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
{
qWarning() << QString("Cannot write file %1:\n%2.")
.arg(fileName)
.arg(file.errorString());
qWarning() << QString::fromLatin1("Cannot write file %1:\n%2.")
.arg(fileName, file.errorString());
return;
}
@ -272,38 +224,32 @@ void XdgMenuPrivate::load(const QString& fileName)
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
qWarning() << QString("%1 not loading: %2").arg(fileName).arg(file.errorString());
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 + "/" + logFileName);
q->save(mLogDir + QLatin1Char('/') + logFileName);
}
/************************************************
************************************************/
void XdgMenuPrivate::mergeMenus(QDomElement& element)
{
QHash<QString, QDomElement> menus;
MutableDomElementIterator it(element, "Menu");
MutableDomElementIterator it(element, QLatin1String("Menu"));
it.toFront();
while(it.hasNext())
{
it.next();
menus[it.current().attribute("name")] = it.current();
menus[it.current().attribute(QLatin1String("name"))] = it.current();
}
@ -311,7 +257,7 @@ void XdgMenuPrivate::mergeMenus(QDomElement& element)
while (it.hasPrevious())
{
QDomElement src = it.previous();
QDomElement dest = menus[src.attribute("name")];
QDomElement dest = menus[src.attribute(QLatin1String("name"))];
if (dest != src)
{
prependChilds(src, dest);
@ -320,11 +266,11 @@ void XdgMenuPrivate::mergeMenus(QDomElement& element)
}
QDomElement n = element.firstChildElement("Menu");
QDomElement n = element.firstChildElement(QLatin1String("Menu"));
while (!n.isNull())
{
mergeMenus(n);
n = n.nextSiblingElement("Menu");
n = n.nextSiblingElement(QLatin1String("Menu"));
}
it.toFront();
@ -333,9 +279,6 @@ void XdgMenuPrivate::mergeMenus(QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuPrivate::simplify(QDomElement& element)
{
MutableDomElementIterator it(element);
@ -344,46 +287,46 @@ void XdgMenuPrivate::simplify(QDomElement& element)
{
QDomElement n = it.next();
if (n.tagName() == "Name")
if (n.tagName() == QLatin1String("Name"))
{
// The <Name> field must not contain the slash character ("/");
// implementations should discard any name containing a slash.
element.setAttribute("name", n.text().remove('/'));
element.setAttribute(QLatin1String("name"), n.text().remove(QLatin1Char('/')));
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == "Deleted")
else if(n.tagName() == QLatin1String("Deleted"))
{
element.setAttribute("deleted", true);
element.setAttribute(QLatin1String("deleted"), true);
n.parentNode().removeChild(n);
}
else if(n.tagName() == "NotDeleted")
else if(n.tagName() == QLatin1String("NotDeleted"))
{
element.setAttribute("deleted", false);
element.setAttribute(QLatin1String("deleted"), false);
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == "OnlyUnallocated")
else if(n.tagName() == QLatin1String("OnlyUnallocated"))
{
element.setAttribute("onlyUnallocated", true);
element.setAttribute(QLatin1String("onlyUnallocated"), true);
n.parentNode().removeChild(n);
}
else if(n.tagName() == "NotOnlyUnallocated")
else if(n.tagName() == QLatin1String(QLatin1String("NotOnlyUnallocated")))
{
element.setAttribute("onlyUnallocated", false);
element.setAttribute(QLatin1String("onlyUnallocated"), false);
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == "FileInfo")
else if(n.tagName() == QLatin1String("FileInfo"))
{
n.parentNode().removeChild(n);
}
// ......................................
else if(n.tagName() == "Menu")
else if(n.tagName() == QLatin1String("Menu"))
{
simplify(n);
}
@ -393,9 +336,6 @@ void XdgMenuPrivate::simplify(QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuPrivate::prependChilds(QDomElement& srcElement, QDomElement& destElement)
{
MutableDomElementIterator it(srcElement);
@ -407,21 +347,18 @@ void XdgMenuPrivate::prependChilds(QDomElement& srcElement, QDomElement& destEle
destElement.insertBefore(n, destElement.firstChild());
}
if (srcElement.attributes().contains("deleted") &&
!destElement.attributes().contains("deleted")
if (srcElement.attributes().contains(QLatin1String("deleted")) &&
!destElement.attributes().contains(QLatin1String("deleted"))
)
destElement.setAttribute("deleted", srcElement.attribute("deleted"));
destElement.setAttribute(QLatin1String("deleted"), srcElement.attribute(QLatin1String("deleted")));
if (srcElement.attributes().contains("onlyUnallocated") &&
!destElement.attributes().contains("onlyUnallocated")
if (srcElement.attributes().contains(QLatin1String("onlyUnallocated")) &&
!destElement.attributes().contains(QLatin1String("onlyUnallocated"))
)
destElement.setAttribute("onlyUnallocated", srcElement.attribute("onlyUnallocated"));
destElement.setAttribute(QLatin1String("onlyUnallocated"), srcElement.attribute(QLatin1String("onlyUnallocated")));
}
/************************************************
************************************************/
void XdgMenuPrivate::appendChilds(QDomElement& srcElement, QDomElement& destElement)
{
MutableDomElementIterator it(srcElement);
@ -429,11 +366,11 @@ void XdgMenuPrivate::appendChilds(QDomElement& srcElement, QDomElement& destElem
while(it.hasNext())
destElement.appendChild(it.next());
if (srcElement.attributes().contains("deleted"))
destElement.setAttribute("deleted", srcElement.attribute("deleted"));
if (srcElement.attributes().contains(QLatin1String("deleted")))
destElement.setAttribute(QLatin1String("deleted"), srcElement.attribute(QLatin1String("deleted")));
if (srcElement.attributes().contains("onlyUnallocated"))
destElement.setAttribute("onlyUnallocated", srcElement.attribute("onlyUnallocated"));
if (srcElement.attributes().contains(QLatin1String("onlyUnallocated")))
destElement.setAttribute(QLatin1String("onlyUnallocated"), srcElement.attribute(QLatin1String("onlyUnallocated")));
}
@ -446,10 +383,10 @@ QDomElement XdgMenu::findMenu(QDomElement& baseElement, const QString& path, boo
{
Q_D(XdgMenu);
// Absolute path ..................
if (path.startsWith('/'))
if (path.startsWith(QLatin1Char('/')))
{
QDomElement root = d->mXml.documentElement();
return findMenu(root, path.section('/', 2), createNonExisting);
return findMenu(root, path.section(QLatin1Char('/'), 2), createNonExisting);
}
// Relative path ..................
@ -457,13 +394,13 @@ QDomElement XdgMenu::findMenu(QDomElement& baseElement, const QString& path, boo
return baseElement;
QString name = path.section('/', 0, 0);
QString name = path.section(QLatin1Char('/'), 0, 0);
MutableDomElementIterator it(baseElement);
while(it.hasNext())
{
QDomElement n = it.next();
if (n.attribute("name") == name)
return findMenu(n, path.section('/', 1), createNonExisting);
if (n.attribute(QLatin1String("name")) == name)
return findMenu(n, path.section(QLatin1Char('/'), 1), createNonExisting);
}
@ -473,23 +410,20 @@ QDomElement XdgMenu::findMenu(QDomElement& baseElement, const QString& path, boo
return QDomElement();
QStringList names = path.split('/', QString::SkipEmptyParts);
const QStringList names = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
QDomElement el = baseElement;
foreach (QString name, names)
for (const QString &name : names)
{
QDomElement p = el;
el = d->mXml.createElement("Menu");
el = d->mXml.createElement(QLatin1String("Menu"));
p.appendChild(el);
el.setAttribute("name", name);
el.setAttribute(QLatin1String("name"), name);
}
return el;
}
/************************************************
************************************************/
bool isParent(const QDomElement& parent, const QDomElement& child)
{
QDomNode n = child;
@ -519,17 +453,17 @@ void XdgMenuPrivate::moveMenus(QDomElement& element)
Q_Q(XdgMenu);
{
MutableDomElementIterator i(element, "Menu");
MutableDomElementIterator i(element, QLatin1String("Menu"));
while(i.hasNext())
moveMenus(i.next());
}
MutableDomElementIterator i(element, "Move");
MutableDomElementIterator i(element, QLatin1String("Move"));
while(i.hasNext())
{
i.next();
QString oldPath = i.current().lastChildElement("Old").text();
QString newPath = i.current().lastChildElement("New").text();
QString oldPath = i.current().lastChildElement(QLatin1String("Old")).text();
QString newPath = i.current().lastChildElement(QLatin1String("New")).text();
element.removeChild(i.current());
@ -559,12 +493,12 @@ void XdgMenuPrivate::moveMenus(QDomElement& element)
************************************************/
void XdgMenuPrivate::deleteDeletedMenus(QDomElement& element)
{
MutableDomElementIterator i(element, "Menu");
MutableDomElementIterator i(element, QLatin1String("Menu"));
while(i.hasNext())
{
QDomElement e = i.next();
if (e.attribute("deleted") == "1" ||
e.attribute("name") == ".hidden"
if (e.attribute(QLatin1String("deleted")) == QLatin1String("1") ||
e.attribute(QLatin1String("name")) == QLatin1String(".hidden")
)
element.removeChild(e);
else
@ -574,15 +508,12 @@ void XdgMenuPrivate::deleteDeletedMenus(QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QStringList& parentDirs)
{
QStringList dirs;
QStringList files;
element.setAttribute("title", element.attribute("name"));
element.setAttribute(QLatin1String("title"), element.attribute(QLatin1String("name")));
MutableDomElementIterator i(element, QString());
i.toBack();
@ -590,13 +521,13 @@ void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QString
{
QDomElement e = i.previous();
if (e.tagName() == "Directory")
if (e.tagName() == QLatin1String("Directory"))
{
files << e.text();
element.removeChild(e);
}
else if (e.tagName() == "DirectoryDir")
else if (e.tagName() == QLatin1String("DirectoryDir"))
{
dirs << e.text();
element.removeChild(e);
@ -606,14 +537,14 @@ void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QString
dirs << parentDirs;
bool found = false;
foreach(QString file, files){
if (file.startsWith('/'))
for (const QString &file : const_cast<const QStringList&>(files)){
if (file.startsWith(QLatin1Char('/')))
found = loadDirectoryFile(file, element);
else
{
foreach (QString dir, dirs)
for (const QString &dir : const_cast<const QStringList&>(dirs))
{
found = loadDirectoryFile(dir + "/" + file, element);
found = loadDirectoryFile(dir + QLatin1Char('/') + file, element);
if (found) break;
}
}
@ -621,7 +552,7 @@ void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QString
}
MutableDomElementIterator it(element, "Menu");
MutableDomElementIterator it(element, QLatin1String("Menu"));
while(it.hasNext())
{
QDomElement e = it.next();
@ -631,9 +562,6 @@ void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QString
}
/************************************************
************************************************/
bool XdgMenuPrivate::loadDirectoryFile(const QString& fileName, QDomElement& element)
{
XdgDesktopFile file;
@ -643,9 +571,9 @@ bool XdgMenuPrivate::loadDirectoryFile(const QString& fileName, QDomElement& ele
return false;
element.setAttribute("title", file.localizedValue("Name").toString());
element.setAttribute("comment", file.localizedValue("Comment").toString());
element.setAttribute("icon", file.value("Icon").toString());
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());
@ -653,9 +581,6 @@ bool XdgMenuPrivate::loadDirectoryFile(const QString& fileName, QDomElement& ele
}
/************************************************
************************************************/
void XdgMenuPrivate::processApps(QDomElement& element)
{
Q_Q(XdgMenu);
@ -664,20 +589,17 @@ void XdgMenuPrivate::processApps(QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuPrivate::deleteEmpty(QDomElement& element)
{
MutableDomElementIterator it(element, "Menu");
MutableDomElementIterator it(element, QLatin1String("Menu"));
while(it.hasNext())
deleteEmpty(it.next());
if (element.attribute("keep") == "true")
if (element.attribute(QLatin1String("keep")) == QLatin1String("true"))
return;
QDomElement childMenu = element.firstChildElement("Menu");
QDomElement childApps = element.firstChildElement("AppLink");
QDomElement childMenu = element.firstChildElement(QLatin1String("Menu"));
QDomElement childApps = element.firstChildElement(QLatin1String("AppLink"));
if (childMenu.isNull() && childApps.isNull())
{
@ -686,9 +608,6 @@ void XdgMenuPrivate::deleteEmpty(QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuPrivate::processLayouts(QDomElement& element)
{
XdgMenuLayoutProcessor proc(element);
@ -696,31 +615,28 @@ void XdgMenuPrivate::processLayouts(QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuPrivate::fixSeparators(QDomElement& element)
{
MutableDomElementIterator it(element, "Separator");
MutableDomElementIterator it(element, QLatin1String("Separator"));
while(it.hasNext())
{
QDomElement s = it.next();
if (s.previousSiblingElement().tagName() == "Separator")
if (s.previousSiblingElement().tagName() == QLatin1String("Separator"))
element.removeChild(s);
}
QDomElement first = element.firstChild().toElement();
if (first.tagName() == "Separator")
if (first.tagName() == QLatin1String("Separator"))
element.removeChild(first);
QDomElement last = element.lastChild().toElement();
if (last.tagName() == "Separator")
if (last.tagName() == QLatin1String("Separator"))
element.removeChild(last);
MutableDomElementIterator mi(element, "Menu");
MutableDomElementIterator mi(element, QLatin1String("Menu"));
while(mi.hasNext())
fixSeparators(mi.next());
}
@ -732,32 +648,32 @@ void XdgMenuPrivate::fixSeparators(QDomElement& element)
************************************************/
QString XdgMenu::getMenuFileName(const QString& baseName)
{
QStringList configDirs = XdgDirs::configDirs();
QString menuPrefix = getenv("XDG_MENU_PREFIX");
const QStringList configDirs = XdgDirs::configDirs();
QString menuPrefix = QString::fromLocal8Bit(qgetenv("XDG_MENU_PREFIX"));
foreach(QString configDir, configDirs)
for (const QString &configDir : configDirs)
{
QFileInfo file(QString("%1/menus/%2%3").arg(configDir, menuPrefix, baseName));
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 << "razor-applications.menu";
wellKnownFiles << QLatin1String("razor-applications.menu");
// the "global" menu file name on suse and fedora
wellKnownFiles << "applications.menu";
wellKnownFiles << QLatin1String("applications.menu");
// rest files ordered by priority (descending)
wellKnownFiles << "kde4-applications.menu";
wellKnownFiles << "kde-applications.menu";
wellKnownFiles << "gnome-applications.menu";
wellKnownFiles << "lxde-applications.menu";
wellKnownFiles << QLatin1String("kde4-applications.menu");
wellKnownFiles << QLatin1String("kde-applications.menu");
wellKnownFiles << QLatin1String("gnome-applications.menu");
wellKnownFiles << QLatin1String("lxde-applications.menu");
foreach(QString configDir, configDirs)
for (const QString &configDir : configDirs)
{
foreach (QString f, wellKnownFiles)
for (const QString &f : const_cast<const QStringList&>(wellKnownFiles))
{
QFileInfo file(QString("%1/menus/%2").arg(configDir, f));
QFileInfo file(QString::fromLatin1("%1/menus/%2").arg(configDir, f));
if (file.exists())
return file.filePath();
}
@ -768,9 +684,6 @@ QString XdgMenu::getMenuFileName(const QString& baseName)
}
/************************************************
************************************************/
void XdgMenu::addWatchPath(const QString &path)
{
Q_D(XdgMenu);
@ -785,9 +698,6 @@ void XdgMenu::addWatchPath(const QString &path)
}
/************************************************
************************************************/
bool XdgMenu::isOutDated() const
{
Q_D(const XdgMenu);
@ -795,9 +705,6 @@ bool XdgMenu::isOutDated() const
}
/************************************************
************************************************/
void XdgMenuPrivate::rebuild()
{
Q_Q(XdgMenu);
@ -807,14 +714,11 @@ void XdgMenuPrivate::rebuild()
if (prevHash != mHash)
{
mOutDated = true;
emit changed();
Q_EMIT changed();
}
}
/************************************************
************************************************/
void XdgMenuPrivate::clearWatcher()
{
QStringList sl;

View File

@ -25,8 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENU_H
#define QTXDG_XDGMENU_H
@ -36,7 +34,6 @@
#include <QStringList>
#include <QtXml/QDomDocument>
class QDomDocument;
class QDomElement;
class XdgMenuPrivate;
@ -111,11 +108,11 @@ public:
*/
void setLogDir(const QString& directory);
static QString getMenuFileName(const QString& baseName = "applications.menu");
static QString getMenuFileName(const QString& baseName = QLatin1String("applications.menu"));
bool isOutDated() const;
signals:
Q_SIGNALS:
void changed();
protected:

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include <QObject>
#include <QFileSystemWatcher>
@ -74,10 +73,10 @@ public:
QFileSystemWatcher mWatcher;
bool mOutDated;
public slots:
public Q_SLOTS:
void rebuild();
signals:
Q_SIGNALS:
void changed();
@ -85,4 +84,3 @@ private:
XdgMenu* const q_ptr;
Q_DECLARE_PUBLIC(XdgMenu)
};

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenu.h"
#include "xdgmenuapplinkprocessor.h"
#include "xmlhelper.h"
@ -34,9 +33,6 @@
#include <QDir>
/************************************************
************************************************/
XdgMenuApplinkProcessor::XdgMenuApplinkProcessor(QDomElement& element, XdgMenu* menu, XdgMenuApplinkProcessor *parent) :
QObject(parent)
{
@ -44,9 +40,9 @@ XdgMenuApplinkProcessor::XdgMenuApplinkProcessor(QDomElement& element, XdgMenu*
mParent = parent;
mMenu = menu;
mOnlyUnallocated = element.attribute("onlyUnallocated") == "1";
mOnlyUnallocated = element.attribute(QLatin1String("onlyUnallocated")) == QLatin1String("1");
MutableDomElementIterator i(element, "Menu");
MutableDomElementIterator i(element, QLatin1String("Menu"));
while(i.hasNext())
{
QDomElement e = i.next();
@ -56,17 +52,11 @@ XdgMenuApplinkProcessor::XdgMenuApplinkProcessor(QDomElement& element, XdgMenu*
}
/************************************************
************************************************/
XdgMenuApplinkProcessor::~XdgMenuApplinkProcessor()
{
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::run()
{
step1();
@ -74,9 +64,6 @@ void XdgMenuApplinkProcessor::run()
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::step1()
{
fillAppFileInfoList();
@ -103,20 +90,18 @@ void XdgMenuApplinkProcessor::step1()
}
// Process childs menus ...............................
foreach (XdgMenuApplinkProcessor* child, mChilds)
for (XdgMenuApplinkProcessor* child : const_cast<const QLinkedList<XdgMenuApplinkProcessor*>&>(mChilds))
child->step1();
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::step2()
{
// Create AppLinks elements ...........................
QDomDocument doc = mElement.ownerDocument();
foreach (XdgMenuAppFileInfo* fileInfo, mSelected)
for (XdgMenuAppFileInfo* fileInfo : const_cast<const QLinkedList<XdgMenuAppFileInfo*>&>(mSelected))
{
if (mOnlyUnallocated && fileInfo->allocated())
continue;
@ -138,18 +123,18 @@ void XdgMenuApplinkProcessor::step2()
if (!show)
continue;
QDomElement appLink = doc.createElement("AppLink");
QDomElement appLink = doc.createElement(QLatin1String("AppLink"));
appLink.setAttribute("id", fileInfo->id());
appLink.setAttribute("title", file->localizedValue("Name").toString());
appLink.setAttribute("comment", file->localizedValue("Comment").toString());
appLink.setAttribute("genericName", file->localizedValue("GenericName").toString());
appLink.setAttribute("exec", file->value("Exec").toString());
appLink.setAttribute("terminal", file->value("Terminal").toBool());
appLink.setAttribute("startupNotify", file->value("StartupNotify").toBool());
appLink.setAttribute("path", file->value("Path").toString());
appLink.setAttribute("icon", file->value("Icon").toString());
appLink.setAttribute("desktopFile", file->fileName());
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);
@ -157,7 +142,7 @@ void XdgMenuApplinkProcessor::step2()
// Process childs menus ...............................
foreach (XdgMenuApplinkProcessor* child, mChilds)
for (XdgMenuApplinkProcessor* child : const_cast<const QLinkedList<XdgMenuApplinkProcessor*>&>(mChilds))
child->step2();
}
@ -175,7 +160,7 @@ void XdgMenuApplinkProcessor::fillAppFileInfoList()
{
// Build a pool by collecting entries found in <AppDir>
{
MutableDomElementIterator i(mElement, "AppDir");
MutableDomElementIterator i(mElement, QLatin1String("AppDir"));
i.toBack();
while(i.hasPrevious())
{
@ -199,16 +184,13 @@ void XdgMenuApplinkProcessor::fillAppFileInfoList()
}
/************************************************
************************************************/
void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QString& prefix)
{
QDir dir(dirName);
mMenu->addWatchPath(dir.absolutePath());
QFileInfoList files = dir.entryInfoList(QStringList("*.desktop"), QDir::Files);
const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files);
foreach (QFileInfo file, files)
for (const QFileInfo &file : files)
{
XdgDesktopFile* f = XdgDesktopFileCache::getFile(file.canonicalFilePath());
if (f)
@ -217,34 +199,31 @@ void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QSt
// Working recursively ............
QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot);
foreach (QFileInfo d, dirs)
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("%1%2-").arg(prefix, d.fileName()));
findDesktopFiles(dn, QString::fromLatin1("%1%2-").arg(prefix, d.fileName()));
}
}
}
/************************************************
Create rules
************************************************/
void XdgMenuApplinkProcessor::createRules()
{
MutableDomElementIterator i(mElement, QString());
while(i.hasNext())
{
QDomElement e = i.next();
if (e.tagName()=="Include")
if (e.tagName()== QLatin1String("Include"))
{
mRules.addInclude(e);
mElement.removeChild(e);
}
else if (e.tagName()=="Exclude")
else if (e.tagName()== QLatin1String("Exclude"))
{
mRules.addExclude(e);
mElement.removeChild(e);
@ -262,9 +241,9 @@ bool XdgMenuApplinkProcessor::checkTryExec(const QString& progName)
if (progName.startsWith(QDir::separator()))
return QFileInfo(progName).isExecutable();
QStringList dirs = QString(getenv("PATH")).split(":");
const QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':'));
foreach (QString dir, dirs)
for (const QString &dir : dirs)
{
if (QFileInfo(QDir(dir), progName).isExecutable())
return true;
@ -272,4 +251,3 @@ bool XdgMenuApplinkProcessor::checkTryExec(const QString& progName)
return false;
}

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENUAPPLINKPROCESSOR_H
#define QTXDG_XDGMENUAPPLINKPROCESSOR_H
@ -45,6 +44,7 @@ typedef QLinkedList<XdgMenuAppFileInfo*> XdgMenuAppFileInfoList;
typedef QHash<QString, XdgMenuAppFileInfo*> XdgMenuAppFileInfoHash;
typedef QHashIterator<QString, XdgMenuAppFileInfo*> XdgMenuAppFileInfoHashIterator;
class XdgMenuApplinkProcessor : public QObject
{
Q_OBJECT
@ -98,5 +98,4 @@ private:
QString mId;
};
#endif // QTXDG_XDGMENUAPPLINKPROCESSOR_H

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenulayoutprocessor.h"
#include "xmlhelper.h"
#include <QDebug>
@ -36,9 +35,7 @@
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);
@ -71,20 +68,20 @@ XdgMenuLayoutProcessor::XdgMenuLayoutProcessor(QDomElement& element):
mDefaultParams.mInlineHeader = true;
mDefaultParams.mInlineAlias = false;
mDefaultLayout = findLastElementByTag(element, "DefaultLayout");
mDefaultLayout = findLastElementByTag(element, QLatin1String("DefaultLayout"));
if (mDefaultLayout.isNull())
{
// Create DefaultLayout node
QDomDocument doc = element.ownerDocument();
mDefaultLayout = doc.createElement("DefaultLayout");
mDefaultLayout = doc.createElement(QLatin1String("DefaultLayout"));
QDomElement menus = doc.createElement("Merge");
menus.setAttribute("type", "menus");
QDomElement menus = doc.createElement(QLatin1String("Merge"));
menus.setAttribute(QLatin1String("type"), QLatin1String("menus"));
mDefaultLayout.appendChild(menus);
QDomElement files = doc.createElement("Merge");
files.setAttribute("type", "files");
QDomElement files = doc.createElement(QLatin1String("Merge"));
files.setAttribute(QLatin1String("type"), QLatin1String("files"));
mDefaultLayout.appendChild(files);
mElement.appendChild(mDefaultLayout);
@ -94,22 +91,19 @@ XdgMenuLayoutProcessor::XdgMenuLayoutProcessor(QDomElement& element):
// 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, "Layout");
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, "DefaultLayout");
QDomElement defaultLayout = findLastElementByTag(element, QLatin1String("DefaultLayout"));
if (defaultLayout.isNull())
mDefaultLayout = parent->mDefaultLayout;
@ -120,38 +114,32 @@ XdgMenuLayoutProcessor::XdgMenuLayoutProcessor(QDomElement& element, XdgMenuLayo
// 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, "Layout");
mLayout = findLastElementByTag(element, QLatin1String("Layout"));
if (mLayout.isNull() || !mLayout.hasChildNodes())
mLayout = mDefaultLayout;
}
/************************************************
************************************************/
void XdgMenuLayoutProcessor::setParams(QDomElement defaultLayout, LayoutParams *result)
{
if (defaultLayout.hasAttribute("show_empty"))
result->mShowEmpty = defaultLayout.attribute("show_empty") == "true";
if (defaultLayout.hasAttribute(QLatin1String("show_empty")))
result->mShowEmpty = defaultLayout.attribute(QLatin1String("show_empty")) == QLatin1String("true");
if (defaultLayout.hasAttribute("inline"))
result->mInline = defaultLayout.attribute("inline") == "true";
if (defaultLayout.hasAttribute(QLatin1String("inline")))
result->mInline = defaultLayout.attribute(QLatin1String("inline")) == QLatin1String("true");
if (defaultLayout.hasAttribute("inline_limit"))
result->mInlineLimit = defaultLayout.attribute("inline_limit").toInt();
if (defaultLayout.hasAttribute(QLatin1String("inline_limit")))
result->mInlineLimit = defaultLayout.attribute(QLatin1String("inline_limit")).toInt();
if (defaultLayout.hasAttribute("inline_header"))
result->mInlineHeader = defaultLayout.attribute("inline_header") == "true";
if (defaultLayout.hasAttribute(QLatin1String("inline_header")))
result->mInlineHeader = defaultLayout.attribute(QLatin1String("inline_header")) == QLatin1String("true");
if (defaultLayout.hasAttribute("inline_alias"))
result->mInlineAlias = defaultLayout.attribute("inline_alias") == "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);
@ -168,9 +156,6 @@ QDomElement XdgMenuLayoutProcessor::searchElement(const QString &tagName, const
}
/************************************************
************************************************/
int childsCount(const QDomElement& element)
{
int count = 0;
@ -178,7 +163,7 @@ int childsCount(const QDomElement& element)
while (it.hasNext())
{
QString tag = it.next().tagName();
if (tag == "AppLink" || tag == "Menu" || tag == "Separator")
if (tag == QLatin1String("AppLink") || tag == QLatin1String("Menu") || tag == QLatin1String("Separator"))
count ++;
}
@ -186,18 +171,15 @@ int childsCount(const QDomElement& element)
}
/************************************************
************************************************/
void XdgMenuLayoutProcessor::run()
{
QDomDocument doc = mLayout.ownerDocument();
mResult = doc.createElement("Result");
mResult = doc.createElement(QLatin1String("Result"));
mElement.appendChild(mResult);
// Process childs menus ...............................
{
DomElementIterator it(mElement, "Menu");
DomElementIterator it(mElement, QLatin1String("Menu"));
while (it.hasNext())
{
QDomElement e = it.next();
@ -214,26 +196,26 @@ void XdgMenuLayoutProcessor::run()
{
QDomElement e = it.next();
if (e.tagName() == "Filename")
if (e.tagName() == QLatin1String("Filename"))
processFilenameTag(e);
else if (e.tagName() == "Menuname")
else if (e.tagName() == QLatin1String("Menuname"))
processMenunameTag(e);
else if (e.tagName() == "Separator")
else if (e.tagName() == QLatin1String("Separator"))
processSeparatorTag(e);
else if (e.tagName() == "Merge")
else if (e.tagName() == QLatin1String("Merge"))
{
QDomElement merge = mResult.ownerDocument().createElement("Merge");
merge.setAttribute("type", e.attribute("type"));
QDomElement merge = mResult.ownerDocument().createElement(QLatin1String("Merge"));
merge.setAttribute(QLatin1String("type"), e.attribute(QLatin1String("type")));
mResult.appendChild(merge);
}
}
// Step 2 ...................................
{
MutableDomElementIterator ri(mResult, "Merge");
MutableDomElementIterator ri(mResult, QLatin1String("Merge"));
while (ri.hasNext())
{
processMergeTag(ri.next());
@ -267,7 +249,7 @@ void XdgMenuLayoutProcessor::processFilenameTag(const QDomElement &element)
{
QString id = element.text();
QDomElement appLink = searchElement("AppLink", "id", id);
QDomElement appLink = searchElement(QLatin1String("AppLink"), QLatin1String("id"), id);
if (!appLink.isNull())
mResult.appendChild(appLink);
}
@ -308,7 +290,7 @@ void XdgMenuLayoutProcessor::processFilenameTag(const QDomElement &element)
void XdgMenuLayoutProcessor::processMenunameTag(const QDomElement &element)
{
QString id = element.text();
QDomElement menu = searchElement("Menu", "name", id);
QDomElement menu = searchElement(QLatin1String("Menu"), QLatin1String("name"), id);
if (menu.isNull())
return;
@ -321,7 +303,7 @@ void XdgMenuLayoutProcessor::processMenunameTag(const QDomElement &element)
{
if (params.mShowEmpty)
{
menu.setAttribute("keep", "true");
menu.setAttribute(QLatin1String("keep"), QLatin1String("true"));
mResult.appendChild(menu);
}
return;
@ -348,7 +330,7 @@ void XdgMenuLayoutProcessor::processMenunameTag(const QDomElement &element)
// Header ....................................
if (doHeader)
{
QDomElement header = mLayout.ownerDocument().createElement("Header");
QDomElement header = mLayout.ownerDocument().createElement(QLatin1String("Header"));
QDomNamedNodeMap attrs = menu.attributes();
for (int i=0; i < attrs.count(); ++i)
@ -362,7 +344,7 @@ void XdgMenuLayoutProcessor::processMenunameTag(const QDomElement &element)
// Alias .....................................
if (doAlias)
{
menu.firstChild().toElement().setAttribute("title", menu.attribute("title"));
menu.firstChild().toElement().setAttribute(QLatin1String("title"), menu.attribute(QLatin1String("title")));
}
// Inline ....................................
@ -382,7 +364,7 @@ void XdgMenuLayoutProcessor::processMenunameTag(const QDomElement &element)
************************************************/
void XdgMenuLayoutProcessor::processSeparatorTag(const QDomElement &element)
{
QDomElement separator = element.ownerDocument().createElement("Separator");
QDomElement separator = element.ownerDocument().createElement(QLatin1String("Separator"));
mResult.appendChild(separator);
}
@ -405,7 +387,7 @@ void XdgMenuLayoutProcessor::processSeparatorTag(const QDomElement &element)
************************************************/
void XdgMenuLayoutProcessor::processMergeTag(const QDomElement &element)
{
QString type = element.attribute("type");
QString type = element.attribute(QLatin1String("type"));
QMap<QString, QDomElement> map;
MutableDomElementIterator it(mElement);
@ -413,10 +395,10 @@ void XdgMenuLayoutProcessor::processMergeTag(const QDomElement &element)
{
QDomElement e = it.next();
if (
((type == "menus" || type == "all") && e.tagName() == "Menu" ) ||
((type == "files" || type == "all") && e.tagName() == "AppLink")
((type == QLatin1String("menus") || type == QLatin1String("all")) && e.tagName() == QLatin1String("Menu" )) ||
((type == QLatin1String("files") || type == QLatin1String("all")) && e.tagName() == QLatin1String("AppLink"))
)
map.insert(e.attribute("title"), e);
map.insert(e.attribute(QLatin1String("title")), e);
}
QMapIterator<QString, QDomElement> mi(map);
@ -427,4 +409,3 @@ void XdgMenuLayoutProcessor::processMergeTag(const QDomElement &element)
mResult.removeChild(element);
}

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENULAYOUTPROCESSOR_H
#define QTXDG_XDGMENULAYOUTPROCESSOR_H

View File

@ -25,26 +25,20 @@
*
* 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 <QDebug>
#include <QString>
#include <QDir>
#include <QDebug>
#include <QtXml/QDomNamedNodeMap>
#include <QtXml/QDomNode>
/************************************************
************************************************/
XdgMenuReader::XdgMenuReader(XdgMenu* menu, XdgMenuReader* parentReader, QObject *parent) :
QObject(parent),
mMenu(menu)
@ -55,18 +49,12 @@ XdgMenuReader::XdgMenuReader(XdgMenu* menu, XdgMenuReader* parentReader, QObjec
}
/************************************************
************************************************/
XdgMenuReader::~XdgMenuReader()
{
}
/************************************************
************************************************/
bool XdgMenuReader::load(const QString& fileName, const QString& baseDir)
{
if (fileName.isEmpty())
@ -88,7 +76,7 @@ bool XdgMenuReader::load(const QString& fileName, const QString& baseDir)
QFile file(mFileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
mErrorStr = QString("%1 not loading: %2").arg(fileName).arg(file.errorString());
mErrorStr = QString::fromLatin1("%1 not loading: %2").arg(fileName, file.errorString());
return false;
}
//qDebug() << "Load file:" << mFileName;
@ -100,7 +88,7 @@ bool XdgMenuReader::load(const QString& fileName, const QString& baseDir)
if (!mXml.setContent(&file, true, &errorStr, &errorLine, &errorColumn))
{
mErrorStr = QString("Parse error at line %1, column %2:\n%3")
mErrorStr = QString::fromLatin1("Parse error at line %1, column %2:\n%3")
.arg(errorLine)
.arg(errorColumn)
.arg(errorStr);
@ -109,10 +97,10 @@ bool XdgMenuReader::load(const QString& fileName, const QString& baseDir)
QDomElement root = mXml.documentElement();
QDomElement debugElement = mXml.createElement("FileInfo");
debugElement.setAttribute("file", mFileName);
QDomElement debugElement = mXml.createElement(QLatin1String("FileInfo"));
debugElement.setAttribute(QLatin1String("file"), mFileName);
if (mParentReader)
debugElement.setAttribute("parent", mParentReader->fileName());
debugElement.setAttribute(QLatin1String("parent"), mParentReader->fileName());
QDomNode null;
root.insertBefore(debugElement, null);
@ -136,49 +124,49 @@ void XdgMenuReader::processMergeTags(QDomElement& element)
{
QDomElement next = n.previousSiblingElement();
// MergeFile ..................
if (n.tagName() == "MergeFile")
if (n.tagName() == QLatin1String("MergeFile"))
{
processMergeFileTag(n, &mergedFiles);
n.parentNode().removeChild(n);
}
// MergeDir ...................
else if(n.tagName() == "MergeDir")
else if(n.tagName() == QLatin1String("MergeDir"))
{
processMergeDirTag(n, &mergedFiles);
n.parentNode().removeChild(n);
}
// DefaultMergeDirs ...........
else if (n.tagName() == "DefaultMergeDirs")
else if (n.tagName() == QLatin1String("DefaultMergeDirs"))
{
processDefaultMergeDirsTag(n, &mergedFiles);
n.parentNode().removeChild(n);
}
// AppDir ...................
else if(n.tagName() == "AppDir")
else if(n.tagName() == QLatin1String("AppDir"))
{
processAppDirTag(n);
n.parentNode().removeChild(n);
}
// DefaultAppDirs .............
else if(n.tagName() == "DefaultAppDirs")
else if(n.tagName() == QLatin1String("DefaultAppDirs"))
{
processDefaultAppDirsTag(n);
n.parentNode().removeChild(n);
}
// DirectoryDir ...................
else if(n.tagName() == "DirectoryDir")
else if(n.tagName() == QLatin1String("DirectoryDir"))
{
processDirectoryDirTag(n);
n.parentNode().removeChild(n);
}
// DefaultDirectoryDirs ...........
else if(n.tagName() == "DefaultDirectoryDirs")
else if(n.tagName() == QLatin1String("DefaultDirectoryDirs"))
{
processDefaultDirectoryDirsTag(n);
n.parentNode().removeChild(n);
@ -186,7 +174,7 @@ void XdgMenuReader::processMergeTags(QDomElement& element)
// Menu .......................
else if(n.tagName() == "Menu")
else if(n.tagName() == QLatin1String("Menu"))
{
processMergeTags(n);
}
@ -217,7 +205,7 @@ void XdgMenuReader::processMergeFileTag(QDomElement& element, QStringList* merge
{
//qDebug() << "Process " << element;// << "in" << mFileName;
if (element.attribute("type") != "parent")
if (element.attribute(QLatin1String("type")) != QLatin1String("parent"))
{
mergeFile(element.text(), element, mergedFiles);
}
@ -227,7 +215,7 @@ void XdgMenuReader::processMergeFileTag(QDomElement& element, QStringList* merge
QString relativeName;
QStringList configDirs = XdgDirs::configDirs();
foreach (QString configDir, configDirs)
for (const QString &configDir : const_cast<const QStringList&>(configDirs))
{
if (mFileName.startsWith(configDir))
{
@ -248,9 +236,9 @@ void XdgMenuReader::processMergeFileTag(QDomElement& element, QStringList* merge
if (relativeName.isEmpty())
return;
foreach (QString configDir, configDirs)
for (const QString &configDir : configDirs)
{
if (QFileInfo(configDir + relativeName).exists())
if (QFileInfo::exists(configDir + relativeName))
{
mergeFile(configDir + relativeName, element, mergedFiles);
return;
@ -300,20 +288,20 @@ void XdgMenuReader::processDefaultMergeDirsTag(QDomElement& element, QStringList
//qDebug() << "Process " << element;// << "in" << mFileName;
QString menuBaseName = QFileInfo(mMenu->menuFileName()).baseName();
int n = menuBaseName.lastIndexOf('-');
int n = menuBaseName.lastIndexOf(QLatin1Char('-'));
if (n>-1)
menuBaseName = menuBaseName.mid(n+1);
QStringList dirs = XdgDirs::configDirs();
dirs << XdgDirs::configHome();
foreach (QString dir, dirs)
for (const QString &dir : const_cast<const QStringList&>(dirs))
{
mergeDir(QString("%1/menus/%2-merged").arg(dir).arg(menuBaseName), element, mergedFiles);
mergeDir(QString::fromLatin1("%1/menus/%2-merged").arg(dir, menuBaseName), element, mergedFiles);
}
if (menuBaseName == "applications")
mergeFile(QString("%1/menus/applications-kmenuedit.menu").arg(XdgDirs::configHome()), element, mergedFiles);
if (menuBaseName == QLatin1String("applications"))
mergeFile(QString::fromLatin1("%1/menus/applications-kmenuedit.menu").arg(XdgDirs::configHome()), element, mergedFiles);
}
@ -324,7 +312,7 @@ void XdgMenuReader::processDefaultMergeDirsTag(QDomElement& element, QStringList
void XdgMenuReader::processAppDirTag(QDomElement& element)
{
//qDebug() << "Process " << element;
addDirTag(element, "AppDir", element.text());
addDirTag(element, QLatin1String("AppDir"), element.text());
}
@ -341,10 +329,10 @@ void XdgMenuReader::processDefaultAppDirsTag(QDomElement& element)
QStringList dirs = XdgDirs::dataDirs();
dirs.prepend(XdgDirs::dataHome(false));
foreach (QString dir, dirs)
for (const QString &dir : const_cast<const QStringList&> (dirs))
{
//qDebug() << "Add AppDir: " << dir + "/applications/";
addDirTag(element, "AppDir", dir + "/applications/");
addDirTag(element, QLatin1String("AppDir"), dir + QLatin1String("/applications/"));
}
}
@ -355,7 +343,7 @@ void XdgMenuReader::processDefaultAppDirsTag(QDomElement& element)
void XdgMenuReader::processDirectoryDirTag(QDomElement& element)
{
//qDebug() << "Process " << element;
addDirTag(element, "DirectoryDir", element.text());
addDirTag(element, QLatin1String("DirectoryDir"), element.text());
}
@ -372,8 +360,8 @@ void XdgMenuReader::processDefaultDirectoryDirsTag(QDomElement& element)
QStringList dirs = XdgDirs::dataDirs();
dirs.prepend(XdgDirs::dataHome(false));
foreach (QString dir, dirs)
addDirTag(element, "DirectoryDir", dir + "/desktop-directories/");
for (const QString &dir : const_cast<const QStringList&>(dirs))
addDirTag(element, QLatin1String("DirectoryDir"), dir + QLatin1String("/desktop-directories/"));
}
/************************************************
@ -391,8 +379,7 @@ void XdgMenuReader::addDirTag(QDomElement& previousElement, const QString& tagNa
}
}
/************************************************
/*
If fileName is not an absolute path then the file to be merged should be located
relative to the location of this menu file.
************************************************/
@ -421,7 +408,7 @@ void XdgMenuReader::mergeFile(const QString& fileName, QDomElement& element, QSt
{
// As a special exception, remove the <Name> element from the root
// element of each file being merged.
if (n.tagName() != "Name")
if (n.tagName() != QLatin1String("Name"))
{
QDomNode imp = mXml.importNode(n, true);
element.parentNode().insertBefore(imp, element);
@ -433,9 +420,6 @@ void XdgMenuReader::mergeFile(const QString& fileName, QDomElement& element, QSt
}
/************************************************
************************************************/
void XdgMenuReader::mergeDir(const QString& dirName, QDomElement& element, QStringList* mergedFiles)
{
QFileInfo dirInfo(mDirName, dirName);
@ -444,13 +428,9 @@ void XdgMenuReader::mergeDir(const QString& dirName, QDomElement& element, QStri
{
//qDebug() << "Merge dir: " << dirInfo.canonicalFilePath();
QDir dir = QDir(dirInfo.canonicalFilePath());
const QFileInfoList files = dir.entryInfoList(QStringList() << "*.menu", QDir::Files | QDir::Readable);
const QFileInfoList files = dir.entryInfoList(QStringList() << QLatin1String("*.menu"), QDir::Files | QDir::Readable);
foreach (QFileInfo file, files)
for (const QFileInfo &file : files)
mergeFile(file.canonicalFilePath(), element, mergedFiles);
}
}

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENUREADER_H
#define QTXDG_XDGMENUREADER_H
@ -34,6 +33,7 @@
#include <QStringList>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
class XdgMenu;
class XdgMenuReader : public QObject
{
@ -47,9 +47,9 @@ public:
QString errorString() const { return mErrorStr; }
QDomDocument& xml() { return mXml; }
signals:
Q_SIGNALS:
public slots:
public Q_SLOTS:
protected:
void processMergeTags(QDomElement& element);

View File

@ -25,23 +25,17 @@
*
* END_COMMON_COPYRIGHT_HEADER */
/*********************************************************************
See: http://standards.freedesktop.org/desktop-entry-spec
*********************************************************************/
#include "xdgmenurules.h"
#include "xmlhelper.h"
#include <QStringList>
#include <QDebug>
#include <QStringList>
/**
* See: http://standards.freedesktop.org/desktop-entry-spec
*/
/************************************************
************************************************/
XdgMenuRule::XdgMenuRule(const QDomElement& element, QObject* parent) :
QObject(parent)
{
@ -49,17 +43,11 @@ XdgMenuRule::XdgMenuRule(const QDomElement& element, QObject* parent) :
}
/************************************************
************************************************/
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
@ -75,34 +63,31 @@ XdgMenuRuleOr::XdgMenuRuleOr(const QDomElement& element, QObject* parent) :
{
QDomElement e = iter.next();
if (e.tagName() == "Or")
if (e.tagName() == QLatin1String("Or"))
mChilds.append(new XdgMenuRuleOr(e, this));
else if (e.tagName() == "And")
else if (e.tagName() == QLatin1String("And"))
mChilds.append(new XdgMenuRuleAnd(e, this));
else if (e.tagName() == "Not")
else if (e.tagName() == QLatin1String("Not"))
mChilds.append(new XdgMenuRuleNot(e, this));
else if (e.tagName() == "Filename")
else if (e.tagName() == QLatin1String("Filename"))
mChilds.append(new XdgMenuRuleFileName(e, this));
else if (e.tagName() == "Category")
else if (e.tagName() == QLatin1String("Category"))
mChilds.append(new XdgMenuRuleCategory(e, this));
else if (e.tagName() == "All")
else if (e.tagName() == QLatin1String("All"))
mChilds.append(new XdgMenuRuleAll(e, this));
else
qWarning() << "Unknown rule" << e.tagName();
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)
@ -124,9 +109,6 @@ XdgMenuRuleAnd::XdgMenuRuleAnd(const QDomElement& element, QObject *parent) :
}
/************************************************
************************************************/
bool XdgMenuRuleAnd::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
for (QLinkedList<XdgMenuRule*>::Iterator i=mChilds.begin(); i!=mChilds.end(); ++i)
@ -136,7 +118,6 @@ bool XdgMenuRuleAnd::check(const QString& desktopFileId, const XdgDesktopFile& d
}
/************************************************
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
@ -150,16 +131,12 @@ XdgMenuRuleNot::XdgMenuRuleNot(const QDomElement& element, QObject *parent) :
}
/************************************************
************************************************/
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.
@ -172,9 +149,6 @@ XdgMenuRuleFileName::XdgMenuRuleFileName(const QDomElement& element, QObject *pa
}
/************************************************
************************************************/
bool XdgMenuRuleFileName::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
Q_UNUSED(desktopFile)
@ -183,7 +157,6 @@ bool XdgMenuRuleFileName::check(const QString& desktopFileId, const XdgDesktopFi
}
/************************************************
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.
@ -195,9 +168,6 @@ XdgMenuRuleCategory::XdgMenuRuleCategory(const QDomElement& element, QObject *pa
}
/************************************************
************************************************/
bool XdgMenuRuleCategory::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
Q_UNUSED(desktopFileId)
@ -215,9 +185,6 @@ XdgMenuRuleAll::XdgMenuRuleAll(const QDomElement& element, QObject *parent) :
}
/************************************************
************************************************/
bool XdgMenuRuleAll::check(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
Q_UNUSED(desktopFileId)
@ -226,46 +193,29 @@ bool XdgMenuRuleAll::check(const QString& desktopFileId, const XdgDesktopFile& d
}
/************************************************
************************************************/
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)
@ -275,9 +225,6 @@ bool XdgMenuRules::checkInclude(const QString& desktopFileId, const XdgDesktopFi
}
/************************************************
************************************************/
bool XdgMenuRules::checkExclude(const QString& desktopFileId, const XdgDesktopFile& desktopFile)
{
for (QLinkedList<XdgMenuRule*>::Iterator i=mExcludeRules.begin(); i!=mExcludeRules.end(); ++i)
@ -285,5 +232,3 @@ bool XdgMenuRules::checkExclude(const QString& desktopFileId, const XdgDesktopFi
return false;
}

View File

@ -25,12 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
/*********************************************************************
See: http://standards.freedesktop.org/desktop-entry-spec
*********************************************************************/
#ifndef QTXDG_XDGMENURULES_H
#define QTXDG_XDGMENURULES_H
@ -40,6 +34,11 @@
#include "xdgdesktopfile.h"
/**
* See: http://standards.freedesktop.org/desktop-entry-spec
*/
class XdgMenuRule : public QObject
{
Q_OBJECT

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#include "xdgmenuwidget.h"
#include "xdgicon.h"
#include "xmlhelper.h"
@ -35,19 +34,17 @@
#include <QEvent>
#include <QDebug>
#include <QUrl>
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
#else
#include <QMimeData>
#endif
#include <QtGui/QDrag>
#include <QtGui/QMouseEvent>
#include <QApplication>
class XdgMenuWidgetPrivate
{
private:
XdgMenuWidget* const q_ptr;
Q_DECLARE_PUBLIC(XdgMenuWidget);
Q_DECLARE_PUBLIC(XdgMenuWidget)
public:
explicit XdgMenuWidgetPrivate(XdgMenuWidget* parent):
@ -69,10 +66,6 @@ private:
};
/************************************************
************************************************/
XdgMenuWidget::XdgMenuWidget(const XdgMenu& xdgMenu, const QString& title, QWidget* parent):
QMenu(parent),
d_ptr(new XdgMenuWidgetPrivate(this))
@ -81,9 +74,7 @@ XdgMenuWidget::XdgMenuWidget(const XdgMenu& xdgMenu, const QString& title, QWidg
setTitle(XdgMenuWidgetPrivate::escape(title));
}
/************************************************
************************************************/
XdgMenuWidget::XdgMenuWidget(const QDomElement& menuElement, QWidget* parent):
QMenu(parent),
d_ptr(new XdgMenuWidgetPrivate(this))
@ -92,9 +83,6 @@ XdgMenuWidget::XdgMenuWidget(const QDomElement& menuElement, QWidget* parent):
}
/************************************************
************************************************/
XdgMenuWidget::XdgMenuWidget(const XdgMenuWidget& other, QWidget* parent):
QMenu(parent),
d_ptr(new XdgMenuWidgetPrivate(this))
@ -103,9 +91,6 @@ XdgMenuWidget::XdgMenuWidget(const XdgMenuWidget& other, QWidget* parent):
}
/************************************************
************************************************/
void XdgMenuWidgetPrivate::init(const QDomElement& xml)
{
Q_Q(XdgMenuWidget);
@ -114,13 +99,13 @@ void XdgMenuWidgetPrivate::init(const QDomElement& xml)
q->clear();
QString title;
if (! xml.attribute("title").isEmpty())
title = xml.attribute("title");
if (! xml.attribute(QLatin1String("title")).isEmpty())
title = xml.attribute(QLatin1String("title"));
else
title = xml.attribute("name");
title = xml.attribute(QLatin1String("name"));
q->setTitle(escape(title));
q->setToolTip(xml.attribute("comment"));
q->setToolTip(xml.attribute(QLatin1String("comment")));
QIcon parentIcon;
@ -128,24 +113,18 @@ void XdgMenuWidgetPrivate::init(const QDomElement& xml)
if (parentMenu)
parentIcon = parentMenu->icon();
q->setIcon(XdgIcon::fromTheme(mXml.attribute("icon"), parentIcon));
q->setIcon(XdgIcon::fromTheme(mXml.attribute(QLatin1String("icon")), parentIcon));
buildMenu();
}
/************************************************
************************************************/
XdgMenuWidget::~XdgMenuWidget()
{
delete d_ptr;
}
/************************************************
************************************************/
XdgMenuWidget& XdgMenuWidget::operator=(const XdgMenuWidget& other)
{
Q_D(XdgMenuWidget);
@ -155,9 +134,6 @@ XdgMenuWidget& XdgMenuWidget::operator=(const XdgMenuWidget& other)
}
/************************************************
************************************************/
bool XdgMenuWidget::event(QEvent* event)
{
Q_D(XdgMenuWidget);
@ -179,9 +155,6 @@ bool XdgMenuWidget::event(QEvent* event)
}
/************************************************
************************************************/
void XdgMenuWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
@ -207,16 +180,13 @@ void XdgMenuWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
}
/************************************************
************************************************/
void XdgMenuWidgetPrivate::buildMenu()
{
Q_Q(XdgMenuWidget);
QAction* first = 0;
if (!q->actions().isEmpty())
first = q->actions().last();
first = q->actions().constLast();
DomElementIterator it(mXml, QString());
@ -225,39 +195,36 @@ void XdgMenuWidgetPrivate::buildMenu()
QDomElement xml = it.next();
// Build submenu ........................
if (xml.tagName() == "Menu")
if (xml.tagName() == QLatin1String("Menu"))
q->insertMenu(first, new XdgMenuWidget(xml, q));
//Build application link ................
else if (xml.tagName() == "AppLink")
else if (xml.tagName() == QLatin1String("AppLink"))
q->insertAction(first, createAction(xml));
//Build separator .......................
else if (xml.tagName() == "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("desktopFile"), q);
XdgAction* action = new XdgAction(xml.attribute(QLatin1String("desktopFile")), q);
QString title;
if (!xml.attribute("title").isEmpty())
title = xml.attribute("title");
if (!xml.attribute(QLatin1String("title")).isEmpty())
title = xml.attribute(QLatin1String("title"));
else
title = xml.attribute("name");
title = xml.attribute(QLatin1String("name"));
if (!xml.attribute("genericName").isEmpty() &&
xml.attribute("genericName") != title)
title += QString(" (%1)").arg(xml.attribute("genericName"));
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;
@ -270,6 +237,5 @@ XdgAction* XdgMenuWidgetPrivate::createAction(const QDomElement& xml)
************************************************/
QString XdgMenuWidgetPrivate::escape(QString string)
{
return string.replace("&", "&&");
return string.replace(QLatin1Char('&'), QLatin1String("&&"));
}

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XDGMENUWIDGET_H
#define QTXDG_XDGMENUWIDGET_H

View File

@ -22,6 +22,7 @@
#include "xdgicon.h"
class XdgMimeTypePrivate : public QSharedData {
public:
XdgMimeTypePrivate();
@ -33,35 +34,41 @@ public:
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);
@ -72,10 +79,12 @@ XdgMimeType &XdgMimeType::operator=(const XdgMimeType &other)
return *this;
}
XdgMimeType::~XdgMimeType()
{
}
QString XdgMimeType::iconName() const
{
if (dx->computed) {
@ -87,7 +96,7 @@ QString XdgMimeType::iconName() const
names.append(QMimeType::iconName());
names.append(QMimeType::genericIconName());
foreach (QString s, names) {
for (const QString &s : const_cast<const QStringList&>(names)) {
if (!XdgIcon::fromTheme(s).isNull()) {
dx->iconName = s;
break;
@ -98,6 +107,7 @@ QString XdgMimeType::iconName() const
}
}
QIcon XdgMimeType::icon() const
{
return XdgIcon::fromTheme((iconName()));

View File

@ -77,7 +77,7 @@ public:
inline bool operator!=(const XdgMimeType &other) const
{
return QMimeType::operator==(other);
return !QMimeType::operator==(other);
}
void swap(XdgMimeType &other)
@ -121,9 +121,6 @@ protected:
};
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
#else
Q_DECLARE_SHARED(XdgMimeType)
#endif
#endif // QTXDG_MIMETYPE_H

View File

@ -33,19 +33,14 @@
#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 += " " + map.item(i).nodeName() + "='" + map.item(i).nodeValue() + "'";
args += QLatin1Char(' ') + map.item(i).nodeName() + QLatin1Char('=') + map.item(i).nodeValue() + QLatin1Char('\'');
dbg.nospace() << QString("<%1%2>%3</%1>").arg(el.tagName()).arg(args).arg(el.text());
dbg.nospace() << QString::fromLatin1("<%1%2>%3</%1>").arg(el.tagName(), args, el.text());
return dbg.space();
}

View File

@ -25,7 +25,6 @@
*
* END_COMMON_COPYRIGHT_HEADER */
#ifndef QTXDG_XMLHELPER_H
#define QTXDG_XMLHELPER_H

View File

@ -1,26 +0,0 @@
PROJECT="libqtxdg"
version="$1"
prefix=$PROJECT-$version
shift
if [[ -z $version ]]; then
>&2 echo "USAGE: $0 <tag>"
exit 1
fi
mkdir -p "dist/$version"
echo "Creating $prefix.tar.gz"
git archive -9 --format tar.gz $version --prefix="$prefix/" > "dist/$version/$prefix.tar.gz"
gpg --armor --detach-sign "dist/$version/$prefix.tar.gz"
echo "Creating $prefix.tar.xz"
git archive -9 --format tar.xz $version --prefix="$prefix/" > "dist/$version/$prefix.tar.xz"
gpg --armor --detach-sign "dist/$version/$prefix.tar.xz"
cd "dist/$version"
sha1sum --tag *.tar.gz *.tar.xz >> CHECKSUMS
sha256sum --tag *.tar.gz *.tar.xz >> CHECKSUMS
cd ..
echo "Uploading to lxqt.org..."
scp -r "$version" "lxde.org:/var/www/lxqt/downloads/$PROJECT/"

View File

@ -1,52 +1,31 @@
set(PROJECT_NAME "qtxdg_test")
set(${PROJECT_NAME}_SRCS
qtxdg_test.cpp
remove_definitions(
-DQT_USE_QSTRINGBUILDER
-DQT_NO_CAST_FROM_ASCII
)
set(${PROJECT_NAME}_MOCS
qtxdg_test.h
add_definitions(
-DQT_NO_KEYWORDS
)
set(LIBRARIES
${QTXDGX_LIBRARY_NAME}
)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
if (BUILD_TESTS)
add_definitions(-DQTXDG_BUILDING_TESTS=1)
endif()
if (USE_QT5)
qt5_wrap_cpp(MOCS ${${PROJECT_NAME}_MOCS})
else()
qt4_wrap_cpp(MOCS ${${PROJECT_NAME}_MOCS})
endif()
include_directories (
${CMAKE_SOURCE_DIR}
)
if (USE_QT5)
add_definitions(${Qt5Test_DEFINITINS})
include_directories (
${Qt5Test_INCLUDE_DIRS}
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"
)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} ${Qt5Test_EXECUTABLE_COMPILE_FLAGS}"
)
else()
include_directories (
${QT_QTCORE_INCLUDE_DIR}
)
endif()
add_test(NAME ${_testname} COMMAND ${_testname})
endforeach()
endmacro()
add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS} )
set_property(DIRECTORY APPEND
PROPERTY COMPILE_DEFINITIONS "QTXDG_BUILDING_TESTS=\"1\""
)
if (USE_QT5)
target_link_libraries ( ${PROJECT_NAME} ${Qt5Test_LIBRARIES} ${LIBRARIES} )
else()
target_link_libraries ( ${PROJECT_NAME} ${QT_LIBRARIES} ${LIBRARIES} )
endif()
add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
qtxdg_add_test(
qtxdg_test
tst_xdgdirs
tst_xdgdesktopfile
)

View File

@ -1,3 +1,33 @@
/* 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"
@ -17,15 +47,17 @@ void QtXdgTest::testDefaultApp()
{
QStringList mimedirs = XdgDirs::dataDirs();
mimedirs.prepend(XdgDirs::dataHome(false));
foreach (QString mimedir, mimedirs)
for (const QString &mimedir : const_cast<const QStringList&>(mimedirs))
{
QDir dir(mimedir + "/mime");
qDebug() << dir.path();
QStringList filters = (QStringList() << "*.xml");
foreach(QFileInfo mediaDir, dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
const QFileInfoList &mediaDirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &mediaDir : mediaDirs)
{
qDebug() << " " << mediaDir.fileName();
foreach (QString mimeXmlFileName, QDir(mediaDir.absoluteFilePath()).entryList(filters, QDir::Files))
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);

View File

@ -1,3 +1,33 @@
/* 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
@ -9,7 +39,7 @@ class QtXdgTest : public QObject
{
Q_OBJECT
private slots:
private Q_SLOTS:
void testCustomFormat();
private:

118
test/tst_xdgdesktopfile.cpp Normal file
View File

@ -0,0 +1,118 @@
/*
* 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"

35
test/tst_xdgdesktopfile.h Normal file
View File

@ -0,0 +1,35 @@
/*
* 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

227
test/tst_xdgdirs.cpp Normal file
View File

@ -0,0 +1,227 @@
/* 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"

52
util/CMakeLists.txt Normal file
View File

@ -0,0 +1,52 @@
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
)

View File

@ -0,0 +1,71 @@
/*
* 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;
}

74
util/qtxdg-iconfinder.cpp Normal file
View File

@ -0,0 +1,74 @@
/*
* 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;
}

View File

@ -1,7 +0,0 @@
#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

View File

@ -0,0 +1,89 @@
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}"
)

View File

@ -0,0 +1,49 @@
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
)

View File

@ -0,0 +1,35 @@
/* 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};
}

View File

@ -0,0 +1,38 @@
/* 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;
};

View File

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

View File

@ -0,0 +1,936 @@
/****************************************************************************
**
** 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

View File

@ -0,0 +1,160 @@
/****************************************************************************
**
** 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

View File

@ -1,366 +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 "xdgmime.h"
#include "xdgicon.h"
#include "xdgdirs.h"
#include <QFileInfo>
#include <magic.h>
#include <QDebug>
#include <QStringList>
#include <QMap>
#include <QDir>
#include <QFileInfo>
#include <QFile>
#include <QDomDocument>
#include <QDomElement>
#include <QSharedData>
struct XdgMimeData
{
public:
XdgMimeData(QString media, QString subtype);
bool readXml(QIODevice* xml);
QString mMedia;
QString mSubtype;
bool mDbLoaded;
QString mComment;
QMap<QString, QString> mLocalizedComments;
QStringList mPatterns;
QString mSubClassOf;
};
/************************************************
************************************************/
XdgMimeInfo::XdgMimeInfo(const QString& mimeType)
{
QString media = mimeType.section('/', 0, 0);
QString subtype = mimeType.section('/', 1);
mData = new XdgMimeData(media, subtype);
}
XdgMimeInfo::~XdgMimeInfo()
{
delete mData;
mData = 0;
}
/************************************************
************************************************/
QString getFileMimeType(const QFileInfo& fileInfo, bool followSymLinks)
{
QString result("application/octet-stream");
magic_t magicMimePredictor;
magicMimePredictor = magic_open(MAGIC_MIME_TYPE); // Open predictor
if (!magicMimePredictor) {
qWarning() << "libmagic: Unable to initialize magic library";
return result;
}
if (magic_load(magicMimePredictor, 0)) { // if not 0 - error
qWarning() << QString("libmagic: Can't load magic database - %1").arg(magic_error(magicMimePredictor));
magic_close(magicMimePredictor); // Close predictor
return result;
}
QByteArray ar = fileInfo.absoluteFilePath().toLocal8Bit();
if (followSymLinks && fileInfo.isSymLink())
{
ar = fileInfo.symLinkTarget().toLocal8Bit();
}
char *file = ar.data();
// getting mime-type ........................
const char *mime;
mime = magic_file(magicMimePredictor, file);
result = QString(mime);
// Close predictor ..........................
magic_close(magicMimePredictor);
return result;
}
/************************************************
************************************************/
XdgMimeInfo::XdgMimeInfo(const QFileInfo& file, bool followSymLinks)
{
QString mimeType = getFileMimeType(file, followSymLinks);
QString media = mimeType.section('/', 0, 0);
QString subtype = mimeType.section('/', 1);
mData = new XdgMimeData(media, subtype);
}
/************************************************
************************************************/
QString XdgMimeInfo::mimeType() const
{
return mData->mMedia + "/" + mData->mSubtype;
}
QString XdgMimeInfo::mediaType() const
{
return mData->mMedia;
}
QString XdgMimeInfo::subType() const
{
return mData->mSubtype;
}
QString XdgMimeInfo::comment() const
{
return mData->mComment;
}
QString XdgMimeInfo::localizedComment() const
{
// FIXME
return mData->mComment;
}
QStringList XdgMimeInfo::patterns() const
{
return mData->mPatterns;
}
/************************************************
************************************************/
QString XdgMimeInfo::iconName() const
{
QStringList names;
names << QString("%1-x-%2").arg(mData->mMedia, mData->mSubtype);
names << QString("%1-%2").arg(mData->mMedia, mData->mSubtype);
names << QString("%1-x-generic").arg(mData->mMedia);
names << QString("%1-generic").arg(mData->mMedia);
foreach (QString s, names)
{
if (!XdgIcon::fromTheme(s).isNull())
return s;
}
return "unknown";
}
/************************************************
************************************************/
QIcon XdgMimeInfo::icon() const
{
return XdgIcon::fromTheme(iconName());
}
QString XdgMimeInfo::subClassOf() const
{
return mData->mSubClassOf;
}
bool XdgMimeInfo::loadFromDb(QIODevice* xml)
{
return mData->readXml(xml);
}
XdgMimeData::XdgMimeData(QString media, QString subtype):
mMedia(media),
mSubtype(subtype),
mDbLoaded(false)
{
}
bool XdgMimeData::readXml(QIODevice* xml)
{
QDomDocument domDocument;
if (! domDocument.setContent(xml, false))
{
return false;
}
QDomElement rootElement = domDocument.documentElement();
if (rootElement.nodeName() != "mime-type")
{
return false;
}
if (rootElement.attribute("type") != mMedia + "/" + mSubtype)
{
return false;
}
QDomNodeList commentNodes = rootElement.elementsByTagName("comment");
for(int i = 0; i < commentNodes.size(); i++)
{
if (! commentNodes.item(i).isElement())
{
continue;
}
QDomElement commentElement = commentNodes.item(i).toElement();
if (commentElement.hasAttribute("xml:lang"))
{
mLocalizedComments[commentElement.attribute("xml:lang")] = commentElement.text();
}
else
{
mComment = commentElement.text();
}
}
QSet<QString> collectedPatterns;
QDomNodeList globNodes = rootElement.elementsByTagName("glob");
for(int i = 0; i < globNodes.size(); i++)
{
if (globNodes.item(i).isElement() && globNodes.item(i).toElement().hasAttribute("pattern"))
{
collectedPatterns << globNodes.item(i).toElement().attribute("pattern");
}
}
mPatterns = collectedPatterns.toList();
mPatterns.sort();
QDomNodeList subClassOfElements = rootElement.elementsByTagName("sub-class-of");
if (subClassOfElements.size() > 0)
{
mSubClassOf = subClassOfElements.at(0).toElement().attribute("type");
}
return true;
}
QStringList XdgMimeInfoCache::mediatypes()
{
return cache().keys();
}
QStringList XdgMimeInfoCache::subtypes(const QString& media)
{
return cache().value(media).keys();
}
XdgMimeInfo* XdgMimeInfoCache::xdgMimeInfo(const QString & media, const QString & subtype)
{
return cache().value(media).value(subtype);
}
XdgMimeInfo* XdgMimeInfoCache::xdgMimeInfo(const QString& mimetype)
{
QString media = mimetype.section("/", 0, 0);
QString subtype = mimetype.section("/", 1, 1);
return xdgMimeInfo(media, subtype);
}
void loadMimeInfoCache(QMap<QString, QMap<QString, XdgMimeInfo*> > & cache)
{
qDebug() << "loadMimeInfoCache";
QStringList datadirs = XdgDirs::dataDirs();
datadirs.prepend(XdgDirs::dataHome(false));
const QStringList filters = (QStringList() << "*.xml");
foreach (const QString datadir, datadirs)
{
QDir mimedir(datadir + "/mime");
if (! mimedir.exists())
{
continue;
}
foreach (QFileInfo mediadirInfo, mimedir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot))
{
QString media = mediadirInfo.fileName();
QDir mediadir(mediadirInfo.absoluteFilePath());
foreach (QFileInfo subtypefileInfo, mediadir.entryInfoList(filters, QDir::Files))
{
QString subtype = subtypefileInfo.fileName().left(subtypefileInfo.fileName().length() - 4);
//qDebug() << "subtype:" << subtype;
QFile subtypefile(subtypefileInfo.absoluteFilePath());
XdgMimeInfo* mimeInfo = new XdgMimeInfo(media + "/" + subtype);
if (subtypefile.open(QIODevice::ReadOnly) && mimeInfo->loadFromDb(&subtypefile))
{
cache[media][subtype] = mimeInfo;
}
else
{
delete mimeInfo;
}
}
}
}
// TESTING
XdgMimeData data("application", "msword");
QFile mswordxml("/usr/share/mime/application/msword.xml");
mswordxml.open(QIODevice::ReadOnly);
data.readXml(&mswordxml);
qDebug() << "=================================================================================";
qDebug() << "data:" << data.mMedia << data.mSubtype << data.mComment << data.mLocalizedComments << data.mPatterns;
qDebug() << "=================================================================================";
}
QMap<QString, QMap<QString, XdgMimeInfo*> > & XdgMimeInfoCache::cache()
{
static QMap<QString, QMap<QString, XdgMimeInfo*> > _cache;
static bool cache_loaded = false;
if (! cache_loaded)
{
loadMimeInfoCache(_cache);
cache_loaded = true;
}
return _cache;
}

View File

@ -1,99 +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_XDGMIME_H
#define QTXDG_XDGMIME_H
#include <QString>
#include <QFileInfo>
#include <QtGui/QIcon>
#include "xdgmacros.h"
struct XdgMimeData;
/*! @brief The XdgMimeInfo class provides mime information about file.
*/
class QTXDG_DEPRECATED QTXDG_API XdgMimeInfo
{
public:
/// Constructs a XdgMimeInfo with the mimeType type.
explicit XdgMimeInfo(const QString& mimeType);
/**
Constructs a new XdgMimeInfo that gives mime information about the given file.
If file is symlink and followSymLinks is true function gives information for the
file the link references rather than for the link itself.
**/
explicit XdgMimeInfo(const QFileInfo& file, bool followSymLinks=true);
~XdgMimeInfo();
/// Returns the name of the mime type.
QString mimeType() const;
/// Returns the media type, eg. 'application' for mimetype 'application/pdf'
QString mediaType() const;
/// Returns the subtype, e.g. 'pdf' for 'application/pdf'
QString subType() const;
QString comment() const;
QString localizedComment() const;
QStringList patterns() const;
/// Returns an icon associated with the mime type.
QIcon icon() const;
/// Returns an icon associated with the mime type.
QString iconName() const;
QString subClassOf() const;
bool loadFromDb(QIODevice* xml);
private:
XdgMimeData *mData;
};
class QTXDG_DEPRECATED QTXDG_API XdgMimeInfoCache
{
public:
static QStringList mediatypes();
static QStringList subtypes(const QString & media);
static XdgMimeInfo* xdgMimeInfo(const QString & media, const QString & subtype);
static XdgMimeInfo* xdgMimeInfo(const QString & mimetype);
private:
static QMap<QString, QMap<QString, XdgMimeInfo*> > & cache();
};
#endif // QTXDG_XDGMIME_H