Adding upstream version 3.0.0.

Signed-off-by: Alf Gaida <agaida@siduction.org>
This commit is contained in:
Alf Gaida 2017-09-23 00:51:06 +02:00
parent 1e3819068c
commit 7abe319414
No known key found for this signature in database
GPG Key ID: CD280A0B4D72827C
40 changed files with 916 additions and 539 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,7 @@ Upstream Authors:
Copyright: Copyright:
Copyright (c) 2010-2012 Razor team Copyright (c) 2010-2012 Razor team
Copyright (c) 2012-2016 LXQt team Copyright (c) 2012-2017 LXQt team
License: LGPL-2.1+ and LGPL-2.1-or-3-with-Digia-1.1-exception 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 full text of the LGPL-2.1+ license can be found in the 'COPYING' file.

View File

@ -1,7 +1,70 @@
libqtxdg-2.0.0 / 2016-09-17 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 * Bump version to 2.0.0
* Extend README.md * Extend README.md
* Updates dependencies * Updates dependencies

View File

@ -25,11 +25,13 @@ else()
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
endif() endif()
set(QTXDG_MAJOR_VERSION 2) set(QTXDG_MAJOR_VERSION 3)
set(QTXDG_MINOR_VERSION 0) set(QTXDG_MINOR_VERSION 0)
set(QTXDG_PATCH_VERSION 0) set(QTXDG_PATCH_VERSION 0)
set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION}) set(QTXDG_VERSION_STRING ${QTXDG_MAJOR_VERSION}.${QTXDG_MINOR_VERSION}.${QTXDG_PATCH_VERSION})
set(QT_MINIMUM_VERSION "5.6.1")
include(GNUInstallDirs) # Standard directories for installation include(GNUInstallDirs) # Standard directories for installation
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
include(GenerateExportHeader) include(GenerateExportHeader)
@ -37,13 +39,12 @@ include(create_portable_headers)
include(create_pkgconfig_file) include(create_pkgconfig_file)
include(compiler_settings NO_POLICY_SCOPE) include(compiler_settings NO_POLICY_SCOPE)
find_package(Qt5Widgets REQUIRED QUIET) set(CMAKE_AUTOMOC ON)
find_package(Qt5Svg REQUIRED QUIET)
find_package(Qt5Xml REQUIRED QUIET) find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Widgets Svg Xml DBus)
find_package(Qt5DBus REQUIRED QUIET)
if (BUILD_TESTS) if (BUILD_TESTS)
find_package(Qt5Test REQUIRED QUIET) find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Test)
endif() endif()
@ -52,12 +53,13 @@ set(QTXDGX_FILE_NAME "qt5xdg")
set(QTXDGX_ICONLOADER_LIBRARY_NAME "Qt5XdgIconLoader") set(QTXDGX_ICONLOADER_LIBRARY_NAME "Qt5XdgIconLoader")
set(QTXDGX_ICONLOADER_FILE_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_DESCRIPTION "Qt5Xdg, a Qt5 implementation of XDG standards")
set(QTXDGX_PKG_CONFIG_REQUIRES "Qt5Core, Qt5Xml, Qt5Widgets, Qt5DBus, Qt5XdgIconLoader") 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_DESCRIPTION "Qt5XdgIconLader, a Qt5 XDG Icon Loader")
set(QTXDGX_ICONLOADER_PKG_CONFIG_REQUIRES "Qt5Gui, Qt5Svg") set(QTXDGX_ICONLOADER_PKG_CONFIG_REQUIRES "Qt5Gui >= ${QT_MINIMUM_VERSION}, Qt5Svg >= ${QT_MINIMUM_VERSION}")
set(QTXDGX_INTREE_INCLUDEDIR "${CMAKE_CURRENT_BINARY_DIR}/InTreeBuild/include") set(QTXDGX_INTREE_INCLUDEDIR "${CMAKE_CURRENT_BINARY_DIR}/InTreeBuild/include")
@ -65,7 +67,7 @@ if (NOT CMAKE_BUILD_TYPE)
set ( CMAKE_BUILD_TYPE Release ) set ( CMAKE_BUILD_TYPE Release )
endif (NOT CMAKE_BUILD_TYPE) endif (NOT CMAKE_BUILD_TYPE)
message(STATUS "Building with Qt ${Qt5Core_VERSION_STRING}") message(STATUS "Building ${PROJECT_NAME} with Qt ${Qt5Core_VERSION}")
add_subdirectory(xdgiconloader) add_subdirectory(xdgiconloader)
add_subdirectory(qtxdg) add_subdirectory(qtxdg)
@ -167,16 +169,5 @@ configure_file(
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY) IMMEDIATE @ONLY)
add_custom_target(uninstall #add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") # COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
# building tarball with CPack -------------------------------------------------
include (InstallRequiredSystemLibraries)
set (CPACK_PACKAGE_VERSION_MAJOR ${QTXDG_MAJOR_VERSION})
set (CPACK_PACKAGE_VERSION_MINOR ${QTXDG_MINOR_VERSION})
set (CPACK_PACKAGE_VERSION_PATCH ${QTXDG_PATCH_VERSION})
set (CPACK_GENERATOR TBZ2)
set (CPACK_SOURCE_GENERATOR TBZ2)
set (CPACK_SOURCE_IGNORE_FILES /build/;.gitignore;.*~;.git;.kdev4;temp)
include (CPack)

View File

@ -1,5 +1,6 @@
#============================================================================= #=============================================================================
# Copyright 2015 Luís Pereira <luis.artur.pereira@gmail.com> # 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 # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions # modification, are permitted provided that the following conditions
@ -65,6 +66,14 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
endif() 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 # Set visibility to hidden to hide symbols, unless they're exported manually
# in the code # in the code
@ -80,18 +89,25 @@ if (CMAKE_COMPILER_IS_GNUCXX OR QTXDG_COMPILER_IS_CLANGCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
endif() endif()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Common warning flags # Common warning flags
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
set(QTXDG_COMMON_WARNING_FLAGS "-Wall") set(QTXDG_COMMON_WARNING_FLAGS "-Wall -Wextra -Wchar-subscripts -Wno-long-long -Wpointer-arith -Wundef -Wformat-security")
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Warning flags # 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}) list(APPEND QTXDG_WARNING_FLAGS ${QTXDG_COMMON_WARNING_FLAGS})
add_definitions(${QTXDG_WARNING_FLAGS})
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# String conversion flags # String conversion flags
@ -103,3 +119,53 @@ add_definitions(
-DQT_NO_URL_CAST_FROM_STRING -DQT_NO_URL_CAST_FROM_STRING
-DQT_NO_CAST_FROM_BYTEARRAY -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,13 +1,15 @@
@PACKAGE_INIT@ @PACKAGE_INIT@
if (NOT TARGET @QTXDGX_LIBRARY_NAME@)
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
find_dependency(Qt5Widgets) find_dependency(Qt5Widgets @QT_MINIMUM_VERSION@)
find_dependency(Qt5Xml) find_dependency(Qt5Xml @QT_MINIMUM_VERSION@)
find_dependency(Qt5DBus) find_dependency(Qt5DBus @QT_MINIMUM_VERSION@)
find_dependency(Qt5XdgIconLoader) find_dependency(Qt5XdgIconLoader @QTXDG_VERSION_STRING@ EXACT)
if (CMAKE_VERSION VERSION_GREATER 2.8.12) if (CMAKE_VERSION VERSION_GREATER 2.8.12)
cmake_policy(SET CMP0024 OLD) cmake_policy(SET CMP0024 NEW)
endif() endif()
include("${CMAKE_CURRENT_LIST_DIR}/qt5xdg-targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/qt5xdg-targets.cmake")
endif()

View File

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

View File

@ -1,8 +1,5 @@
set(QTX_LIBRARIES Qt5::Widgets Qt5::Xml Qt5::DBus) set(QTX_LIBRARIES Qt5::Widgets Qt5::Xml Qt5::DBus)
include_directories(
"${Qt5Gui_PRIVATE_INCLUDE_DIRS}"
)
set(libqtxdg_PUBLIC_H_FILES set(libqtxdg_PUBLIC_H_FILES
xdgaction.h xdgaction.h
xdgdesktopfile.h xdgdesktopfile.h
@ -63,14 +60,11 @@ set(libqtxdg_MOCS
xdgmenuwidget.h xdgmenuwidget.h
) )
QT5_WRAP_CPP(libqtxdg_CXX_FILES ${libqtxdg_MOCS})
add_library(${QTXDGX_LIBRARY_NAME} SHARED add_library(${QTXDGX_LIBRARY_NAME} SHARED
${libqtxdg_PUBLIC_H_FILES} ${libqtxdg_PUBLIC_H_FILES}
${libqtxdg_PRIVATE_H_FILES} ${libqtxdg_PRIVATE_H_FILES}
${libqtxdg_PRIVATE_H_FILES}
${libqtxdg_CPP_FILES} ${libqtxdg_CPP_FILES}
${libqtxdg_CXX_FILES} ${libqtxdg_MOCS}
) )
target_link_libraries(${QTXDGX_LIBRARY_NAME} target_link_libraries(${QTXDGX_LIBRARY_NAME}
@ -85,24 +79,22 @@ set_target_properties(${QTXDGX_LIBRARY_NAME} PROPERTIES
) )
target_compile_definitions(${QTXDGX_LIBRARY_NAME} target_compile_definitions(${QTXDGX_LIBRARY_NAME}
PRIVATE "QTXDG_COMPILATION=\"1\"" PRIVATE
PRIVATE "QTXDG_VERSION=\"${QTXDG_VERSION_STRING}\"" "QTXDG_COMPILATION=\"1\""
"QTXDG_VERSION=\"${QTXDG_VERSION_STRING}\""
"QT_NO_KEYWORDS"
) )
target_include_directories(${QTXDGX_LIBRARY_NAME} target_include_directories(${QTXDGX_LIBRARY_NAME}
INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_FILE_NAME}>" INTERFACE
INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" "$<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}
) )
# include directories and targets for the in tree build
target_include_directories(${QTXDGX_LIBRARY_NAME}
INTERFACE "$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_FILE_NAME}>"
INTERFACE "$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}>"
)
export(TARGETS ${QTXDGX_LIBRARY_NAME} APPEND FILE "${CMAKE_BINARY_DIR}/${QTXDGX_FILE_NAME}-targets.cmake")
# end of in tree build stuff
# create the portble headers # create the portble headers
create_portable_headers(libqtxdg_PORTABLE_HEADERS create_portable_headers(libqtxdg_PORTABLE_HEADERS
HEADER_NAMES ${libqtxdg_PUBLIC_CLASSES} HEADER_NAMES ${libqtxdg_PUBLIC_CLASSES}

View File

@ -71,7 +71,7 @@ public:
const XdgDesktopFile& desktopFile() const { return mDesktopFile; } const XdgDesktopFile& desktopFile() const { return mDesktopFile; }
private slots: private Q_SLOTS:
void runConmmand() const; void runConmmand() const;
void updateIcon(); void updateIcon();

View File

@ -57,14 +57,14 @@ XdgDesktopFileList XdgAutoStart::desktopFileList(QStringList dirs, bool excludeH
QSet<QString> processed; QSet<QString> processed;
XdgDesktopFileList ret; XdgDesktopFileList ret;
foreach (const QString &dirName, dirs) for (const QString &dirName : const_cast<const QStringList&>(dirs))
{ {
QDir dir(dirName); QDir dir(dirName);
if (!dir.exists()) if (!dir.exists())
continue; continue;
const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files | QDir::Readable); const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files | QDir::Readable);
foreach (const QFileInfo &fi, files) for (const QFileInfo &fi : files)
{ {
if (processed.contains(fi.fileName())) if (processed.contains(fi.fileName()))
continue; continue;

View File

@ -409,9 +409,9 @@ bool XdgDesktopFileData::startApplicationDetached(const XdgDesktopFile *q, const
} }
bool nonDetach = false; bool nonDetach = false;
foreach(const QString &s, nonDetachExecs) for (const QString &s : nonDetachExecs)
{ {
foreach(const QString &a, args) for (const QString &a : const_cast<const QStringList&>(args))
{ {
if (a.contains(s)) if (a.contains(s))
{ {
@ -953,7 +953,7 @@ QString expandEnvVariables(const QString str)
QStringList expandEnvVariables(const QStringList strs) QStringList expandEnvVariables(const QStringList strs)
{ {
QStringList res; QStringList res;
foreach(const QString &s, strs) for (const QString &s : strs)
res << expandEnvVariables(s); res << expandEnvVariables(s);
return res; return res;
@ -969,9 +969,9 @@ QStringList XdgDesktopFile::expandExecString(const QStringList& urls) const
QString execStr = value(execKey).toString(); QString execStr = value(execKey).toString();
unEscapeExec(execStr); unEscapeExec(execStr);
QStringList tokens = parseCombinedArgString(execStr); const QStringList tokens = parseCombinedArgString(execStr);
foreach (QString token, tokens) for (QString token : tokens)
{ {
// The parseCombinedArgString() splits the string by the space symbols, // The parseCombinedArgString() splits the string by the space symbols,
// we temporarily replaced them on the special characters. // we temporarily replaced them on the special characters.
@ -1016,7 +1016,7 @@ QStringList XdgDesktopFile::expandExecString(const QStringList& urls) const
// program. Local files may either be passed as file: URLs or as file path. // program. Local files may either be passed as file: URLs or as file path.
if (token == QLatin1String("%U")) if (token == QLatin1String("%U"))
{ {
foreach (const QString &s, urls) for (const QString &s : urls)
{ {
QUrl url(expandEnvVariables(s)); QUrl url(expandEnvVariables(s));
result << ((!url.toLocalFile().isEmpty()) ? url.toLocalFile() : QString::fromUtf8(url.toEncoded())); result << ((!url.toLocalFile().isEmpty()) ? url.toLocalFile() : QString::fromUtf8(url.toEncoded()));
@ -1079,9 +1079,9 @@ bool checkTryExec(const QString& progName)
if (progName.startsWith(QDir::separator())) if (progName.startsWith(QDir::separator()))
return QFileInfo(progName).isExecutable(); return QFileInfo(progName).isExecutable();
QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':')); const QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':'));
foreach (const QString &dir, dirs) for (const QString &dir : dirs)
{ {
if (QFileInfo(QDir(dir), progName).isExecutable()) if (QFileInfo(QDir(dir), progName).isExecutable())
return true; return true;
@ -1103,7 +1103,7 @@ QString XdgDesktopFile::id(const QString &fileName, bool checkFileExists)
QString id = f.absoluteFilePath(); QString id = f.absoluteFilePath();
const QStringList dataDirs = XdgDirs::dataDirs(); const QStringList dataDirs = XdgDirs::dataDirs();
foreach(const QString &d, dataDirs) { for (const QString &d : dataDirs) {
if (id.startsWith(d)) { if (id.startsWith(d)) {
// remove only the first occurence // remove only the first occurence
id.replace(id.indexOf(d), d.size(), QString()); id.replace(id.indexOf(d), d.size(), QString());
@ -1211,7 +1211,8 @@ bool XdgDesktopFile::isSuitable(bool excludeHidden, const QString &environment)
QString expandDynamicUrl(QString url) QString expandDynamicUrl(QString url)
{ {
foreach(const QString &line, QProcess::systemEnvironment()) const QStringList env = QProcess::systemEnvironment();
for (const QString &line : env)
{ {
QString name = line.section(QLatin1Char('='), 0, 0); QString name = line.section(QLatin1Char('='), 0, 0);
QString val = line.section(QLatin1Char('='), 1); QString val = line.section(QLatin1Char('='), 1);
@ -1252,8 +1253,8 @@ QString findDesktopFile(const QString& dirName, const QString& desktopName)
return fi.canonicalFilePath(); return fi.canonicalFilePath();
// Working recursively ............ // Working recursively ............
QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); const QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QFileInfo &d, dirs) for (const QFileInfo &d : dirs)
{ {
QString cn = d.canonicalFilePath(); QString cn = d.canonicalFilePath();
if (dirName != cn) if (dirName != cn)
@ -1273,7 +1274,7 @@ QString findDesktopFile(const QString& desktopName)
QStringList dataDirs = XdgDirs::dataDirs(); QStringList dataDirs = XdgDirs::dataDirs();
dataDirs.prepend(XdgDirs::dataHome(false)); dataDirs.prepend(XdgDirs::dataHome(false));
foreach (const QString &dirName, dataDirs) for (const QString &dirName : const_cast<const QStringList&>(dataDirs))
{ {
QString f = findDesktopFile(dirName + QLatin1String("/applications"), desktopName); QString f = findDesktopFile(dirName + QLatin1String("/applications"), desktopName);
if (!f.isEmpty()) if (!f.isEmpty())
@ -1415,14 +1416,14 @@ bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map)
QTextStream stream(&device); QTextStream stream(&device);
QString section; QString section;
foreach (const QString &key, map.keys()) for (auto it = map.constBegin(); it != map.constEnd(); ++it)
{ {
if (! map.value(key).canConvert<QString>()) if (! it.value().canConvert<QString>())
{ {
return false; return false;
} }
QString thisSection = key.section(QLatin1Char('/'), 0, 0); QString thisSection = it.key().section(QLatin1Char('/'), 0, 0);
if (thisSection.isEmpty()) if (thisSection.isEmpty())
{ {
qWarning() << "No section defined"; qWarning() << "No section defined";
@ -1435,7 +1436,7 @@ bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map)
section = thisSection; section = thisSection;
} }
QString remainingKey = key.section(QLatin1Char('/'), 1, -1); QString remainingKey = it.key().section(QLatin1Char('/'), 1, -1);
if (remainingKey.isEmpty()) if (remainingKey.isEmpty())
{ {
@ -1443,7 +1444,7 @@ bool writeDesktopFile(QIODevice & device, const QSettings::SettingsMap & map)
return false; return false;
} }
stream << remainingKey << QLatin1Char('=') << map.value(key).toString() << QLatin1Char('\n'); stream << remainingKey << QLatin1Char('=') << it.value().toString() << QLatin1Char('\n');
} }
@ -1461,8 +1462,8 @@ void XdgDesktopFileCache::initialize(const QString& dirName)
// Working recursively ............ // Working recursively ............
QFileInfoList files = dir.entryInfoList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); const QFileInfoList files = dir.entryInfoList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QFileInfo &f, files) for (const QFileInfo &f : files)
{ {
if (f.isDir()) if (f.isDir())
{ {
@ -1480,9 +1481,9 @@ void XdgDesktopFileCache::initialize(const QString& dirName)
m_fileCache.insert(f.absoluteFilePath(), df); m_fileCache.insert(f.absoluteFilePath(), df);
} }
QStringList mimes = df->value(mimeTypeKey).toString().split(QLatin1Char(';'), QString::SkipEmptyParts); const QStringList mimes = df->value(mimeTypeKey).toString().split(QLatin1Char(';'), QString::SkipEmptyParts);
foreach (const QString &mime, mimes) for (const QString &mime : mimes)
{ {
int pref = df->value(initialPreferenceKey, 0).toInt(); int pref = df->value(initialPreferenceKey, 0).toInt();
// We move the desktopFile forward in the list for this mime, so that // We move the desktopFile forward in the list for this mime, so that
@ -1522,8 +1523,8 @@ void loadMimeCacheDir(const QString& dirName, QHash<QString, QList<XdgDesktopFil
// Working recursively ............ // Working recursively ............
QFileInfoList files = dir.entryInfoList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); const QFileInfoList files = dir.entryInfoList(QStringList(), QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QFileInfo &f, files) for (const QFileInfo &f : files)
{ {
if (f.isDir()) if (f.isDir())
{ {
@ -1536,9 +1537,9 @@ void loadMimeCacheDir(const QString& dirName, QHash<QString, QList<XdgDesktopFil
if (!df) if (!df)
continue; continue;
QStringList mimes = df->value(mimeTypeKey).toString().split(QLatin1Char(';'), QString::SkipEmptyParts); const QStringList mimes = df->value(mimeTypeKey).toString().split(QLatin1Char(';'), QString::SkipEmptyParts);
foreach (const QString &mime, mimes) for (const QString &mime : mimes)
{ {
int pref = df->value(initialPreferenceKey, 0).toInt(); int pref = df->value(initialPreferenceKey, 0).toInt();
// We move the desktopFile forward in the list for this mime, so that // We move the desktopFile forward in the list for this mime, so that
@ -1582,7 +1583,7 @@ void XdgDesktopFileCache::initialize()
QStringList dataDirs = XdgDirs::dataDirs(); QStringList dataDirs = XdgDirs::dataDirs();
dataDirs.prepend(XdgDirs::dataHome(false)); dataDirs.prepend(XdgDirs::dataHome(false));
foreach (const QString &dirname, dataDirs) for (const QString &dirname : const_cast<const QStringList&>(dataDirs))
{ {
initialize(dirname + QLatin1String("/applications")); initialize(dirname + QLatin1String("/applications"));
// loadMimeCacheDir(dirname + "/applications", m_defaultAppsCache); // loadMimeCacheDir(dirname + "/applications", m_defaultAppsCache);
@ -1593,7 +1594,8 @@ QList<XdgDesktopFile*> XdgDesktopFileCache::getAppsOfCategory(const QString& cat
{ {
QList<XdgDesktopFile*> list; QList<XdgDesktopFile*> list;
const QString _category = category.toUpper(); const QString _category = category.toUpper();
foreach (XdgDesktopFile *desktopFile, instance().m_fileCache.values()) const QHash<QString, XdgDesktopFile*> fileCache = instance().m_fileCache;
for (XdgDesktopFile *desktopFile : fileCache)
{ {
QStringList categories = desktopFile->value(categoriesKey).toString().toUpper().split(QLatin1Char(';')); QStringList categories = desktopFile->value(categoriesKey).toString().toUpper().split(QLatin1Char(';'));
if (!categories.isEmpty() && (categories.contains(_category) || categories.contains(QLatin1String("X-") + _category))) if (!categories.isEmpty() && (categories.contains(_category) || categories.contains(QLatin1String("X-") + _category)))
@ -1614,10 +1616,10 @@ XdgDesktopFile* XdgDesktopFileCache::getDefaultApp(const QString& mimetype)
// /usr/share/applications/mimeapps.list (in that order) for a default. // /usr/share/applications/mimeapps.list (in that order) for a default.
QStringList dataDirs = XdgDirs::dataDirs(); QStringList dataDirs = XdgDirs::dataDirs();
dataDirs.prepend(XdgDirs::dataHome(false)); dataDirs.prepend(XdgDirs::dataHome(false));
foreach(const QString &dataDir, dataDirs) for (const QString &dataDir : const_cast<const QStringList&>(dataDirs))
{ {
QString defaultsListPath = dataDir + QLatin1String("/applications/mimeapps.list"); QString defaultsListPath = dataDir + QLatin1String("/applications/mimeapps.list");
if (QFileInfo(defaultsListPath).exists()) if (QFileInfo::exists(defaultsListPath))
{ {
QSettings defaults(defaultsListPath, desktopFileSettingsFormat()); QSettings defaults(defaultsListPath, desktopFileSettingsFormat());
@ -1628,7 +1630,8 @@ XdgDesktopFile* XdgDesktopFileCache::getDefaultApp(const QString& mimetype)
QVariant value = defaults.value(mimetype); QVariant value = defaults.value(mimetype);
if (value.canConvert<QStringList>()) // A single string can also convert to a stringlist if (value.canConvert<QStringList>()) // A single string can also convert to a stringlist
{ {
foreach (const QString &desktopFileName, value.toStringList()) const QStringList values = value.toStringList();
for (const QString &desktopFileName : values)
{ {
XdgDesktopFile* desktopFile = XdgDesktopFileCache::getFile(desktopFileName); XdgDesktopFile* desktopFile = XdgDesktopFileCache::getFile(desktopFileName);
if (desktopFile) if (desktopFile)

View File

@ -108,7 +108,7 @@ QString userDirFallback(XdgDirs::UserDirectory dir)
if (home.isEmpty()) if (home.isEmpty())
return QString::fromLatin1("/tmp"); return QString::fromLatin1("/tmp");
else if (dir == XdgDirs::Desktop) else if (dir == XdgDirs::Desktop)
fallback = QString::fromLatin1("%1/%2").arg(home).arg(QLatin1String("Desktop")); fallback = QString::fromLatin1("%1/%2").arg(home, QLatin1String("Desktop"));
else else
fallback = home; fallback = home;
@ -178,9 +178,11 @@ bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool
if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos) if (dir < XdgDirs::Desktop || dir > XdgDirs::Videos)
return false; return false;
const QString home = QFile::decodeName(qgetenv("HOME"));
if (!(value.startsWith(QLatin1String("$HOME")) if (!(value.startsWith(QLatin1String("$HOME"))
|| value.startsWith(QLatin1String("~/")) || value.startsWith(QLatin1String("~/"))
|| value.startsWith(QFile::decodeName(qgetenv("HOME"))))) || value.startsWith(home)
|| value.startsWith(QDir(home).canonicalPath())))
return false; return false;
QString folderName = userDirectoryString[dir]; QString folderName = userDirectoryString[dir];
@ -215,7 +217,7 @@ bool XdgDirs::setUserDir(XdgDirs::UserDirectory dir, const QString& value, bool
stream.reset(); stream.reset();
configFile.resize(0); configFile.resize(0);
if (!foundVar) if (!foundVar)
stream << QString::fromLatin1("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) for (QVector<QString>::iterator i = lines.begin(); i != lines.end(); ++i)
stream << *i << QLatin1Char('\n'); stream << *i << QLatin1Char('\n');
@ -334,7 +336,7 @@ QStringList XdgDirs::autostartDirs(const QString &postfix)
{ {
QStringList dirs; QStringList dirs;
const QStringList s = configDirs(); const QStringList s = configDirs();
foreach(const QString &dir, s) for (const QString &dir : s)
dirs << QString::fromLatin1("%1/autostart").arg(dir) + postfix; dirs << QString::fromLatin1("%1/autostart").arg(dir) + postfix;
return dirs; return dirs;

View File

@ -50,7 +50,7 @@ struct QtIconCache: public IconCache
} }
}; };
} }
Q_GLOBAL_STATIC(IconCache, qtIconCache); Q_GLOBAL_STATIC(IconCache, qtIconCache)
static void qt_cleanup_icon_cache() static void qt_cleanup_icon_cache()
{ {
@ -68,25 +68,6 @@ 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);
XdgIconLoader::instance()->updateSystemTheme();
}
/************************************************ /************************************************
Returns the QIcon corresponding to name in the current icon theme. If no such icon 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. is found in the current theme fallback is return instead.
@ -137,7 +118,7 @@ QIcon XdgIcon::fromTheme(const QString& iconName, const QIcon& fallback)
************************************************/ ************************************************/
QIcon XdgIcon::fromTheme(const QStringList& iconNames, const QIcon& fallback) QIcon XdgIcon::fromTheme(const QStringList& iconNames, const QIcon& fallback)
{ {
foreach (const QString &iconName, iconNames) for (const QString &iconName : iconNames)
{ {
QIcon icon = fromTheme(iconName); QIcon icon = fromTheme(iconName);
if (!icon.isNull()) if (!icon.isNull())
@ -164,6 +145,17 @@ QIcon XdgIcon::fromTheme(const QString &iconName,
return fromTheme(icons); return fromTheme(icons);
} }
bool XdgIcon::followColorScheme()
{
return XdgIconLoader::instance()->followColorScheme();
}
void XdgIcon::setFollowColorScheme(bool enable)
{
XdgIconLoader::instance()->setFollowColorScheme(enable);
}
QIcon XdgIcon::defaultApplicationIcon() QIcon XdgIcon::defaultApplicationIcon()
{ {

View File

@ -44,8 +44,19 @@ public:
const QString &fallbackIcon4 = QString()); const QString &fallbackIcon4 = QString());
static QIcon fromTheme(const QStringList& iconNames, const QIcon& fallback = QIcon()); 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 QIcon defaultApplicationIcon();
static QString defaultApplicationIconName(); static QString defaultApplicationIconName();

View File

@ -205,8 +205,7 @@ void XdgMenu::save(const QString& fileName)
if (!file.open(QFile::WriteOnly | QFile::Text)) if (!file.open(QFile::WriteOnly | QFile::Text))
{ {
qWarning() << QString::fromLatin1("Cannot write file %1:\n%2.") qWarning() << QString::fromLatin1("Cannot write file %1:\n%2.")
.arg(fileName) .arg(fileName, file.errorString());
.arg(file.errorString());
return; return;
} }
@ -225,7 +224,7 @@ void XdgMenuPrivate::load(const QString& fileName)
QFile file(fileName); QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) if (!file.open(QFile::ReadOnly | QFile::Text))
{ {
qWarning() << QString::fromLatin1("%1 not loading: %2").arg(fileName).arg(file.errorString()); qWarning() << QString::fromLatin1("%1 not loading: %2").arg(fileName, file.errorString());
return; return;
} }
mXml.setContent(&file, true); mXml.setContent(&file, true);
@ -413,7 +412,7 @@ QDomElement XdgMenu::findMenu(QDomElement& baseElement, const QString& path, boo
const QStringList names = path.split(QLatin1Char('/'), QString::SkipEmptyParts); const QStringList names = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
QDomElement el = baseElement; QDomElement el = baseElement;
foreach (const QString &name, names) for (const QString &name : names)
{ {
QDomElement p = el; QDomElement p = el;
el = d->mXml.createElement(QLatin1String("Menu")); el = d->mXml.createElement(QLatin1String("Menu"));
@ -538,12 +537,12 @@ void XdgMenuPrivate::processDirectoryEntries(QDomElement& element, const QString
dirs << parentDirs; dirs << parentDirs;
bool found = false; bool found = false;
foreach(const QString &file, files){ for (const QString &file : const_cast<const QStringList&>(files)){
if (file.startsWith(QLatin1Char('/'))) if (file.startsWith(QLatin1Char('/')))
found = loadDirectoryFile(file, element); found = loadDirectoryFile(file, element);
else else
{ {
foreach (const QString &dir, dirs) for (const QString &dir : const_cast<const QStringList&>(dirs))
{ {
found = loadDirectoryFile(dir + QLatin1Char('/') + file, element); found = loadDirectoryFile(dir + QLatin1Char('/') + file, element);
if (found) break; if (found) break;
@ -652,7 +651,7 @@ QString XdgMenu::getMenuFileName(const QString& baseName)
const QStringList configDirs = XdgDirs::configDirs(); const QStringList configDirs = XdgDirs::configDirs();
QString menuPrefix = QString::fromLocal8Bit(qgetenv("XDG_MENU_PREFIX")); QString menuPrefix = QString::fromLocal8Bit(qgetenv("XDG_MENU_PREFIX"));
foreach(const QString &configDir, configDirs) for (const QString &configDir : configDirs)
{ {
QFileInfo file(QString::fromLatin1("%1/menus/%2%3").arg(configDir, menuPrefix, baseName)); QFileInfo file(QString::fromLatin1("%1/menus/%2%3").arg(configDir, menuPrefix, baseName));
if (file.exists()) if (file.exists())
@ -670,9 +669,9 @@ QString XdgMenu::getMenuFileName(const QString& baseName)
wellKnownFiles << QLatin1String("gnome-applications.menu"); wellKnownFiles << QLatin1String("gnome-applications.menu");
wellKnownFiles << QLatin1String("lxde-applications.menu"); wellKnownFiles << QLatin1String("lxde-applications.menu");
foreach(const QString &configDir, configDirs) for (const QString &configDir : configDirs)
{ {
foreach (const QString &f, wellKnownFiles) for (const QString &f : const_cast<const QStringList&>(wellKnownFiles))
{ {
QFileInfo file(QString::fromLatin1("%1/menus/%2").arg(configDir, f)); QFileInfo file(QString::fromLatin1("%1/menus/%2").arg(configDir, f));
if (file.exists()) if (file.exists())
@ -715,7 +714,7 @@ void XdgMenuPrivate::rebuild()
if (prevHash != mHash) if (prevHash != mHash)
{ {
mOutDated = true; mOutDated = true;
emit changed(); Q_EMIT changed();
} }
} }

View File

@ -112,7 +112,7 @@ public:
bool isOutDated() const; bool isOutDated() const;
signals: Q_SIGNALS:
void changed(); void changed();
protected: protected:

View File

@ -73,10 +73,10 @@ public:
QFileSystemWatcher mWatcher; QFileSystemWatcher mWatcher;
bool mOutDated; bool mOutDated;
public slots: public Q_SLOTS:
void rebuild(); void rebuild();
signals: Q_SIGNALS:
void changed(); void changed();

View File

@ -90,7 +90,8 @@ void XdgMenuApplinkProcessor::step1()
} }
// Process childs menus ............................... // Process childs menus ...............................
foreach (XdgMenuApplinkProcessor* child, mChilds)
for (XdgMenuApplinkProcessor* child : const_cast<const QLinkedList<XdgMenuApplinkProcessor*>&>(mChilds))
child->step1(); child->step1();
} }
@ -100,7 +101,7 @@ void XdgMenuApplinkProcessor::step2()
// Create AppLinks elements ........................... // Create AppLinks elements ...........................
QDomDocument doc = mElement.ownerDocument(); QDomDocument doc = mElement.ownerDocument();
foreach (XdgMenuAppFileInfo* fileInfo, mSelected) for (XdgMenuAppFileInfo* fileInfo : const_cast<const QLinkedList<XdgMenuAppFileInfo*>&>(mSelected))
{ {
if (mOnlyUnallocated && fileInfo->allocated()) if (mOnlyUnallocated && fileInfo->allocated())
continue; continue;
@ -141,7 +142,7 @@ void XdgMenuApplinkProcessor::step2()
// Process childs menus ............................... // Process childs menus ...............................
foreach (XdgMenuApplinkProcessor* child, mChilds) for (XdgMenuApplinkProcessor* child : const_cast<const QLinkedList<XdgMenuApplinkProcessor*>&>(mChilds))
child->step2(); child->step2();
} }
@ -189,7 +190,7 @@ void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QSt
mMenu->addWatchPath(dir.absolutePath()); mMenu->addWatchPath(dir.absolutePath());
const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files); const QFileInfoList files = dir.entryInfoList(QStringList(QLatin1String("*.desktop")), QDir::Files);
foreach (const QFileInfo &file, files) for (const QFileInfo &file : files)
{ {
XdgDesktopFile* f = XdgDesktopFileCache::getFile(file.canonicalFilePath()); XdgDesktopFile* f = XdgDesktopFileCache::getFile(file.canonicalFilePath());
if (f) if (f)
@ -199,7 +200,7 @@ void XdgMenuApplinkProcessor::findDesktopFiles(const QString& dirName, const QSt
// Working recursively ............ // Working recursively ............
const QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); const QFileInfoList dirs = dir.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QFileInfo &d, dirs) for (const QFileInfo &d : dirs)
{ {
QString dn = d.canonicalFilePath(); QString dn = d.canonicalFilePath();
if (dn != dirName) if (dn != dirName)
@ -242,7 +243,7 @@ bool XdgMenuApplinkProcessor::checkTryExec(const QString& progName)
const QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':')); const QStringList dirs = QFile::decodeName(qgetenv("PATH")).split(QLatin1Char(':'));
foreach (const QString &dir, dirs) for (const QString &dir : dirs)
{ {
if (QFileInfo(QDir(dir), progName).isExecutable()) if (QFileInfo(QDir(dir), progName).isExecutable())
return true; return true;

View File

@ -76,7 +76,7 @@ bool XdgMenuReader::load(const QString& fileName, const QString& baseDir)
QFile file(mFileName); QFile file(mFileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) if (!file.open(QFile::ReadOnly | QFile::Text))
{ {
mErrorStr = QString::fromLatin1("%1 not loading: %2").arg(fileName).arg(file.errorString()); mErrorStr = QString::fromLatin1("%1 not loading: %2").arg(fileName, file.errorString());
return false; return false;
} }
//qDebug() << "Load file:" << mFileName; //qDebug() << "Load file:" << mFileName;
@ -215,7 +215,7 @@ void XdgMenuReader::processMergeFileTag(QDomElement& element, QStringList* merge
QString relativeName; QString relativeName;
QStringList configDirs = XdgDirs::configDirs(); QStringList configDirs = XdgDirs::configDirs();
foreach (const QString &configDir, configDirs) for (const QString &configDir : const_cast<const QStringList&>(configDirs))
{ {
if (mFileName.startsWith(configDir)) if (mFileName.startsWith(configDir))
{ {
@ -236,9 +236,9 @@ void XdgMenuReader::processMergeFileTag(QDomElement& element, QStringList* merge
if (relativeName.isEmpty()) if (relativeName.isEmpty())
return; return;
foreach (const QString &configDir, configDirs) for (const QString &configDir : configDirs)
{ {
if (QFileInfo(configDir + relativeName).exists()) if (QFileInfo::exists(configDir + relativeName))
{ {
mergeFile(configDir + relativeName, element, mergedFiles); mergeFile(configDir + relativeName, element, mergedFiles);
return; return;
@ -295,9 +295,9 @@ void XdgMenuReader::processDefaultMergeDirsTag(QDomElement& element, QStringList
QStringList dirs = XdgDirs::configDirs(); QStringList dirs = XdgDirs::configDirs();
dirs << XdgDirs::configHome(); dirs << XdgDirs::configHome();
foreach (const QString &dir, dirs) for (const QString &dir : const_cast<const QStringList&>(dirs))
{ {
mergeDir(QString::fromLatin1("%1/menus/%2-merged").arg(dir).arg(menuBaseName), element, mergedFiles); mergeDir(QString::fromLatin1("%1/menus/%2-merged").arg(dir, menuBaseName), element, mergedFiles);
} }
if (menuBaseName == QLatin1String("applications")) if (menuBaseName == QLatin1String("applications"))
@ -329,7 +329,7 @@ void XdgMenuReader::processDefaultAppDirsTag(QDomElement& element)
QStringList dirs = XdgDirs::dataDirs(); QStringList dirs = XdgDirs::dataDirs();
dirs.prepend(XdgDirs::dataHome(false)); dirs.prepend(XdgDirs::dataHome(false));
foreach (const QString &dir, dirs) for (const QString &dir : const_cast<const QStringList&> (dirs))
{ {
//qDebug() << "Add AppDir: " << dir + "/applications/"; //qDebug() << "Add AppDir: " << dir + "/applications/";
addDirTag(element, QLatin1String("AppDir"), dir + QLatin1String("/applications/")); addDirTag(element, QLatin1String("AppDir"), dir + QLatin1String("/applications/"));
@ -360,7 +360,7 @@ void XdgMenuReader::processDefaultDirectoryDirsTag(QDomElement& element)
QStringList dirs = XdgDirs::dataDirs(); QStringList dirs = XdgDirs::dataDirs();
dirs.prepend(XdgDirs::dataHome(false)); dirs.prepend(XdgDirs::dataHome(false));
foreach (const QString &dir, dirs) for (const QString &dir : const_cast<const QStringList&>(dirs))
addDirTag(element, QLatin1String("DirectoryDir"), dir + QLatin1String("/desktop-directories/")); addDirTag(element, QLatin1String("DirectoryDir"), dir + QLatin1String("/desktop-directories/"));
} }
@ -379,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 If fileName is not an absolute path then the file to be merged should be located
relative to the location of this menu file. relative to the location of this menu file.
************************************************/ ************************************************/
@ -431,7 +430,7 @@ void XdgMenuReader::mergeDir(const QString& dirName, QDomElement& element, QStri
QDir dir = QDir(dirInfo.canonicalFilePath()); QDir dir = QDir(dirInfo.canonicalFilePath());
const QFileInfoList files = dir.entryInfoList(QStringList() << QLatin1String("*.menu"), QDir::Files | QDir::Readable); const QFileInfoList files = dir.entryInfoList(QStringList() << QLatin1String("*.menu"), QDir::Files | QDir::Readable);
foreach (const QFileInfo &file, files) for (const QFileInfo &file : files)
mergeFile(file.canonicalFilePath(), element, mergedFiles); mergeFile(file.canonicalFilePath(), element, mergedFiles);
} }
} }

View File

@ -47,9 +47,9 @@ public:
QString errorString() const { return mErrorStr; } QString errorString() const { return mErrorStr; }
QDomDocument& xml() { return mXml; } QDomDocument& xml() { return mXml; }
signals: Q_SIGNALS:
public slots: public Q_SLOTS:
protected: protected:
void processMergeTags(QDomElement& element); void processMergeTags(QDomElement& element);

View File

@ -44,7 +44,7 @@ class XdgMenuWidgetPrivate
{ {
private: private:
XdgMenuWidget* const q_ptr; XdgMenuWidget* const q_ptr;
Q_DECLARE_PUBLIC(XdgMenuWidget); Q_DECLARE_PUBLIC(XdgMenuWidget)
public: public:
explicit XdgMenuWidgetPrivate(XdgMenuWidget* parent): explicit XdgMenuWidgetPrivate(XdgMenuWidget* parent):
@ -186,7 +186,7 @@ void XdgMenuWidgetPrivate::buildMenu()
QAction* first = 0; QAction* first = 0;
if (!q->actions().isEmpty()) if (!q->actions().isEmpty())
first = q->actions().last(); first = q->actions().constLast();
DomElementIterator it(mXml, QString()); DomElementIterator it(mXml, QString());

View File

@ -96,7 +96,7 @@ QString XdgMimeType::iconName() const
names.append(QMimeType::iconName()); names.append(QMimeType::iconName());
names.append(QMimeType::genericIconName()); names.append(QMimeType::genericIconName());
foreach (const QString &s, names) { for (const QString &s : const_cast<const QStringList&>(names)) {
if (!XdgIcon::fromTheme(s).isNull()) { if (!XdgIcon::fromTheme(s).isNull()) {
dx->iconName = s; dx->iconName = s;
break; break;

View File

@ -41,6 +41,6 @@ QDebug operator<<(QDebug dbg, const QDomElement &el)
for (int i=0; i<map.count(); ++i) for (int i=0; i<map.count(); ++i)
args += QLatin1Char(' ') + map.item(i).nodeName() + QLatin1Char('=') + map.item(i).nodeValue() + QLatin1Char('\''); args += QLatin1Char(' ') + map.item(i).nodeName() + QLatin1Char('=') + map.item(i).nodeValue() + QLatin1Char('\'');
dbg.nospace() << QString::fromLatin1("<%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(); return dbg.space();
} }

View File

@ -1,28 +0,0 @@
#!/bin/bash
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" "downloads.lxqt.org:/srv/downloads.lxqt.org/$PROJECT/"

View File

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

View File

@ -47,15 +47,17 @@ void QtXdgTest::testDefaultApp()
{ {
QStringList mimedirs = XdgDirs::dataDirs(); QStringList mimedirs = XdgDirs::dataDirs();
mimedirs.prepend(XdgDirs::dataHome(false)); mimedirs.prepend(XdgDirs::dataHome(false));
foreach (QString mimedir, mimedirs) for (const QString &mimedir : const_cast<const QStringList&>(mimedirs))
{ {
QDir dir(mimedir + "/mime"); QDir dir(mimedir + "/mime");
qDebug() << dir.path(); qDebug() << dir.path();
QStringList filters = (QStringList() << "*.xml"); 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(); 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 mimetype = mediaDir.fileName() + "/" + mimeXmlFileName.left(mimeXmlFileName.length() - 4);
QString xdg_utils_default = xdgUtilDefaultApp(mimetype); QString xdg_utils_default = xdgUtilDefaultApp(mimetype);

View File

@ -39,7 +39,7 @@ class QtXdgTest : public QObject
{ {
Q_OBJECT Q_OBJECT
private slots: private Q_SLOTS:
void testCustomFormat(); void testCustomFormat();
private: private:

View File

@ -27,20 +27,20 @@ class Language
{ {
public: public:
Language (const QString& lang) Language (const QString& lang)
: mPreviousLang(QString::fromLocal8Bit(qgetenv("LANG"))) : mPreviousLang(QString::fromLocal8Bit(qgetenv("LC_MESSAGES")))
{ {
qputenv("LANG", lang.toLocal8Bit()); qputenv("LC_MESSAGES", lang.toLocal8Bit());
} }
~Language() ~Language()
{ {
qputenv("LANG", mPreviousLang.toLocal8Bit()); qputenv("LC_MESSAGES", mPreviousLang.toLocal8Bit());
} }
private: private:
QString mPreviousLang; QString mPreviousLang;
}; };
QTEST_MAIN(tst_xdgdesktopfile); QTEST_MAIN(tst_xdgdesktopfile)
void tst_xdgdesktopfile::testRead() void tst_xdgdesktopfile::testRead()
{ {

View File

@ -25,7 +25,7 @@
class tst_xdgdesktopfile : public QObject { class tst_xdgdesktopfile : public QObject {
Q_OBJECT Q_OBJECT
private slots: private Q_SLOTS:
void testRead(); void testRead();
void testReadLocalized(); void testReadLocalized();

View File

@ -36,7 +36,7 @@ class tst_xdgdirs : public QObject
{ {
Q_OBJECT Q_OBJECT
private slots: private Q_SLOTS:
void initTestCase(); void initTestCase();
void cleanupTestCase(); void cleanupTestCase();

View File

@ -1,26 +1,52 @@
include_directories ( set(CMAKE_INCLUDE_CURRENT_DIR ON)
"${CMAKE_PROJECT_DIR}/qtxdg"
${CMAKE_CURRENT_BINARY_DIR}
)
set(QTXDG_DESKTOP_FILE_START_SRCS set(QTXDG_DESKTOP_FILE_START_SRCS
qtxdg-desktop-file-start.cpp qtxdg-desktop-file-start.cpp
) )
set(QTXDG_ICONFINDER_SRCS
qtxdg-iconfinder.cpp
)
add_executable(qtxdg-desktop-file-start add_executable(qtxdg-desktop-file-start
${QTXDG_DESKTOP_FILE_START_SRCS} ${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 target_compile_definitions(qtxdg-desktop-file-start
PRIVATE "-DQTXDG_VERSION=\"${QTXDG_VERSION_STRING}\"" 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 target_link_libraries(qtxdg-desktop-file-start
${QTXDGX_LIBRARY_NAME} ${QTXDGX_LIBRARY_NAME}
) )
target_link_libraries(qtxdg-iconfinder
${QTXDGX_ICONLOADER_LIBRARY_NAME}
)
install(TARGETS install(TARGETS
qtxdg-desktop-file-start qtxdg-desktop-file-start
qtxdg-iconfinder
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT Runtime COMPONENT Runtime
) )

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 +1,3 @@
include_directories(
"${Qt5Gui_PRIVATE_INCLUDE_DIRS}"
)
set(xdgiconloader_PUBLIC_H_FILES set(xdgiconloader_PUBLIC_H_FILES
) )
@ -38,17 +34,22 @@ configure_file(
COPYONLY COPYONLY
) )
target_include_directories(${QTXDGX_ICONLOADER_LIBRARY_NAME} target_compile_definitions(${QTXDGX_ICONLOADER_LIBRARY_NAME}
INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}>" PRIVATE
INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" "QT_NO_KEYWORDS"
INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}>"
) )
# include directories and targets for the in tree build
target_include_directories(${QTXDGX_ICONLOADER_LIBRARY_NAME} target_include_directories(${QTXDGX_ICONLOADER_LIBRARY_NAME}
PUBLIC "$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}>" INTERFACE
PUBLIC "$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}>"
PUBLIC "$<BUILD_INTERFACE:${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}>" "$<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} target_link_libraries(${QTXDGX_ICONLOADER_LIBRARY_NAME}
@ -63,7 +64,7 @@ set_target_properties(${QTXDGX_ICONLOADER_LIBRARY_NAME}
SOVERSION ${QTXDG_MAJOR_VERSION} SOVERSION ${QTXDG_MAJOR_VERSION}
) )
export(TARGETS ${QTXDGX_ICONLOADER_LIBRARY_NAME} FILE "${CMAKE_BINARY_DIR}/${QTXDGX_ICONLOADER_FILE_NAME}-targets.cmake") add_subdirectory(plugin)
install(TARGETS install(TARGETS
${QTXDGX_ICONLOADER_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}" ${QTXDGX_ICONLOADER_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}"
@ -77,6 +78,11 @@ install(FILES
COMPONENT Devel COMPONENT Devel
) )
file(COPY
${xdgiconloader_PRIVATE_INSTALLABLE_H_FILES}
DESTINATION "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${QTXDG_VERSION_STRING}/private/xdgiconloader"
)
install(FILES install(FILES
"${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${XDGICONLOADER_EXPORT_FILE}" "${QTXDGX_INTREE_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}/${XDGICONLOADER_EXPORT_FILE}"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${QTXDGX_ICONLOADER_FILE_NAME}" 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

@ -41,10 +41,13 @@
#include <qpa/qplatformtheme.h> #include <qpa/qplatformtheme.h>
#include <QtGui/QIconEngine> #include <QtGui/QIconEngine>
#include <QtGui/QPalette> #include <QtGui/QPalette>
#include <QtCore/qmath.h>
#include <QtCore/QList> #include <QtCore/QList>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QSettings> #include <QtCore/QSettings>
#include <QtGui/QPainter> #include <QtGui/QPainter>
#include <QImageReader>
#include <QXmlStreamReader>
#ifdef Q_DEAD_CODE_FROM_QT4_MAC #ifdef Q_DEAD_CODE_FROM_QT4_MAC
#include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_cocoa_helpers_mac_p.h>
@ -62,104 +65,36 @@ static QString fallbackTheme()
{ {
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconFallbackThemeName); const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconFallbackThemeName);
if (themeHint.isValid()) if (themeHint.isValid()) {
return themeHint.toString(); const QString theme = themeHint.toString();
if (theme != QLatin1String("hicolor"))
return theme;
} }
return QLatin1String("hicolor"); }
return QString();
} }
XdgIconLoader::XdgIconLoader() : #ifdef QT_NO_LIBRARY
m_themeKey(1), m_supportsSvg(false), m_initialized(false) static bool gSupportsSvg = false;
{ #else
} static bool gSupportsSvg = true;
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 XdgIconLoader::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 #endif //QT_NO_LIBRARY
void XdgIconLoader::setFollowColorScheme(bool enable)
{
if (m_followColorScheme != enable)
{
QIconLoader::instance()->invalidateKey();
m_followColorScheme = enable;
} }
} }
XdgIconLoader *XdgIconLoader::instance() XdgIconLoader *XdgIconLoader::instance()
{ {
iconLoaderInstance()->ensureInitialized(); QIconLoader::instance()->ensureInitialized();
return iconLoaderInstance(); return iconLoaderInstance();
} }
// Queries the system theme and invalidates existing
// icons if the theme has changed.
void XdgIconLoader::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 XdgIconLoader::setThemeName(const QString &themeName)
{
m_userTheme = themeName;
invalidateKey();
}
void XdgIconLoader::setThemeSearchPath(const QStringList &searchPaths)
{
m_iconDirs = searchPaths;
themeList.clear();
invalidateKey();
}
QStringList XdgIconLoader::themeSearchPaths() const
{
if (m_iconDirs.isEmpty()) {
m_iconDirs = systemIconSearchPaths();
// Always add resource directory as search path
m_iconDirs.append(QLatin1String(":/icons"));
}
return m_iconDirs;
}
/*! /*!
\class QIconCacheGtkReader \class QIconCacheGtkReader
\internal \internal
@ -172,7 +107,7 @@ class QIconCacheGtkReader
{ {
public: public:
explicit QIconCacheGtkReader(const QString &themeDir); explicit QIconCacheGtkReader(const QString &themeDir);
QVector<const char *> lookup(const QString &); QVector<const char *> lookup(const QStringRef &);
bool isValid() const { return m_isValid; } bool isValid() const { return m_isValid; }
private: private:
QFile m_file; QFile m_file;
@ -203,7 +138,7 @@ private:
QIconCacheGtkReader::QIconCacheGtkReader(const QString &dirName) QIconCacheGtkReader::QIconCacheGtkReader(const QString &dirName)
: m_isValid(false) : m_isValid(false)
{ {
QFileInfo info(dirName + QLatin1Literal("/icon-theme.cache")); QFileInfo info(dirName + QLatin1String("/icon-theme.cache"));
if (!info.exists() || info.lastModified() < QFileInfo(dirName).lastModified()) if (!info.exists() || info.lastModified() < QFileInfo(dirName).lastModified())
return; return;
m_file.setFileName(info.absoluteFilePath()); m_file.setFileName(info.absoluteFilePath());
@ -245,7 +180,7 @@ static quint32 icon_name_hash(const char *p)
with this name is present. The char* are pointers to the mapped data. with this name is present. The char* are pointers to the mapped data.
For example, this would return { "32x32/apps", "24x24/apps" , ... } For example, this would return { "32x32/apps", "24x24/apps" , ... }
*/ */
QVector<const char *> QIconCacheGtkReader::lookup(const QString &name) QVector<const char *> QIconCacheGtkReader::lookup(const QStringRef &name)
{ {
QVector<const char *> ret; QVector<const char *> ret;
if (!isValid()) if (!isValid())
@ -295,12 +230,13 @@ QVector<const char *> QIconCacheGtkReader::lookup(const QString &name)
return ret; return ret;
} }
QIconTheme::QIconTheme(const QString &themeName) XdgIconTheme::XdgIconTheme(const QString &themeName)
: m_valid(false) : m_valid(false)
, m_followsColorScheme(false)
{ {
QFile themeIndex; QFile themeIndex;
QStringList iconDirs = QIcon::themeSearchPaths(); const QStringList iconDirs = QIcon::themeSearchPaths();
for ( int i = 0 ; i < iconDirs.size() ; ++i) { for ( int i = 0 ; i < iconDirs.size() ; ++i) {
QDir iconDir(iconDirs[i]); QDir iconDir(iconDirs[i]);
QString themeDir = iconDir.path() + QLatin1Char('/') + themeName; QString themeDir = iconDir.path() + QLatin1Char('/') + themeName;
@ -320,27 +256,26 @@ QIconTheme::QIconTheme(const QString &themeName)
#ifndef QT_NO_SETTINGS #ifndef QT_NO_SETTINGS
if (themeIndex.exists()) { if (themeIndex.exists()) {
const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat); const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
QStringListIterator keyIterator(indexReader.allKeys()); m_followsColorScheme = indexReader.value(QStringLiteral("Icon Theme/FollowsColorScheme"), false).toBool();
while (keyIterator.hasNext()) { const QStringList keys = indexReader.allKeys();
for (auto const &key : keys) {
const QString key = keyIterator.next();
if (key.endsWith(QLatin1String("/Size"))) { if (key.endsWith(QLatin1String("/Size"))) {
// Note the QSettings ini-format does not accept // Note the QSettings ini-format does not accept
// slashes in key names, hence we have to cheat // slashes in key names, hence we have to cheat
if (int size = indexReader.value(key).toInt()) { if (int size = indexReader.value(key).toInt()) {
QString directoryKey = key.left(key.size() - 5); QString directoryKey = key.left(key.size() - 5);
XdgIconDirInfo dirInfo(directoryKey); QIconDirInfo dirInfo(directoryKey);
dirInfo.size = size; dirInfo.size = size;
QString type = indexReader.value(directoryKey + QString type = indexReader.value(directoryKey +
QLatin1String("/Type") QLatin1String("/Type")
).toString(); ).toString();
if (type == QLatin1String("Fixed")) if (type == QLatin1String("Fixed"))
dirInfo.type = XdgIconDirInfo::Fixed; dirInfo.type = QIconDirInfo::Fixed;
else if (type == QLatin1String("Scalable")) else if (type == QLatin1String("Scalable"))
dirInfo.type = XdgIconDirInfo::Scalable; dirInfo.type = QIconDirInfo::Scalable;
else else
dirInfo.type = XdgIconDirInfo::Threshold; dirInfo.type = QIconDirInfo::Threshold;
dirInfo.threshold = indexReader.value(directoryKey + dirInfo.threshold = indexReader.value(directoryKey +
QLatin1String("/Threshold"), QLatin1String("/Threshold"),
@ -353,6 +288,11 @@ QIconTheme::QIconTheme(const QString &themeName)
dirInfo.maxSize = indexReader.value(directoryKey + dirInfo.maxSize = indexReader.value(directoryKey +
QLatin1String("/MaxSize"), QLatin1String("/MaxSize"),
size).toInt(); 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); m_keyList.append(dirInfo);
} }
} }
@ -362,6 +302,7 @@ QIconTheme::QIconTheme(const QString &themeName)
m_parents = indexReader.value( m_parents = indexReader.value(
QLatin1String("Icon Theme/Inherits")).toStringList(); QLatin1String("Icon Theme/Inherits")).toStringList();
m_parents.removeAll(QString()); m_parents.removeAll(QString());
m_parents.removeAll(QLatin1String("hicolor"));
// Ensure a default platform fallback for all themes // Ensure a default platform fallback for all themes
if (m_parents.isEmpty()) { if (m_parents.isEmpty()) {
@ -369,33 +310,51 @@ QIconTheme::QIconTheme(const QString &themeName)
if (!fallback.isEmpty()) if (!fallback.isEmpty())
m_parents.append(fallback); 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 #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, QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
const QString &iconName, const QString &iconName,
QStringList &visited) const QStringList &visited,
bool dashFallback) const
{ {
QThemeIconInfo info; QThemeIconInfo info;
Q_ASSERT(!themeName.isEmpty()); Q_ASSERT(!themeName.isEmpty());
QPixmap pixmap;
// Used to protect against potential recursions // Used to protect against potential recursions
visited << themeName; visited << themeName;
QIconTheme theme = themeList.value(themeName); XdgIconTheme &theme = themeList[themeName];
if (!theme.isValid()) { if (!theme.isValid()) {
theme = QIconTheme(themeName); theme = XdgIconTheme(themeName);
if (!theme.isValid()) if (!theme.isValid()) {
theme = QIconTheme(fallbackTheme()); const QString fallback = fallbackTheme();
if (!fallback.isEmpty())
themeList.insert(themeName, theme); theme = XdgIconTheme(fallback);
}
} }
const QStringList contentDirs = theme.contentDirs(); const QStringList contentDirs = theme.contentDirs();
@ -405,7 +364,7 @@ QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
const QString xpmext(QLatin1String(".xpm")); const QString xpmext(QLatin1String(".xpm"));
QString iconNameFallback = iconName; QStringRef iconNameFallback(&iconName);
// Iterate through all icon's fallbacks in current theme // Iterate through all icon's fallbacks in current theme
while (info.entries.isEmpty()) { while (info.entries.isEmpty()) {
@ -415,21 +374,21 @@ QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
// Add all relevant files // Add all relevant files
for (int i = 0; i < contentDirs.size(); ++i) { for (int i = 0; i < contentDirs.size(); ++i) {
QVector<XdgIconDirInfo> subDirs = theme.keyList(); QVector<QIconDirInfo> subDirs = theme.keyList();
// Try to reduce the amount of subDirs by looking in the GTK+ cache in order to save // 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) // a massive amount of file stat (especially if the icon is not there)
auto cache = theme.m_gtkCaches.at(i); auto cache = theme.m_gtkCaches.at(i);
if (cache->isValid()) { if (cache->isValid()) {
auto result = cache->lookup(iconNameFallback); const auto result = cache->lookup(iconNameFallback);
if (cache->isValid()) { if (cache->isValid()) {
const QVector<XdgIconDirInfo> subDirsCopy = subDirs; const QVector<QIconDirInfo> subDirsCopy = subDirs;
subDirs.clear(); subDirs.clear();
subDirs.reserve(result.count()); subDirs.reserve(result.count());
foreach (const char *s, result) { for (const char *s : result) {
QString path = QString::fromUtf8(s); QString path = QString::fromUtf8(s);
auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(), auto it = std::find_if(subDirsCopy.cbegin(), subDirsCopy.cend(),
[&](const XdgIconDirInfo &info) { [&](const QIconDirInfo &info) {
return info.path == path; } ); return info.path == path; } );
if (it != subDirsCopy.cend()) { if (it != subDirsCopy.cend()) {
subDirs.append(*it); subDirs.append(*it);
@ -440,45 +399,41 @@ QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
QString contentDir = contentDirs.at(i) + QLatin1Char('/'); QString contentDir = contentDirs.at(i) + QLatin1Char('/');
for (int j = 0; j < subDirs.size() ; ++j) { for (int j = 0; j < subDirs.size() ; ++j) {
const XdgIconDirInfo &dirInfo = subDirs.at(j); const QIconDirInfo &dirInfo = subDirs.at(j);
QString subdir = dirInfo.path; const QString subDir = contentDir + dirInfo.path + QLatin1Char('/');
QDir currentDir(contentDir + subdir); const QString pngPath = subDir + pngIconName;
if (currentDir.exists(pngIconName)) { if (QFile::exists(pngPath)) {
PixmapEntry *iconEntry = new PixmapEntry; PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo; iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(pngIconName); iconEntry->filename = pngPath;
// Notice we ensure that pixmap entries always come before // Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards // scalable to preserve search order afterwards
info.entries.prepend(iconEntry); info.entries.prepend(iconEntry);
} else if (m_supportsSvg && } else {
currentDir.exists(svgIconName)) { const QString svgPath = subDir + svgIconName;
ScalableEntry *iconEntry = new ScalableEntry; if (gSupportsSvg && QFile::exists(svgPath)) {
ScalableEntry *iconEntry = (followColorScheme() && theme.followsColorScheme()) ? new ScalableFollowsColorEntry : new ScalableEntry;
iconEntry->dir = dirInfo; iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(svgIconName); iconEntry->filename = svgPath;
info.entries.append(iconEntry); info.entries.append(iconEntry);
} else if(currentDir.exists(iconName + xpmext)) { }
}
const QString xpmPath = subDir + xpmIconName;
if (QFile::exists(xpmPath)) {
PixmapEntry *iconEntry = new PixmapEntry; PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->dir = dirInfo; iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + xpmext); iconEntry->filename = xpmPath;
// Notice we ensure that pixmap entries always come before // Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards // scalable to preserve search order afterwards
info.entries.append(iconEntry); info.entries.append(iconEntry);
break;
} }
} }
} }
if (!info.entries.isEmpty()) { if (!info.entries.isEmpty())
info.iconName = iconNameFallback; info.iconName = iconNameFallback.toString();
break;
}
// If it's possible - find next fallback for the icon
const int indexOfDash = iconNameFallback.lastIndexOf(QLatin1Char('-'));
if (indexOfDash == -1)
break; break;
iconNameFallback.truncate(indexOfDash);
} }
if (info.entries.isEmpty()) { if (info.entries.isEmpty()) {
@ -496,10 +451,28 @@ QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
} }
} }
if (info.entries.isEmpty()) { if (dashFallback && info.entries.isEmpty()) {
// Search for unthemed icons in main dir of search paths // If it's possible - find next fallback for the icon
QStringList themeSearchPaths = QIcon::themeSearchPaths(); const int indexOfDash = iconNameFallback.lastIndexOf(QLatin1Char('-'));
foreach (QString contentDir, themeSearchPaths) { 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); QDir currentDir(contentDir);
if (currentDir.exists(iconName + pngext)) { if (currentDir.exists(iconName + pngext)) {
@ -508,71 +481,50 @@ QThemeIconInfo XdgIconLoader::findIconHelper(const QString &themeName,
// Notice we ensure that pixmap entries always come before // Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards // scalable to preserve search order afterwards
info.entries.prepend(iconEntry); info.entries.prepend(iconEntry);
} else if (m_supportsSvg && } else if (gSupportsSvg &&
currentDir.exists(iconName + svgext)) { currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry; ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->filename = currentDir.filePath(iconName + svgext); iconEntry->filename = currentDir.filePath(iconName + svgext);
info.entries.append(iconEntry); info.entries.append(iconEntry);
break;
} else if (currentDir.exists(iconName + xpmext)) { } else if (currentDir.exists(iconName + xpmext)) {
PixmapEntry *iconEntry = new PixmapEntry; PixmapEntry *iconEntry = new PixmapEntry;
iconEntry->filename = currentDir.filePath(iconName + xpmext); iconEntry->filename = currentDir.filePath(iconName + xpmext);
// Notice we ensure that pixmap entries always come before // Notice we ensure that pixmap entries always come before
// scalable to preserve search order afterwards // scalable to preserve search order afterwards
info.entries.append(iconEntry); info.entries.append(iconEntry);
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 (info.entries.isEmpty()) {
const QString pixmaps(QLatin1String("/usr/share/pixmaps"));
const QDir currentDir(pixmaps);
const XdgIconDirInfo 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
info.entries.prepend(iconEntry);
} else if (m_supportsSvg &&
currentDir.exists(iconName + svgext)) {
ScalableEntry *iconEntry = new ScalableEntry;
iconEntry->dir = dirInfo;
iconEntry->filename = currentDir.filePath(iconName + svgext);
info.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
info.entries.append(iconEntry);
}
}
#endif
return info; return info;
} }
QThemeIconInfo XdgIconLoader::loadIcon(const QString &name) const QThemeIconInfo XdgIconLoader::loadIcon(const QString &name) const
{ {
if (!themeName().isEmpty()) { const QString theme_name = QIconLoader::instance()->themeName();
if (!theme_name.isEmpty()) {
QStringList visited; QStringList visited;
return findIconHelper(themeName(), name, 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(); return QThemeIconInfo();
@ -623,14 +575,14 @@ bool XdgIconLoaderEngine::hasIcon() const
// Lazily load the icon // Lazily load the icon
void XdgIconLoaderEngine::ensureLoaded() void XdgIconLoaderEngine::ensureLoaded()
{ {
if (!(XdgIconLoader::instance()->themeKey() == m_key)) { if (!(QIconLoader::instance()->themeKey() == m_key)) {
qDeleteAll(m_info.entries); qDeleteAll(m_info.entries);
m_info.entries.clear(); m_info.entries.clear();
m_info.iconName.clear(); m_info.iconName.clear();
Q_ASSERT(m_info.entries.size() == 0); Q_ASSERT(m_info.entries.size() == 0);
m_info = XdgIconLoader::instance()->loadIcon(m_iconName); m_info = XdgIconLoader::instance()->loadIcon(m_iconName);
m_key = XdgIconLoader::instance()->themeKey(); m_key = QIconLoader::instance()->themeKey();
} }
} }
@ -648,16 +600,20 @@ void XdgIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
* This algorithm is defined by the freedesktop spec: * This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/ */
static bool directoryMatchesSize(const XdgIconDirInfo &dir, int iconsize) static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int iconscale)
{ {
if (dir.type == XdgIconDirInfo::Fixed) { #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; return dir.size == iconsize;
} else if (dir.type == XdgIconDirInfo::Scalable) { } else if (dir.type == QIconDirInfo::Scalable) {
return iconsize <= dir.maxSize && return iconsize <= dir.maxSize &&
iconsize >= dir.minSize; iconsize >= dir.minSize;
} else if (dir.type == XdgIconDirInfo::Threshold) { } else if (dir.type == QIconDirInfo::Threshold) {
return iconsize >= dir.size - dir.threshold && return iconsize >= dir.size - dir.threshold &&
iconsize <= dir.size + dir.threshold; iconsize <= dir.size + dir.threshold;
} }
@ -670,12 +626,33 @@ static bool directoryMatchesSize(const XdgIconDirInfo &dir, int iconsize)
* This algorithm is defined by the freedesktop spec: * This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/ */
static int directorySizeDistance(const XdgIconDirInfo &dir, int iconsize) static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale)
{ {
if (dir.type == XdgIconDirInfo::Fixed) { #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); return qAbs(dir.size - iconsize);
} else if (dir.type == XdgIconDirInfo::Scalable) { } else if (dir.type == QIconDirInfo::Scalable) {
if (iconsize < dir.minSize) if (iconsize < dir.minSize)
return dir.minSize - iconsize; return dir.minSize - iconsize;
else if (iconsize > dir.maxSize) else if (iconsize > dir.maxSize)
@ -683,19 +660,20 @@ static int directorySizeDistance(const XdgIconDirInfo &dir, int iconsize)
else else
return 0; return 0;
} else if (dir.type == XdgIconDirInfo::Threshold) { } else if (dir.type == QIconDirInfo::Threshold) {
if (iconsize < dir.size - dir.threshold) if (iconsize < dir.size - dir.threshold)
return dir.minSize - iconsize; return dir.minSize - iconsize;
else if (iconsize > dir.size + dir.threshold) else if (iconsize > dir.size + dir.threshold)
return iconsize - dir.maxSize; return iconsize - dir.maxSize;
else return 0; else return 0;
} }
#endif
Q_ASSERT(1); // Not a valid value Q_ASSERT(1); // Not a valid value
return INT_MAX; return INT_MAX;
} }
XdgIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size) QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int scale)
{ {
int iconsize = qMin(size.width(), size.height()); int iconsize = qMin(size.width(), size.height());
@ -706,18 +684,18 @@ XdgIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size)
// Search for exact matches first // Search for exact matches first
for (int i = 0; i < numEntries; ++i) { for (int i = 0; i < numEntries; ++i) {
XdgIconLoaderEngineEntry *entry = m_info.entries.at(i); QIconLoaderEngineEntry *entry = m_info.entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize)) { if (directoryMatchesSize(entry->dir, iconsize, scale)) {
return entry; return entry;
} }
} }
// Find the minimum distance icon // Find the minimum distance icon
int minimalSize = INT_MAX; int minimalSize = INT_MAX;
XdgIconLoaderEngineEntry *closestMatch = 0; QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) { for (int i = 0; i < numEntries; ++i) {
XdgIconLoaderEngineEntry *entry = m_info.entries.at(i); QIconLoaderEngineEntry *entry = m_info.entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize); int distance = directorySizeDistance(entry->dir, iconsize, scale);
if (distance < minimalSize) { if (distance < minimalSize) {
minimalSize = distance; minimalSize = distance;
closestMatch = entry; closestMatch = entry;
@ -737,10 +715,10 @@ QSize XdgIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
{ {
ensureLoaded(); ensureLoaded();
XdgIconLoaderEngineEntry *entry = entryForSize(size); QIconLoaderEngineEntry *entry = entryForSize(size);
if (entry) { if (entry) {
const XdgIconDirInfo &dir = entry->dir; const QIconDirInfo &dir = entry->dir;
if (dir.type == XdgIconDirInfo::Scalable || dynamic_cast<ScalableEntry *>(entry)) if (dir.type == QIconDirInfo::Scalable || dynamic_cast<ScalableEntry *>(entry))
return size; return size;
else { else {
int dir_size = dir.size; int dir_size = dir.size;
@ -756,9 +734,10 @@ QSize XdgIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
return QSize(result, result); return QSize(result, result);
} }
} }
return QIconEngine::actualSize(size, mode, state); 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) QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
{ {
Q_UNUSED(state); Q_UNUSED(state);
@ -769,6 +748,8 @@ QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State st
basePixmap.load(filename); basePixmap.load(filename);
QSize actualSize = basePixmap.size(); 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())) if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio); actualSize.scale(size, Qt::KeepAspectRatio);
@ -794,6 +775,7 @@ QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State st
return 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) QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
{ {
if (svgIcon.isNull()) if (svgIcon.isNull())
@ -803,12 +785,90 @@ QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State
return svgIcon.pixmap(size, mode, state); 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, QPixmap XdgIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
QIcon::State state) QIcon::State state)
{ {
ensureLoaded(); ensureLoaded();
XdgIconLoaderEngineEntry *entry = entryForSize(size); QIconLoaderEngineEntry *entry = entryForSize(size);
if (entry) if (entry)
return entry->pixmap(size, mode, state); return entry->pixmap(size, mode, state);
@ -853,6 +913,17 @@ void XdgIconLoaderEngine::virtual_hook(int id, void *data)
*reinterpret_cast<bool*>(data) = m_info.entries.isEmpty(); *reinterpret_cast<bool*>(data) = m_info.entries.isEmpty();
} }
break; 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 #endif
default: default:
QIconEngine::virtual_hook(id, data); QIconEngine::virtual_hook(id, data);

View File

@ -31,8 +31,8 @@
** **
****************************************************************************/ ****************************************************************************/
#ifndef QICONLOADER_P_H #ifndef XDGICONLOADER_P_H
#define QICONLOADER_P_H #define XDGICONLOADER_P_H
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
@ -52,65 +52,19 @@
#include <QtGui/QIcon> #include <QtGui/QIcon>
#include <QtGui/QIconEngine> #include <QtGui/QIconEngine>
#include <QtGui/QPixmapCache>
#include <private/qicon_p.h> #include <private/qicon_p.h>
#include <private/qfactoryloader_p.h> #include <private/qiconloader_p.h>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QVector> #include <QtCore/QVector>
#include <QtCore/QTypeInfo>
//QT_BEGIN_NAMESPACE //QT_BEGIN_NAMESPACE
class XdgIconLoader; class XdgIconLoader;
struct XdgIconDirInfo struct ScalableFollowsColorEntry : public ScalableEntry
{
enum Type { Fixed, Scalable, Threshold };
XdgIconDirInfo(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;
};
class XdgIconLoaderEngineEntry
{
public:
virtual ~XdgIconLoaderEngineEntry() {}
virtual QPixmap pixmap(const QSize &size,
QIcon::Mode mode,
QIcon::State state) = 0;
QString filename;
XdgIconDirInfo dir;
static int count;
};
struct ScalableEntry : public XdgIconLoaderEngineEntry
{ {
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIcon svgIcon; QIcon svgSelectedIcon;
};
struct PixmapEntry : public XdgIconLoaderEngineEntry
{
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QPixmap basePixmap;
};
typedef QList<XdgIconLoaderEngineEntry*> QThemeIconEntries;
struct QThemeIconInfo
{
QThemeIconEntries entries;
QString iconName;
}; };
//class QIconLoaderEngine : public QIconEngine //class QIconLoaderEngine : public QIconEngine
@ -120,19 +74,19 @@ public:
XdgIconLoaderEngine(const QString& iconName = QString()); XdgIconLoaderEngine(const QString& iconName = QString());
~XdgIconLoaderEngine(); ~XdgIconLoaderEngine();
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state); 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); 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); QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
QIconEngine *clone() const; QIconEngine *clone() const Q_DECL_OVERRIDE;
bool read(QDataStream &in); bool read(QDataStream &in) Q_DECL_OVERRIDE;
bool write(QDataStream &out) const; bool write(QDataStream &out) const Q_DECL_OVERRIDE;
private: private:
QString key() const; QString key() const Q_DECL_OVERRIDE;
bool hasIcon() const; bool hasIcon() const;
void ensureLoaded(); void ensureLoaded();
void virtual_hook(int id, void *data); void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
XdgIconLoaderEngineEntry *entryForSize(const QSize &size); QIconLoaderEngineEntry *entryForSize(const QSize &size, int scale = 1);
XdgIconLoaderEngine(const XdgIconLoaderEngine &other); XdgIconLoaderEngine(const XdgIconLoaderEngine &other);
QThemeIconInfo m_info; QThemeIconInfo m_info;
QString m_iconName; QString m_iconName;
@ -143,20 +97,24 @@ private:
class QIconCacheGtkReader; class QIconCacheGtkReader;
class QIconTheme // Note: We can't simply reuse the QIconTheme from Qt > 5.7 because
// the QIconTheme constructor symbol isn't exported.
class XdgIconTheme
{ {
public: public:
QIconTheme(const QString &name); XdgIconTheme(const QString &name);
QIconTheme() : m_valid(false) {} XdgIconTheme() = default;
QStringList parents() { return m_parents; } QStringList parents() { return m_parents; }
QVector <XdgIconDirInfo> keyList() { return m_keyList; } QVector <QIconDirInfo> keyList() { return m_keyList; }
QStringList contentDirs() { return m_contentDirs; } QStringList contentDirs() { return m_contentDirs; }
bool isValid() { return m_valid; } bool isValid() const { return m_valid; }
bool followsColorScheme() const { return m_followsColorScheme; }
private: private:
QStringList m_contentDirs; QStringList m_contentDirs;
QVector <XdgIconDirInfo> m_keyList; QVector <QIconDirInfo> m_keyList;
QStringList m_parents; QStringList m_parents;
bool m_valid; bool m_valid = false;
bool m_followsColorScheme = false;
public: public:
QVector<QSharedPointer<QIconCacheGtkReader>> m_gtkCaches; QVector<QSharedPointer<QIconCacheGtkReader>> m_gtkCaches;
}; };
@ -164,43 +122,39 @@ public:
class XDGICONLOADER_EXPORT XdgIconLoader class XDGICONLOADER_EXPORT XdgIconLoader
{ {
public: public:
XdgIconLoader();
QThemeIconInfo loadIcon(const QString &iconName) const; QThemeIconInfo loadIcon(const QString &iconName) const;
uint themeKey() const { return m_themeKey; }
QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; } /* TODO: deprecate & remove all QIconLoader wrappers */
void setThemeName(const QString &themeName); inline uint themeKey() const { return QIconLoader::instance()->themeKey(); }
QIconTheme theme() { return themeList.value(themeName()); } inline QString themeName() const { return QIconLoader::instance()->themeName(); }
void setThemeSearchPath(const QStringList &searchPaths); inline void setThemeName(const QString &themeName) { QIconLoader::instance()->setThemeName(themeName); }
QStringList themeSearchPaths() const; inline void setThemeSearchPath(const QStringList &searchPaths) { QIconLoader::instance()->setThemeSearchPath(searchPaths); }
XdgIconDirInfo dirInfo(int dirindex); 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(); static XdgIconLoader *instance();
void updateSystemTheme();
void invalidateKey() { m_themeKey++; }
void ensureInitialized();
bool hasUserTheme() const { return !m_userTheme.isEmpty(); }
private: private:
QThemeIconInfo findIconHelper(const QString &themeName, QThemeIconInfo findIconHelper(const QString &themeName,
const QString &iconName, const QString &iconName,
QStringList &visited) const; QStringList &visited,
uint m_themeKey; bool dashFallback = false) const;
bool m_supportsSvg; QThemeIconInfo unthemedFallback(const QString &iconName, const QStringList &searchPaths) const;
bool m_initialized; mutable QHash <QString, XdgIconTheme> themeList;
bool m_followColorScheme = true;
mutable QString m_userTheme;
mutable QString m_systemTheme;
mutable QStringList m_iconDirs;
mutable QHash <QString, QIconTheme> themeList;
}; };
// Note: class template specialization of 'QTypeInfo' must occur at
// global scope
Q_DECLARE_TYPEINFO(XdgIconDirInfo, Q_MOVABLE_TYPE);
//QT_END_NAMESPACE
#endif // QT_NO_ICON #endif // QT_NO_ICON
#endif // QICONLOADER_P_H #endif // XDGICONLOADER_P_H