Import Upstream version 0.9.3+16.04.20160218
This commit is contained in:
commit
04ab4db09c
|
@ -0,0 +1,145 @@
|
||||||
|
project(dbusmenu-qt)
|
||||||
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules")
|
||||||
|
|
||||||
|
# Build options
|
||||||
|
option(WITH_DOC "Build documentation (requires Doxygen)" ON)
|
||||||
|
|
||||||
|
# Versions
|
||||||
|
## Package version
|
||||||
|
set(dbusmenu_qt_VERSION_MAJOR 0)
|
||||||
|
set(dbusmenu_qt_VERSION_MINOR 9)
|
||||||
|
set(dbusmenu_qt_VERSION_PATCH 2)
|
||||||
|
set(dbusmenu_qt_VERSION ${dbusmenu_qt_VERSION_MAJOR}.${dbusmenu_qt_VERSION_MINOR}.${dbusmenu_qt_VERSION_PATCH})
|
||||||
|
|
||||||
|
## Lib version
|
||||||
|
### Bump this one when a binary-incompatible change is introduced
|
||||||
|
set(dbusmenu_qt_lib_SOVERSION 2)
|
||||||
|
|
||||||
|
### Bump this one when the API is extended in a binary-compatible way
|
||||||
|
set(dbusmenu_qt_lib_API_VERSION 6)
|
||||||
|
|
||||||
|
### Bump this one when changes do not extend the API
|
||||||
|
set(dbusmenu_qt_lib_PATCH_VERSION 0)
|
||||||
|
|
||||||
|
set(dbusmenu_qt_lib_VERSION ${dbusmenu_qt_lib_SOVERSION}.${dbusmenu_qt_lib_API_VERSION}.${dbusmenu_qt_lib_PATCH_VERSION})
|
||||||
|
|
||||||
|
# Check if we want to explicitly select the Qt version to be used or autodetect
|
||||||
|
if (NOT USE_QT4 AND NOT USE_QT5)
|
||||||
|
# Autodetect, prefering Qt5
|
||||||
|
message(STATUS "Autodetecting Qt version to use")
|
||||||
|
find_package(Qt5Widgets QUIET)
|
||||||
|
if (Qt5Widgets_FOUND)
|
||||||
|
set(USE_QT5 TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Detect for which Qt version we're building
|
||||||
|
if (USE_QT5)
|
||||||
|
find_package(Qt5Widgets REQUIRED)
|
||||||
|
find_package(Qt5DBus REQUIRED)
|
||||||
|
include_directories(${Qt5Widgets_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS})
|
||||||
|
find_package(Qt5Core REQUIRED)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOMOC_RELAXED_MODE ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
set(QT_SUFFIX "qt5")
|
||||||
|
else()
|
||||||
|
find_package(Qt4 REQUIRED)
|
||||||
|
include_directories(
|
||||||
|
${QT_INCLUDE_DIR}
|
||||||
|
${QT_QTCORE_INCLUDE_DIR}
|
||||||
|
${QT_QTDBUS_INCLUDE_DIR}
|
||||||
|
${QT_QTGUI_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(QT_SUFFIX "qt")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include (CheckCXXCompilerFlag)
|
||||||
|
# Check some compiler flags
|
||||||
|
check_cxx_compiler_flag(-fvisibility=hidden __DBUSMENU_HAVE_GCC_VISIBILITY)
|
||||||
|
if (__DBUSMENU_HAVE_GCC_VISIBILITY AND NOT WIN32)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
|
||||||
|
endif (__DBUSMENU_HAVE_GCC_VISIBILITY AND NOT WIN32)
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-Woverloaded-virtual __DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
|
||||||
|
if (__DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||||
|
endif (__DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-std=c++11 __DBUSMENU_HAVE_CXX11)
|
||||||
|
if (__DBUSMENU_HAVE_CXX11)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
endif (__DBUSMENU_HAVE_CXX11)
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
set(LIB_DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
set(CMAKECONFIG_INSTALL_DIR "${LIB_DESTINATION}/cmake/dbusmenu-${QT_SUFFIX}")
|
||||||
|
set(INCLUDE_INSTALL_DIR "include/dbusmenu-${QT_SUFFIX}")
|
||||||
|
|
||||||
|
# dist targets
|
||||||
|
set(ARCHIVE_NAME libdbusmenu-${QT_SUFFIX}-${dbusmenu_qt_VERSION})
|
||||||
|
add_custom_target(dist
|
||||||
|
COMMAND bzr export --root=${ARCHIVE_NAME} ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(distcheck
|
||||||
|
COMMAND cd ${CMAKE_BINARY_DIR}
|
||||||
|
&& rm -rf ${ARCHIVE_NAME}
|
||||||
|
&& tar xf ${ARCHIVE_NAME}.tar.bz2
|
||||||
|
&& mkdir ${ARCHIVE_NAME}/build
|
||||||
|
&& cd ${ARCHIVE_NAME}/build
|
||||||
|
&& cmake -DCMAKE_INSTALL_PREFIX=../install ..
|
||||||
|
&& make
|
||||||
|
&& make install
|
||||||
|
&& make check
|
||||||
|
)
|
||||||
|
add_dependencies(distcheck dist)
|
||||||
|
|
||||||
|
configure_file(dbusmenu-qt.pc.in ${CMAKE_BINARY_DIR}/dbusmenu-${QT_SUFFIX}.pc @ONLY)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_BINARY_DIR}/dbusmenu-${QT_SUFFIX}.pc
|
||||||
|
DESTINATION ${LIB_DESTINATION}/pkgconfig
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
add_subdirectory(tools)
|
||||||
|
|
||||||
|
if(WITH_DOC)
|
||||||
|
configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile @ONLY)
|
||||||
|
|
||||||
|
add_custom_target(doc ALL doxygen
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
install(DIRECTORY ${CMAKE_BINARY_DIR}/html/
|
||||||
|
DESTINATION share/doc/libdbusmenu-${QT_SUFFIX}-doc
|
||||||
|
)
|
||||||
|
endif(WITH_DOC)
|
||||||
|
|
||||||
|
# Generate dbusmenu-qt-config* files
|
||||||
|
configure_package_config_file(
|
||||||
|
dbusmenu-qt-config.cmake.in
|
||||||
|
${CMAKE_BINARY_DIR}/dbusmenu-${QT_SUFFIX}-config.cmake
|
||||||
|
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
|
||||||
|
PATH_VARS INCLUDE_INSTALL_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_BINARY_DIR}/dbusmenu-${QT_SUFFIX}-config-version.cmake
|
||||||
|
VERSION ${dbusmenu_qt_VERSION}
|
||||||
|
COMPATIBILITY SameMajorVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install dbusmenu-qt-config* files
|
||||||
|
install(FILES
|
||||||
|
${CMAKE_BINARY_DIR}/dbusmenu-${QT_SUFFIX}-config.cmake
|
||||||
|
${CMAKE_BINARY_DIR}/dbusmenu-${QT_SUFFIX}-config-version.cmake
|
||||||
|
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
|
@ -0,0 +1,481 @@
|
||||||
|
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA.
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the library GPL. It is
|
||||||
|
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Library General Public License, applies to some
|
||||||
|
specially designated Free Software Foundation software, and to any
|
||||||
|
other libraries whose authors decide to use it. You can use it for
|
||||||
|
your libraries, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if
|
||||||
|
you distribute copies of the library, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link a program with the library, you must provide
|
||||||
|
complete object files to the recipients so that they can relink them
|
||||||
|
with the library, after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
Our method of protecting your rights has two steps: (1) copyright
|
||||||
|
the library, and (2) offer you this license which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
Also, for each distributor's protection, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
library. If the library is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original
|
||||||
|
version, so that any problems introduced by others will not reflect on
|
||||||
|
the original authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that companies distributing free
|
||||||
|
software will individually obtain patent licenses, thus in effect
|
||||||
|
transforming the program into proprietary software. To prevent this,
|
||||||
|
we have made it clear that any patent must be licensed for everyone's
|
||||||
|
free use or not licensed at all.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the ordinary
|
||||||
|
GNU General Public License, which was designed for utility programs. This
|
||||||
|
license, the GNU Library General Public License, applies to certain
|
||||||
|
designated libraries. This license is quite different from the ordinary
|
||||||
|
one; be sure to read it in full, and don't assume that anything in it is
|
||||||
|
the same as in the ordinary license.
|
||||||
|
|
||||||
|
The reason we have a separate public license for some libraries is that
|
||||||
|
they blur the distinction we usually make between modifying or adding to a
|
||||||
|
program and simply using it. Linking a program with a library, without
|
||||||
|
changing the library, is in some sense simply using the library, and is
|
||||||
|
analogous to running a utility program or application program. However, in
|
||||||
|
a textual and legal sense, the linked executable is a combined work, a
|
||||||
|
derivative of the original library, and the ordinary General Public License
|
||||||
|
treats it as such.
|
||||||
|
|
||||||
|
Because of this blurred distinction, using the ordinary General
|
||||||
|
Public License for libraries did not effectively promote software
|
||||||
|
sharing, because most developers did not use the libraries. We
|
||||||
|
concluded that weaker conditions might promote sharing better.
|
||||||
|
|
||||||
|
However, unrestricted linking of non-free programs would deprive the
|
||||||
|
users of those programs of all benefit from the free status of the
|
||||||
|
libraries themselves. This Library General Public License is intended to
|
||||||
|
permit developers of non-free programs to use free libraries, while
|
||||||
|
preserving your freedom as a user of such programs to change the free
|
||||||
|
libraries that are incorporated in them. (We have not seen how to achieve
|
||||||
|
this as regards changes in header files, but we have achieved it as regards
|
||||||
|
changes in the actual functions of the Library.) The hope is that this
|
||||||
|
will lead to faster development of free libraries.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, while the latter only
|
||||||
|
works together with the library.
|
||||||
|
|
||||||
|
Note that it is possible for a library to be covered by the ordinary
|
||||||
|
General Public License rather than by this special one.
|
||||||
|
|
||||||
|
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library which
|
||||||
|
contains a notice placed by the copyright holder or other authorized
|
||||||
|
party saying it may be distributed under the terms of this Library
|
||||||
|
General Public License (also called "this License"). Each licensee is
|
||||||
|
addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also compile or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
c) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
d) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the source code distributed need not include anything that is normally
|
||||||
|
distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Library General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
|
@ -0,0 +1,277 @@
|
||||||
|
# Doxyfile 1.7.3
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Project related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
DOXYFILE_ENCODING = UTF-8
|
||||||
|
PROJECT_NAME = dbusmenu-qt
|
||||||
|
PROJECT_NUMBER = @dbusmenu_qt_VERSION@
|
||||||
|
PROJECT_BRIEF =
|
||||||
|
PROJECT_LOGO =
|
||||||
|
OUTPUT_DIRECTORY =
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
OUTPUT_LANGUAGE = English
|
||||||
|
BRIEF_MEMBER_DESC = YES
|
||||||
|
REPEAT_BRIEF = YES
|
||||||
|
ABBREVIATE_BRIEF =
|
||||||
|
ALWAYS_DETAILED_SEC = NO
|
||||||
|
INLINE_INHERITED_MEMB = NO
|
||||||
|
FULL_PATH_NAMES = YES
|
||||||
|
STRIP_FROM_PATH =
|
||||||
|
STRIP_FROM_INC_PATH =
|
||||||
|
SHORT_NAMES = NO
|
||||||
|
JAVADOC_AUTOBRIEF = NO
|
||||||
|
QT_AUTOBRIEF = NO
|
||||||
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
INHERIT_DOCS = YES
|
||||||
|
SEPARATE_MEMBER_PAGES = NO
|
||||||
|
TAB_SIZE = 4
|
||||||
|
ALIASES =
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = NO
|
||||||
|
OPTIMIZE_FOR_FORTRAN = NO
|
||||||
|
OPTIMIZE_OUTPUT_VHDL = NO
|
||||||
|
EXTENSION_MAPPING =
|
||||||
|
BUILTIN_STL_SUPPORT = NO
|
||||||
|
CPP_CLI_SUPPORT = NO
|
||||||
|
SIP_SUPPORT = NO
|
||||||
|
IDL_PROPERTY_SUPPORT = YES
|
||||||
|
DISTRIBUTE_GROUP_DOC = NO
|
||||||
|
SUBGROUPING = YES
|
||||||
|
TYPEDEF_HIDES_STRUCT = NO
|
||||||
|
SYMBOL_CACHE_SIZE = 0
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Build related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
EXTRACT_ALL = NO
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
EXTRACT_LOCAL_CLASSES = YES
|
||||||
|
EXTRACT_LOCAL_METHODS = NO
|
||||||
|
EXTRACT_ANON_NSPACES = NO
|
||||||
|
HIDE_UNDOC_MEMBERS = NO
|
||||||
|
HIDE_UNDOC_CLASSES = NO
|
||||||
|
HIDE_FRIEND_COMPOUNDS = NO
|
||||||
|
HIDE_IN_BODY_DOCS = NO
|
||||||
|
INTERNAL_DOCS = NO
|
||||||
|
CASE_SENSE_NAMES = YES
|
||||||
|
HIDE_SCOPE_NAMES = NO
|
||||||
|
SHOW_INCLUDE_FILES = YES
|
||||||
|
FORCE_LOCAL_INCLUDES = NO
|
||||||
|
INLINE_INFO = YES
|
||||||
|
SORT_MEMBER_DOCS = YES
|
||||||
|
SORT_BRIEF_DOCS = NO
|
||||||
|
SORT_MEMBERS_CTORS_1ST = NO
|
||||||
|
SORT_GROUP_NAMES = NO
|
||||||
|
SORT_BY_SCOPE_NAME = NO
|
||||||
|
STRICT_PROTO_MATCHING = NO
|
||||||
|
GENERATE_TODOLIST = YES
|
||||||
|
GENERATE_TESTLIST = YES
|
||||||
|
GENERATE_BUGLIST = YES
|
||||||
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
|
ENABLED_SECTIONS =
|
||||||
|
MAX_INITIALIZER_LINES = 30
|
||||||
|
SHOW_USED_FILES = YES
|
||||||
|
SHOW_DIRECTORIES = NO
|
||||||
|
SHOW_FILES = YES
|
||||||
|
SHOW_NAMESPACES = YES
|
||||||
|
FILE_VERSION_FILTER =
|
||||||
|
LAYOUT_FILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to warning and progress messages
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
QUIET = YES
|
||||||
|
WARNINGS = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
WARN_IF_DOC_ERROR = YES
|
||||||
|
WARN_NO_PARAMDOC = NO
|
||||||
|
WARN_FORMAT = "$file:$line: $text"
|
||||||
|
WARN_LOGFILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the input files
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
INPUT = @CMAKE_SOURCE_DIR@/src
|
||||||
|
INPUT_ENCODING = UTF-8
|
||||||
|
FILE_PATTERNS = *.h
|
||||||
|
RECURSIVE = NO
|
||||||
|
EXCLUDE =
|
||||||
|
EXCLUDE_SYMLINKS = NO
|
||||||
|
EXCLUDE_PATTERNS = *_p.*
|
||||||
|
EXCLUDE_SYMBOLS =
|
||||||
|
EXAMPLE_PATH =
|
||||||
|
EXAMPLE_PATTERNS =
|
||||||
|
EXAMPLE_RECURSIVE = NO
|
||||||
|
IMAGE_PATH =
|
||||||
|
INPUT_FILTER =
|
||||||
|
FILTER_PATTERNS =
|
||||||
|
FILTER_SOURCE_FILES = NO
|
||||||
|
FILTER_SOURCE_PATTERNS =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to source browsing
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SOURCE_BROWSER = NO
|
||||||
|
INLINE_SOURCES = NO
|
||||||
|
STRIP_CODE_COMMENTS = YES
|
||||||
|
REFERENCED_BY_RELATION = NO
|
||||||
|
REFERENCES_RELATION = NO
|
||||||
|
REFERENCES_LINK_SOURCE = YES
|
||||||
|
USE_HTAGS = NO
|
||||||
|
VERBATIM_HEADERS = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the alphabetical class index
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ALPHABETICAL_INDEX = YES
|
||||||
|
COLS_IN_ALPHA_INDEX = 5
|
||||||
|
IGNORE_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the HTML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
HTML_OUTPUT = html
|
||||||
|
HTML_FILE_EXTENSION = .html
|
||||||
|
HTML_HEADER =
|
||||||
|
HTML_FOOTER =
|
||||||
|
HTML_STYLESHEET =
|
||||||
|
HTML_COLORSTYLE_HUE = 220
|
||||||
|
HTML_COLORSTYLE_SAT = 100
|
||||||
|
HTML_COLORSTYLE_GAMMA = 80
|
||||||
|
HTML_TIMESTAMP = YES
|
||||||
|
HTML_ALIGN_MEMBERS = YES
|
||||||
|
HTML_DYNAMIC_SECTIONS = NO
|
||||||
|
GENERATE_DOCSET = NO
|
||||||
|
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||||
|
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||||
|
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||||
|
DOCSET_PUBLISHER_NAME = Publisher
|
||||||
|
GENERATE_HTMLHELP = NO
|
||||||
|
CHM_FILE =
|
||||||
|
HHC_LOCATION =
|
||||||
|
GENERATE_CHI = NO
|
||||||
|
CHM_INDEX_ENCODING =
|
||||||
|
BINARY_TOC = NO
|
||||||
|
TOC_EXPAND = NO
|
||||||
|
GENERATE_QHP = NO
|
||||||
|
QCH_FILE =
|
||||||
|
QHP_NAMESPACE = org.doxygen.Project
|
||||||
|
QHP_VIRTUAL_FOLDER = doc
|
||||||
|
QHP_CUST_FILTER_NAME =
|
||||||
|
QHP_CUST_FILTER_ATTRS =
|
||||||
|
QHP_SECT_FILTER_ATTRS =
|
||||||
|
QHG_LOCATION =
|
||||||
|
GENERATE_ECLIPSEHELP = NO
|
||||||
|
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
GENERATE_TREEVIEW = NO
|
||||||
|
USE_INLINE_TREES = NO
|
||||||
|
TREEVIEW_WIDTH = 250
|
||||||
|
EXT_LINKS_IN_WINDOW = NO
|
||||||
|
FORMULA_FONTSIZE = 10
|
||||||
|
FORMULA_TRANSPARENT = YES
|
||||||
|
USE_MATHJAX = NO
|
||||||
|
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
|
||||||
|
SEARCHENGINE = YES
|
||||||
|
SERVER_BASED_SEARCH = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the LaTeX output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
LATEX_OUTPUT = latex
|
||||||
|
LATEX_CMD_NAME = latex
|
||||||
|
MAKEINDEX_CMD_NAME = makeindex
|
||||||
|
COMPACT_LATEX = NO
|
||||||
|
PAPER_TYPE = a4
|
||||||
|
EXTRA_PACKAGES =
|
||||||
|
LATEX_HEADER =
|
||||||
|
PDF_HYPERLINKS = YES
|
||||||
|
USE_PDFLATEX = YES
|
||||||
|
LATEX_BATCHMODE = NO
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
|
LATEX_SOURCE_CODE = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the RTF output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_RTF = NO
|
||||||
|
RTF_OUTPUT = rtf
|
||||||
|
COMPACT_RTF = NO
|
||||||
|
RTF_HYPERLINKS = NO
|
||||||
|
RTF_STYLESHEET_FILE =
|
||||||
|
RTF_EXTENSIONS_FILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the man page output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_MAN = NO
|
||||||
|
MAN_OUTPUT = man
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
MAN_LINKS = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the XML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_XML = NO
|
||||||
|
XML_OUTPUT = xml
|
||||||
|
XML_SCHEMA =
|
||||||
|
XML_DTD =
|
||||||
|
XML_PROGRAMLISTING = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options for the AutoGen Definitions output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the Perl module output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_PERLMOD = NO
|
||||||
|
PERLMOD_LATEX = NO
|
||||||
|
PERLMOD_PRETTY = YES
|
||||||
|
PERLMOD_MAKEVAR_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the preprocessor
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ENABLE_PREPROCESSING = YES
|
||||||
|
MACRO_EXPANSION = NO
|
||||||
|
EXPAND_ONLY_PREDEF = NO
|
||||||
|
SEARCH_INCLUDES = YES
|
||||||
|
INCLUDE_PATH =
|
||||||
|
INCLUDE_FILE_PATTERNS =
|
||||||
|
PREDEFINED =
|
||||||
|
EXPAND_AS_DEFINED =
|
||||||
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::additions related to external references
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
TAGFILES =
|
||||||
|
GENERATE_TAGFILE =
|
||||||
|
ALLEXTERNALS = NO
|
||||||
|
EXTERNAL_GROUPS = YES
|
||||||
|
PERL_PATH = /usr/bin/perl
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the dot tool
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
CLASS_DIAGRAMS = YES
|
||||||
|
MSCGEN_PATH =
|
||||||
|
HIDE_UNDOC_RELATIONS = YES
|
||||||
|
HAVE_DOT = NO
|
||||||
|
DOT_NUM_THREADS = 0
|
||||||
|
DOT_FONTNAME = Helvetica
|
||||||
|
DOT_FONTSIZE = 10
|
||||||
|
DOT_FONTPATH =
|
||||||
|
CLASS_GRAPH = YES
|
||||||
|
COLLABORATION_GRAPH = YES
|
||||||
|
GROUP_GRAPHS = YES
|
||||||
|
UML_LOOK = NO
|
||||||
|
TEMPLATE_RELATIONS = NO
|
||||||
|
INCLUDE_GRAPH = YES
|
||||||
|
INCLUDED_BY_GRAPH = YES
|
||||||
|
CALL_GRAPH = NO
|
||||||
|
CALLER_GRAPH = NO
|
||||||
|
GRAPHICAL_HIERARCHY = YES
|
||||||
|
DIRECTORY_GRAPH = YES
|
||||||
|
DOT_IMAGE_FORMAT = png
|
||||||
|
DOT_PATH =
|
||||||
|
DOTFILE_DIRS =
|
||||||
|
MSCFILE_DIRS =
|
||||||
|
DOT_GRAPH_MAX_NODES = 50
|
||||||
|
MAX_DOT_GRAPH_DEPTH = 0
|
||||||
|
DOT_TRANSPARENT = NO
|
||||||
|
DOT_MULTI_TARGETS = YES
|
||||||
|
GENERATE_LEGEND = YES
|
||||||
|
DOT_CLEANUP = YES
|
|
@ -0,0 +1,135 @@
|
||||||
|
# 0.9.2 - 2012.03.29
|
||||||
|
- Fix disabling and hiding actions (Aurelien Gateau)
|
||||||
|
- Avoid spamming dbus at startup (Aurelien Gateau)
|
||||||
|
- Do not print warnings when not necessary (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.9.1 - 2012.03.26
|
||||||
|
- Add support for "opened" and "closed" events (Aurelien Gateau)
|
||||||
|
- Add support for icon-data (LP BUG 633339) (Christoph Spielmann)
|
||||||
|
|
||||||
|
# 0.9.0 - 2011.08.30
|
||||||
|
- Add support for the "Status" dbusmenu property. Will be used by appmenu-qt for LP BUG 737419 (Aurelien Gateau)
|
||||||
|
- Collapse multiple separators, get rid of starting and trailing separators (LP BUG 793339) (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.8.3 - 2011.06.21
|
||||||
|
- If DBusMenuExporter is deleted, delete all DBusMenu instances which were working with it (Aurelien Gateau)
|
||||||
|
- Only show icons in menu if the platform allows them (Michael Terry)
|
||||||
|
|
||||||
|
# 0.8.2 - 2011.04.12
|
||||||
|
- Shortcut handling: Translate "+" into "plus" and "-" into "minus" (LP BUG 712565) (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.8.1 - 2011.03.24
|
||||||
|
- Added target to build documentation with Doxygen (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.8.0 - 2011.02.24
|
||||||
|
- Implements version 2 of the dbusmenu protocol (Aurelien Gateau)
|
||||||
|
- Merged support for KMenu titles (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.7.0 - 2011.13.01
|
||||||
|
- Switched DBus domain from org.ayatana to com.canonical (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.6 - 2010.12.08
|
||||||
|
- Properly increase version numbers (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.5 - 2010.12.07
|
||||||
|
- Avoid false warnings (Aurelien Gateau)
|
||||||
|
- Make sure we don't track actions twice (KDE BUG 254066) (Aurelien Gateau)
|
||||||
|
- CMake-parser-friendly of dbusmenu_version.h (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.4 - 2010.09.23
|
||||||
|
- Trigger action asynchronously when the "clicked" event is received (LP BUG 643393) (Aurelien Gateau)
|
||||||
|
- Fixed copyright headers (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.3 - 2010.09.16
|
||||||
|
- Moved to LP (Aurelien Gateau)
|
||||||
|
- Removed all code which did not belong to Canonical. Hopefully we get this
|
||||||
|
code back in soon (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.2 - 2010.09.09
|
||||||
|
- Fix some memory leaks (Aurelien Gateau)
|
||||||
|
- Do not keep dangling pointers to deleted actions (LP BUG 624964) (Aurelien Gateau)
|
||||||
|
- Updated documentation of iconNameForAction() (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.1 - 2010.09.02
|
||||||
|
- Fix some memory leaks (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.6.0 - 2010.08.19
|
||||||
|
- Added the DBusMenuImporter::actionActivationRequested(QAction*) signal (Aurelien Gateau)
|
||||||
|
- Fix hardcoded libdir in pkgconfig file (LP BUG 610633) (oneforall)
|
||||||
|
|
||||||
|
# 0.5.2 - 2010.08.05
|
||||||
|
- Fix implementation of GetGroupProperties() (Aurelien Gateau)
|
||||||
|
- Fix detection of QIcon::name() with gold (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.5.1 - 2010.07.01
|
||||||
|
- Add support for KMenu titles (Christoph Feck)
|
||||||
|
|
||||||
|
# 0.5.0 - 2010.06.28
|
||||||
|
- Queue calls to refresh() because we may be spammed with many LayoutUpdated()
|
||||||
|
signals at once (Aurelien Gateau)
|
||||||
|
- Turned DBusMenuImporter::updateMenu() into a slot (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.4.0 - 2010.06.24
|
||||||
|
- Introduce a dbusmenu_version.h file (Aurelien Gateau)
|
||||||
|
- Introduce updateMenu() and menuUpdated(), deprecate menuReadyToBeShown() (Aurelien Gateau)
|
||||||
|
- Better build check for QIcon::name() (LP BUG 597975) (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.3.5 - 2010.06.17
|
||||||
|
- Rework the way menuReadyToBeShown() is emitted (Aurelien Gateau)
|
||||||
|
- Queue LayoutUpdated() signal to avoid emitting it too often (Aurelien Gateau)
|
||||||
|
- Increase timeouts: prefer slow but complete menus to fast but incomplete (Aurelien Gateau)
|
||||||
|
- Use QIcon::name() to return the icon name, when built with Qt 4.7 (Aurelien Gateau)
|
||||||
|
- Correctly handle non-exclusive action groups (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.3.4 - 2010.06.10
|
||||||
|
- Fixed KDE bug #237156 (Aurelien Gateau)
|
||||||
|
- Added support for shortcuts (Aurelien Gateau)
|
||||||
|
- Make the connection to LayoutUpdated() work :/ (Aurelien Gateau)
|
||||||
|
|
||||||
|
# 0.3.3 - 2010.05.19
|
||||||
|
- Introduce a qt minimum version. Qt 4.5 doesn't work. (Michael Jansen)
|
||||||
|
- Use the FindQjson.cmake file made by pinotree for chokoq because it works.
|
||||||
|
The old one didn't (for me). (Michael Jansen)
|
||||||
|
- Refresh after LayoutUpdated signal (Marco Martin)
|
||||||
|
- Test items added to an existing menu are properly imported (Aurelien Gateau)
|
||||||
|
- Allow notification of the menu being filled, don't call aboutToShow more than
|
||||||
|
once per actual menu showing (Aaron Seigo)
|
||||||
|
- Win32 fixes from Ralf Habacker (Patrick Spendrin)
|
||||||
|
- Added option to disable tests (Alex Elsayed)
|
||||||
|
|
||||||
|
# 0.3.2 - 2010.04.02
|
||||||
|
- Fix some weird positioning of menus and submenus.
|
||||||
|
- Handle ItemPropertyUpdated() signal.
|
||||||
|
- Correctly handle properties which are not part of the returned property map
|
||||||
|
because they are set to their default value.
|
||||||
|
- Export "visible" property of action.
|
||||||
|
|
||||||
|
# 0.3.1 - 2010.04.01
|
||||||
|
- Updated to the latest protocol change: 0 is no longer the default value of
|
||||||
|
the "toggle-state" property.
|
||||||
|
- Make it build without QJson again.
|
||||||
|
|
||||||
|
# 0.3.0 - 2010.03.09
|
||||||
|
- Moved the DBus side of DBusMenuExporter to a separate class, hiding it from
|
||||||
|
the outside world.
|
||||||
|
- Cleaned the API of DBusMenuExporter and DBusMenuImporter.
|
||||||
|
- Implemented AboutToShow method from the DBusMenu spec.
|
||||||
|
|
||||||
|
# 0.2.2 - 2010.02.17
|
||||||
|
- Fixed crash if action is removed from menu after exporter is deleted
|
||||||
|
(LP BUG 521011).
|
||||||
|
- Introduced a Qt equivalent of the test application used by dbusmenu-bench in
|
||||||
|
libdbusmenu-glib.
|
||||||
|
- Added distcheck target.
|
||||||
|
|
||||||
|
# 0.2.1 - 2010.02.04
|
||||||
|
- Export KDE titles as disabled standard items.
|
||||||
|
- Added temporary workaround to get more dynamic menus to work on GNOME.
|
||||||
|
|
||||||
|
# 0.2.0 - 2010.02.03
|
||||||
|
- Make it possible to define the object-path used by DBusMenuExporter.
|
||||||
|
- Unit tests.
|
||||||
|
- Follow new DBusMenu spec.
|
||||||
|
|
||||||
|
# 0.1.0 - 2010.01.05
|
||||||
|
- First release.
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
This library provides a Qt implementation of the DBusMenu protocol.
|
||||||
|
|
||||||
|
The DBusMenu protocol makes it possible for applications to export and import
|
||||||
|
their menus over DBus.
|
||||||
|
|
||||||
|
# Author
|
||||||
|
|
||||||
|
Canonical DX Team
|
||||||
|
Maintainer: Renato Filho <renato.filho@canonical.com>
|
||||||
|
Former maintainer: Aurélien Gâteau
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
By default documentation is generated with Doxygen. You can disable
|
||||||
|
documentation generation by passing -DWITH_DOC=OFF to cmake.
|
||||||
|
|
||||||
|
# Links
|
||||||
|
|
||||||
|
## Source code, bugtracker and tarball hosts
|
||||||
|
|
||||||
|
https://launchpad.net/libdbusmenu-qt
|
||||||
|
|
||||||
|
## KDE developers mirror
|
||||||
|
|
||||||
|
http://gitorious.org/dbusmenu/dbusmenu-qt
|
||||||
|
|
||||||
|
## Spec
|
||||||
|
|
||||||
|
http://people.canonical.com/~agateau/dbusmenu/spec/index.html
|
|
@ -0,0 +1,18 @@
|
||||||
|
- Verify copy is clean and up to date
|
||||||
|
bzr st
|
||||||
|
bzr pull
|
||||||
|
- Update NEWS
|
||||||
|
r!bzr log --line -r tag:x.y.z-1..
|
||||||
|
- Bump version number in CMakeLists.txt
|
||||||
|
- Bump library version number in CMakeLists.txt
|
||||||
|
- Commit
|
||||||
|
- Create tarball
|
||||||
|
- Unpack tarball, build and run tests
|
||||||
|
- Test with KDE trunk
|
||||||
|
- If ok, create tag
|
||||||
|
tag=x.y.z
|
||||||
|
bzr tag $tag
|
||||||
|
- Push
|
||||||
|
bzr push
|
||||||
|
- Upload tarball
|
||||||
|
lp-project-upload libdbusmenu-qt $tag libdbusmenu-qt-$tag.tar.bz2
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Find QJSON - JSON handling library for Qt
|
||||||
|
#
|
||||||
|
# This module defines
|
||||||
|
# QJSON_FOUND - whether the qsjon library was found
|
||||||
|
# QJSON_LIBRARIES - the qjson library
|
||||||
|
# QJSON_INCLUDE_DIR - the include path of the qjson library
|
||||||
|
#
|
||||||
|
|
||||||
|
if (QJSON_INCLUDE_DIR AND QJSON_LIBRARIES)
|
||||||
|
|
||||||
|
# Already in cache
|
||||||
|
set (QJSON_FOUND TRUE)
|
||||||
|
|
||||||
|
else (QJSON_INCLUDE_DIR AND QJSON_LIBRARIES)
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
# use pkg-config to get the values of QJSON_INCLUDE_DIRS
|
||||||
|
# and QJSON_LIBRARY_DIRS to add as hints to the find commands.
|
||||||
|
include (FindPkgConfig)
|
||||||
|
pkg_check_modules (PC_QJSON QJson>=0.5)
|
||||||
|
endif (NOT WIN32)
|
||||||
|
|
||||||
|
find_library (QJSON_LIBRARIES
|
||||||
|
NAMES
|
||||||
|
qjson
|
||||||
|
PATHS
|
||||||
|
${PC_QJSON_LIBRARY_DIRS}
|
||||||
|
${LIB_INSTALL_DIR}
|
||||||
|
${KDE4_LIB_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_path (QJSON_INCLUDE_DIR
|
||||||
|
NAMES
|
||||||
|
qjson/parser.h
|
||||||
|
PATHS
|
||||||
|
${PC_QJSON_INCLUDE_DIRS}
|
||||||
|
${INCLUDE_INSTALL_DIR}
|
||||||
|
${KDE4_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(QJSON DEFAULT_MSG QJSON_LIBRARIES QJSON_INCLUDE_DIR)
|
||||||
|
|
||||||
|
endif (QJSON_INCLUDE_DIR AND QJSON_LIBRARIES)
|
|
@ -0,0 +1,5 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/dbusmenu-@QT_SUFFIX@-targets.cmake")
|
||||||
|
|
||||||
|
set_and_check(dbusmenu-@QT_SUFFIX@_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
|
@ -0,0 +1,10 @@
|
||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
libdir=@CMAKE_INSTALL_PREFIX@/lib
|
||||||
|
includedir=@CMAKE_INSTALL_PREFIX@/include/dbusmenu-@QT_SUFFIX@
|
||||||
|
|
||||||
|
Name: libdbusmenu-@QT_SUFFIX@
|
||||||
|
Description: Qt implementation of dbusmenu spec
|
||||||
|
Version: @dbusmenu_qt_VERSION@
|
||||||
|
Libs: -L${libdir} -ldbusmenu-@QT_SUFFIX@
|
||||||
|
Cflags: -I${includedir}
|
|
@ -0,0 +1,127 @@
|
||||||
|
include(CheckCXXSourceCompiles)
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-Wall __DBUSMENU_HAVE_W_ALL)
|
||||||
|
if (__DBUSMENU_HAVE_W_ALL)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
|
endif (__DBUSMENU_HAVE_W_ALL)
|
||||||
|
|
||||||
|
# Check some compiler flags
|
||||||
|
check_cxx_compiler_flag(-fvisibility=hidden __DBUSMENU_HAVE_GCC_VISIBILITY)
|
||||||
|
if (__DBUSMENU_HAVE_GCC_VISIBILITY AND NOT WIN32)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
|
||||||
|
endif (__DBUSMENU_HAVE_GCC_VISIBILITY AND NOT WIN32)
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-Woverloaded-virtual __DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
|
||||||
|
if (__DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||||
|
endif (__DBUSMENU_HAVE_W_OVERLOADED_VIRTUAL)
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-Wall __DBUSMENU_HAVE_W_ALL)
|
||||||
|
if (__DBUSMENU_HAVE_W_ALL)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||||
|
endif (__DBUSMENU_HAVE_W_ALL)
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-std=c++11 __DBUSMENU_HAVE_CXX11)
|
||||||
|
if (__DBUSMENU_HAVE_CXX11)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
endif (__DBUSMENU_HAVE_CXX11)
|
||||||
|
|
||||||
|
# Check whether QIcon::name() exists. It was added in late Qt 4.7 cycle, and is
|
||||||
|
# not present in betas.
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES "${QT_INCLUDE_DIR}")
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES "${QT_QTGUI_LIBRARIES};${QT_QTCORE_LIBRARIES}")
|
||||||
|
else()
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES "${Qt5Gui_INCLUDE_DIRS};${Qt5Core_INCLUDE_DIRS}")
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES "${Qt5Gui_LIBRARIES};${Qt5Core_LIBRARIES}")
|
||||||
|
endif()
|
||||||
|
check_cxx_source_compiles("
|
||||||
|
#include <QtGui/QIcon>
|
||||||
|
int main() {
|
||||||
|
QIcon icon;
|
||||||
|
icon.name();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
" HAVE_QICON_NAME)
|
||||||
|
if (NOT HAVE_QICON_NAME)
|
||||||
|
message(STATUS "QIcon::name() does not exist, DBusMenuExporter will not export icon names by itself")
|
||||||
|
endif()
|
||||||
|
configure_file(dbusmenu_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/dbusmenu_config.h @ONLY)
|
||||||
|
|
||||||
|
set(dbusmenu_qt_SRCS
|
||||||
|
dbusmenu_p.cpp
|
||||||
|
dbusmenuexporter.cpp
|
||||||
|
dbusmenuexporterdbus_p.cpp
|
||||||
|
dbusmenuimporter.cpp
|
||||||
|
dbusmenutypes_p.cpp
|
||||||
|
dbusmenushortcut_p.cpp
|
||||||
|
utils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
${CMAKE_BINARY_DIR}/src
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
qt4_automoc(${dbusmenu_qt_SRCS})
|
||||||
|
qt4_add_dbus_adaptor(dbusmenu_qt_SRCS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.dbusmenu.xml
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/dbusmenuexporterdbus_p.h DBusMenuExporterDBus
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
qt5_add_dbus_adaptor(dbusmenu_qt_SRCS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.dbusmenu.xml
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/dbusmenuexporterdbus_p.h DBusMenuExporterDBus
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(dbusmenu_version.h.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/dbusmenu_version.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(dbusmenu-${QT_SUFFIX} SHARED ${dbusmenu_qt_SRCS})
|
||||||
|
set_target_properties(dbusmenu-${QT_SUFFIX} PROPERTIES
|
||||||
|
VERSION ${dbusmenu_qt_lib_VERSION}
|
||||||
|
SOVERSION ${dbusmenu_qt_lib_SOVERSION}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
target_link_libraries(dbusmenu-${QT_SUFFIX}
|
||||||
|
${QT_QTGUI_LIBRARIES}
|
||||||
|
${QT_QTDBUS_LIBRARIES}
|
||||||
|
${QT_QTCORE_LIBRARIES}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_link_libraries(dbusmenu-${QT_SUFFIX}
|
||||||
|
${Qt5Gui_LIBRARIES}
|
||||||
|
${Qt5Core_LIBRARIES}
|
||||||
|
${Qt5DBus_LIBRARIES}
|
||||||
|
${Qt5Widgets_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Make sure linking to the target adds dbusmenu-qt install directory
|
||||||
|
target_include_directories(dbusmenu-${QT_SUFFIX}
|
||||||
|
INTERFACE "$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>")
|
||||||
|
|
||||||
|
install(TARGETS dbusmenu-${QT_SUFFIX}
|
||||||
|
EXPORT dbusmenu-${QT_SUFFIX}-targets
|
||||||
|
LIBRARY DESTINATION ${LIB_DESTINATION}
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
install(EXPORT dbusmenu-${QT_SUFFIX}-targets
|
||||||
|
DESTINATION ${CMAKECONFIG_INSTALL_DIR})
|
||||||
|
|
||||||
|
install(DIRECTORY .
|
||||||
|
DESTINATION ${INCLUDE_INSTALL_DIR}
|
||||||
|
FILES_MATCHING PATTERN "*.h"
|
||||||
|
PATTERN "*_p.h" EXCLUDE
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dbusmenu_version.h
|
||||||
|
DESTINATION ${INCLUDE_INSTALL_DIR}
|
||||||
|
)
|
|
@ -0,0 +1,365 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
A library to allow applications to provide simple indications of
|
||||||
|
information to be displayed to users of the application through the
|
||||||
|
interface shell.
|
||||||
|
|
||||||
|
Copyright 2009 Canonical Ltd.
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
Ted Gould <ted@canonical.com>
|
||||||
|
Aurélien Gâteau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of either or both of the following licenses:
|
||||||
|
|
||||||
|
1) the GNU Lesser General Public License version 3, as published by the
|
||||||
|
Free Software Foundation; and/or
|
||||||
|
2) the GNU Lesser General Public License version 2.1, as published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||||
|
MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the applicable version of the GNU Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of both the GNU Lesser General Public
|
||||||
|
License version 3 and version 2.1 along with this program. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>
|
||||||
|
-->
|
||||||
|
<node name="/" xmlns:dox="http://www.canonical.com/dbus/dox.dtd">
|
||||||
|
<dox:d><![CDATA[
|
||||||
|
@mainpage
|
||||||
|
|
||||||
|
The goal of DBusMenu is to expose menus on DBus.
|
||||||
|
|
||||||
|
Main interface is documented here: @ref com::canonical::dbusmenu
|
||||||
|
]]></dox:d>
|
||||||
|
<interface name="com.canonical.dbusmenu">
|
||||||
|
<dox:d><![CDATA[
|
||||||
|
A DBus interface to expose menus on DBus.
|
||||||
|
|
||||||
|
Menu items are represented with a unique numeric id and a dictionary of
|
||||||
|
properties.
|
||||||
|
|
||||||
|
To reduce the amount of DBus traffic, a property should only be returned
|
||||||
|
if its value is not the default value.
|
||||||
|
|
||||||
|
Available properties are:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Default Value</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>type</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Can be one of:
|
||||||
|
- "standard": an item which can be clicked to trigger an action or
|
||||||
|
show another menu
|
||||||
|
- "separator": a separator
|
||||||
|
|
||||||
|
Vendor specific types can be added by prefixing them with
|
||||||
|
"x-<vendor>-".
|
||||||
|
</td>
|
||||||
|
<td>"standard"</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>label</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>Text of the item, except that:
|
||||||
|
-# two consecutive underscore characters "__" are displayed as a
|
||||||
|
single underscore,
|
||||||
|
-# any remaining underscore characters are not displayed at all,
|
||||||
|
-# the first of those remaining underscore characters (unless it is
|
||||||
|
the last character in the string) indicates that the following
|
||||||
|
character is the access key.
|
||||||
|
</td>
|
||||||
|
<td>""</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>enabled</td>
|
||||||
|
<td>boolean</td>
|
||||||
|
<td>Whether the item can be activated or not.</td>
|
||||||
|
<td>true</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>visible</td>
|
||||||
|
<td>boolean</td>
|
||||||
|
<td>True if the item is visible in the menu.</td>
|
||||||
|
<td>true</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>icon-name</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>Icon name of the item, following the freedesktop.org icon spec.</td>
|
||||||
|
<td>""</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>icon-data</td>
|
||||||
|
<td>binary</td>
|
||||||
|
<td>PNG data of the icon.</td>
|
||||||
|
<td>Empty</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>shortcut</td>
|
||||||
|
<td>array of arrays of strings</td>
|
||||||
|
<td>The shortcut of the item. Each array represents the key press
|
||||||
|
in the list of keypresses. Each list of strings contains a list of
|
||||||
|
modifiers and then the key that is used. The modifier strings
|
||||||
|
allowed are: "Control", "Alt", "Shift" and "Super".
|
||||||
|
|
||||||
|
- A simple shortcut like Ctrl+S is represented as:
|
||||||
|
[["Control", "S"]]
|
||||||
|
- A complex shortcut like Ctrl+Q, Alt+X is represented as:
|
||||||
|
[["Control", "Q"], ["Alt", "X"]]</td>
|
||||||
|
<td>Empty</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>toggle-type</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>
|
||||||
|
If the item can be toggled, this property should be set to:
|
||||||
|
- "checkmark": Item is an independent togglable item
|
||||||
|
- "radio": Item is part of a group where only one item can be
|
||||||
|
toggled at a time
|
||||||
|
- "": Item cannot be toggled
|
||||||
|
</td>
|
||||||
|
<td>""</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>toggle-state</td>
|
||||||
|
<td>int</td>
|
||||||
|
<td>
|
||||||
|
Describe the current state of a "togglable" item. Can be one of:
|
||||||
|
- 0 = off
|
||||||
|
- 1 = on
|
||||||
|
- anything else = indeterminate
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The implementation does not itself handle ensuring that only one
|
||||||
|
item in a radio group is set to "on", or that a group does not have
|
||||||
|
"on" and "indeterminate" items simultaneously; maintaining this
|
||||||
|
policy is up to the toolkit wrappers.
|
||||||
|
</td>
|
||||||
|
<td>-1</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>children-display</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>
|
||||||
|
If the menu item has children this property should be set to
|
||||||
|
"submenu".
|
||||||
|
</td>
|
||||||
|
<td>""</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Vendor specific properties can be added by prefixing them with
|
||||||
|
"x-<vendor>-".
|
||||||
|
]]></dox:d>
|
||||||
|
|
||||||
|
<!-- Properties -->
|
||||||
|
<property name="Version" type="u" access="read">
|
||||||
|
<dox:d>
|
||||||
|
Provides the version of the DBusmenu API that this API is
|
||||||
|
implementing.
|
||||||
|
</dox:d>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="Status" type="s" access="read">
|
||||||
|
<dox:d>
|
||||||
|
Tells if the menus are in a normal state or they believe that they
|
||||||
|
could use some attention. Cases for showing them would be if help
|
||||||
|
were referring to them or they accessors were being highlighted.
|
||||||
|
This property can have two values: "normal" in almost all cases and
|
||||||
|
"notice" when they should have a higher priority to be shown.
|
||||||
|
</dox:d>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<!-- Functions -->
|
||||||
|
|
||||||
|
<method name="GetLayout">
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.Out1" value="DBusMenuLayoutItem"/>
|
||||||
|
<dox:d>
|
||||||
|
Provides the layout and propertiers that are attached to the entries
|
||||||
|
that are in the layout. It only gives the items that are children
|
||||||
|
of the item that is specified in @a parentId. It will return all of the
|
||||||
|
properties or specific ones depending of the value in @a propertyNames.
|
||||||
|
|
||||||
|
The format is recursive, where the second 'v' is in the same format
|
||||||
|
as the original 'a(ia{sv}av)'. Its content depends on the value
|
||||||
|
of @a recursionDepth.
|
||||||
|
</dox:d>
|
||||||
|
<arg type="i" name="parentId" direction="in">
|
||||||
|
<dox:d>The ID of the parent node for the layout. For
|
||||||
|
grabbing the layout from the root node use zero.</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="i" name="recursionDepth" direction="in">
|
||||||
|
<dox:d>
|
||||||
|
The amount of levels of recursion to use. This affects the
|
||||||
|
content of the second variant array.
|
||||||
|
- -1: deliver all the items under the @a parentId.
|
||||||
|
- 0: no recursion, the array will be empty.
|
||||||
|
- n: array will contains items up to 'n' level depth.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" name="propertyNames" direction="in" >
|
||||||
|
<dox:d>
|
||||||
|
The list of item properties we are
|
||||||
|
interested in. If there are no entries in the list all of
|
||||||
|
the properties will be sent.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="u" name="revision" direction="out">
|
||||||
|
<dox:d>The revision number of the layout. For matching
|
||||||
|
with layoutUpdated signals.</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="(ia{sv}av)" name="layout" direction="out">
|
||||||
|
<dox:d>The layout, as a recursive structure.</dox:d>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="GetGroupProperties">
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QList<int>"/>
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="DBusMenuItemList"/>
|
||||||
|
<dox:d>
|
||||||
|
Returns the list of items which are children of @a parentId.
|
||||||
|
</dox:d>
|
||||||
|
<arg type="ai" name="ids" direction="in" >
|
||||||
|
<dox:d>
|
||||||
|
A list of ids that we should be finding the properties
|
||||||
|
on. If the list is empty, all menu items should be sent.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" name="propertyNames" direction="in" >
|
||||||
|
<dox:d>
|
||||||
|
The list of item properties we are
|
||||||
|
interested in. If there are no entries in the list all of
|
||||||
|
the properties will be sent.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="a(ia{sv})" name="properties" direction="out" >
|
||||||
|
<dox:d>
|
||||||
|
An array of property values.
|
||||||
|
An item in this area is represented as a struct following
|
||||||
|
this format:
|
||||||
|
@li id unsigned the item id
|
||||||
|
@li properties map(string => variant) the requested item properties
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="GetProperty">
|
||||||
|
<dox:d>
|
||||||
|
Get a signal property on a single item. This is not useful if you're
|
||||||
|
going to implement this interface, it should only be used if you're
|
||||||
|
debugging via a commandline tool.
|
||||||
|
</dox:d>
|
||||||
|
<arg type="i" name="id" direction="in">
|
||||||
|
<dox:d>the id of the item which received the event</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="s" name="name" direction="in">
|
||||||
|
<dox:d>the name of the property to get</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="v" name="value" direction="out">
|
||||||
|
<dox:d>the value of the property</dox:d>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="Event">
|
||||||
|
<dox:d><![CDATA[
|
||||||
|
This is called by the applet to notify the application an event happened on a
|
||||||
|
menu item.
|
||||||
|
|
||||||
|
@a type can be one of the following:
|
||||||
|
|
||||||
|
@li "clicked"
|
||||||
|
@li "hovered"
|
||||||
|
|
||||||
|
Vendor specific events can be added by prefixing them with "x-<vendor>-"
|
||||||
|
]]></dox:d>
|
||||||
|
<arg type="i" name="id" direction="in" >
|
||||||
|
<dox:d>the id of the item which received the event</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="s" name="eventId" direction="in" >
|
||||||
|
<dox:d>the type of event</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="v" name="data" direction="in" >
|
||||||
|
<dox:d>event-specific data</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="u" name="timestamp" direction="in" >
|
||||||
|
<dox:d>The time that the event occured if available or the time the message was sent if not</dox:d>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="AboutToShow">
|
||||||
|
<dox:d>
|
||||||
|
This is called by the applet to notify the application that it is about
|
||||||
|
to show the menu under the specified item.
|
||||||
|
</dox:d>
|
||||||
|
<arg type="i" name="id" direction="in">
|
||||||
|
<dox:d>
|
||||||
|
Which menu item represents the parent of the item about to be shown.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="b" name="needUpdate" direction="out">
|
||||||
|
<dox:d>
|
||||||
|
Whether this AboutToShow event should result in the menu being updated.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<!-- Signals -->
|
||||||
|
<signal name="ItemsPropertiesUpdated">
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="DBusMenuItemList"/>
|
||||||
|
<annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="DBusMenuItemKeysList"/>
|
||||||
|
<dox:d>
|
||||||
|
Triggered when there are lots of property updates across many items
|
||||||
|
so they all get grouped into a single dbus message. The format is
|
||||||
|
the ID of the item with a hashtable of names and values for those
|
||||||
|
properties.
|
||||||
|
</dox:d>
|
||||||
|
<arg type="a(ia{sv})" name="updatedProps" direction="out" />
|
||||||
|
<arg type="a(ias)" name="removedProps" direction="out" />
|
||||||
|
</signal>
|
||||||
|
|
||||||
|
<signal name="LayoutUpdated">
|
||||||
|
<dox:d>
|
||||||
|
Triggered by the application to notify display of a layout update, up to
|
||||||
|
revision
|
||||||
|
</dox:d>
|
||||||
|
<arg type="u" name="revision" direction="out" >
|
||||||
|
<dox:d>The revision of the layout that we're currently on</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="i" name="parent" direction="out" >
|
||||||
|
<dox:d>
|
||||||
|
If the layout update is only of a subtree, this is the
|
||||||
|
parent item for the entries that have changed. It is zero if
|
||||||
|
the whole layout should be considered invalid.
|
||||||
|
</dox:d>
|
||||||
|
</arg>
|
||||||
|
</signal>
|
||||||
|
<signal name="ItemActivationRequested">
|
||||||
|
<dox:d>
|
||||||
|
The server is requesting that all clients displaying this
|
||||||
|
menu open it to the user. This would be for things like
|
||||||
|
hotkeys that when the user presses them the menu should
|
||||||
|
open and display itself to the user.
|
||||||
|
</dox:d>
|
||||||
|
<arg type="i" name="id" direction="out" >
|
||||||
|
<dox:d>ID of the menu that should be activated</dox:d>
|
||||||
|
</arg>
|
||||||
|
<arg type="u" name="timestamp" direction="out" >
|
||||||
|
<dox:d>The time that the event occured</dox:d>
|
||||||
|
</arg>
|
||||||
|
</signal>
|
||||||
|
|
||||||
|
<!-- End of interesting stuff -->
|
||||||
|
|
||||||
|
</interface>
|
||||||
|
</node>
|
|
@ -0,0 +1,2 @@
|
||||||
|
/* Whether QIcon::name() exists */
|
||||||
|
#cmakedefine HAVE_QICON_NAME
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENU_EXPORT_H
|
||||||
|
#define DBUSMENU_EXPORT_H
|
||||||
|
|
||||||
|
// Include this file from here to make transition from version 0.3.5 and
|
||||||
|
// earlier easier (no need to conditionally include a file)
|
||||||
|
#include <dbusmenu_version.h>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
#ifdef dbusmenu_qt_EXPORTS
|
||||||
|
#define DBUSMENU_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
#define DBUSMENU_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* DBUSMENU_EXPORT_H */
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "dbusmenu_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QAction>
|
||||||
|
#include <QActionEvent>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenuexporter.h"
|
||||||
|
#include "dbusmenuexporterprivate_p.h"
|
||||||
|
#include "debug_p.h"
|
||||||
|
|
||||||
|
DBusMenu::DBusMenu(QMenu *menu, DBusMenuExporter *exporter, int parentId)
|
||||||
|
: QObject(menu)
|
||||||
|
, m_exporter(exporter)
|
||||||
|
, m_parentId(parentId)
|
||||||
|
{
|
||||||
|
menu->installEventFilter(this);
|
||||||
|
connect(m_exporter, SIGNAL(destroyed(QObject*)), SLOT(deleteMe()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenu::~DBusMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DBusMenu::eventFilter(QObject *, QEvent *event)
|
||||||
|
{
|
||||||
|
QActionEvent *actionEvent = 0;
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::ActionAdded:
|
||||||
|
case QEvent::ActionChanged:
|
||||||
|
case QEvent::ActionRemoved:
|
||||||
|
actionEvent = static_cast<QActionEvent *>(event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::ActionAdded:
|
||||||
|
addAction(actionEvent->action());
|
||||||
|
break;
|
||||||
|
case QEvent::ActionChanged:
|
||||||
|
updateAction(actionEvent->action());
|
||||||
|
break;
|
||||||
|
case QEvent::ActionRemoved:
|
||||||
|
removeAction(actionEvent->action());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenu::addAction(QAction *action)
|
||||||
|
{
|
||||||
|
m_exporter->d->addAction(action, m_parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenu::updateAction(QAction *action)
|
||||||
|
{
|
||||||
|
m_exporter->d->updateAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenu::removeAction(QAction *action)
|
||||||
|
{
|
||||||
|
m_exporter->d->removeAction(action, m_parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenu::deleteMe()
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dbusmenu_p.moc"
|
|
@ -0,0 +1,59 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENU_H
|
||||||
|
#define DBUSMENU_H
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
class DBusMenuExporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class responsible for tracking changes in a menu and reporting them
|
||||||
|
* through DBusMenuExporter
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class DBusMenu : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DBusMenu(QMenu *menu, DBusMenuExporter *exporter, int parentId);
|
||||||
|
virtual ~DBusMenu();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void deleteMe();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addAction(QAction *action);
|
||||||
|
void updateAction(QAction *action);
|
||||||
|
void removeAction(QAction *action);
|
||||||
|
|
||||||
|
DBusMenuExporter* m_exporter;
|
||||||
|
int m_parentId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENU_H */
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* This file is part of the KDE libraries
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUQT_VERSION_H
|
||||||
|
#define DBUSMENUQT_VERSION_H
|
||||||
|
|
||||||
|
#define DBUSMENUQT_VERSION_MAJOR @dbusmenu_qt_VERSION_MAJOR@
|
||||||
|
#define DBUSMENUQT_VERSION_MINOR @dbusmenu_qt_VERSION_MINOR@
|
||||||
|
#define DBUSMENUQT_VERSION_PATCH @dbusmenu_qt_VERSION_PATCH@
|
||||||
|
|
||||||
|
#define DBUSMENUQT_MAKE_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c))
|
||||||
|
|
||||||
|
#define DBUSMENUQT_VERSION DBUSMENUQT_MAKE_VERSION( \
|
||||||
|
DBUSMENUQT_VERSION_MAJOR, \
|
||||||
|
DBUSMENUQT_VERSION_MINOR, \
|
||||||
|
DBUSMENUQT_VERSION_PATCH)
|
||||||
|
|
||||||
|
// Use this macro to add code which depends on a minimum version of dbusmenu-qt
|
||||||
|
#define DBUSMENUQT_IS_VERSION(a, b, c) \
|
||||||
|
(DBUSMENUQT_VERSION >= DBUSMENUQT_MAKE_VERSION(a, b, c))
|
||||||
|
|
||||||
|
#endif /*DBUSMENUQT_VERSION_H */
|
|
@ -0,0 +1,506 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "dbusmenuexporter.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QWidgetAction>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenu_config.h"
|
||||||
|
#include "dbusmenu_p.h"
|
||||||
|
#include "dbusmenuexporterdbus_p.h"
|
||||||
|
#include "dbusmenuexporterprivate_p.h"
|
||||||
|
#include "dbusmenutypes_p.h"
|
||||||
|
#include "dbusmenushortcut_p.h"
|
||||||
|
#include "debug_p.h"
|
||||||
|
#include "utils_p.h"
|
||||||
|
|
||||||
|
static const char *KMENU_TITLE = "kmenu_title";
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
//
|
||||||
|
// DBusMenuExporterPrivate
|
||||||
|
//
|
||||||
|
//-------------------------------------------------
|
||||||
|
int DBusMenuExporterPrivate::idForAction(QAction *action) const
|
||||||
|
{
|
||||||
|
DMRETURN_VALUE_IF_FAIL(action, -1);
|
||||||
|
return m_idForAction.value(action, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::addMenu(QMenu *menu, int parentId)
|
||||||
|
{
|
||||||
|
if (menu->findChild<DBusMenu *>()) {
|
||||||
|
// This can happen if a menu is removed from its parent and added back
|
||||||
|
// See KDE bug 254066
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new DBusMenu(menu, q, parentId);
|
||||||
|
Q_FOREACH(QAction *action, menu->actions()) {
|
||||||
|
addAction(action, parentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap DBusMenuExporterPrivate::propertiesForAction(QAction *action) const
|
||||||
|
{
|
||||||
|
DMRETURN_VALUE_IF_FAIL(action, QVariantMap());
|
||||||
|
|
||||||
|
if (action->objectName() == KMENU_TITLE) {
|
||||||
|
// Hack: Support for KDE menu titles in a Qt-only library...
|
||||||
|
return propertiesForKMenuTitleAction(action);
|
||||||
|
} else if (action->isSeparator()) {
|
||||||
|
return propertiesForSeparatorAction(action);
|
||||||
|
} else {
|
||||||
|
return propertiesForStandardAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap DBusMenuExporterPrivate::propertiesForKMenuTitleAction(QAction *action_) const
|
||||||
|
{
|
||||||
|
QVariantMap map;
|
||||||
|
// In case the other side does not know about x-kde-title, show a disabled item
|
||||||
|
map.insert("enabled", false);
|
||||||
|
map.insert("x-kde-title", true);
|
||||||
|
|
||||||
|
const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction *>(action_);
|
||||||
|
DMRETURN_VALUE_IF_FAIL(widgetAction, map);
|
||||||
|
QToolButton *button = qobject_cast<QToolButton *>(widgetAction->defaultWidget());
|
||||||
|
DMRETURN_VALUE_IF_FAIL(button, map);
|
||||||
|
QAction *action = button->defaultAction();
|
||||||
|
DMRETURN_VALUE_IF_FAIL(action, map);
|
||||||
|
|
||||||
|
map.insert("label", swapMnemonicChar(action->text(), '&', '_'));
|
||||||
|
insertIconProperty(&map, action);
|
||||||
|
if (!action->isVisible()) {
|
||||||
|
map.insert("visible", false);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap DBusMenuExporterPrivate::propertiesForSeparatorAction(QAction *action) const
|
||||||
|
{
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert("type", "separator");
|
||||||
|
if (!action->isVisible()) {
|
||||||
|
map.insert("visible", false);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap DBusMenuExporterPrivate::propertiesForStandardAction(QAction *action) const
|
||||||
|
{
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert("label", swapMnemonicChar(action->text(), '&', '_'));
|
||||||
|
if (!action->isEnabled()) {
|
||||||
|
map.insert("enabled", false);
|
||||||
|
}
|
||||||
|
if (!action->isVisible()) {
|
||||||
|
map.insert("visible", false);
|
||||||
|
}
|
||||||
|
if (action->menu()) {
|
||||||
|
map.insert("children-display", "submenu");
|
||||||
|
}
|
||||||
|
if (action->isCheckable()) {
|
||||||
|
bool exclusive = action->actionGroup() && action->actionGroup()->isExclusive();
|
||||||
|
map.insert("toggle-type", exclusive ? "radio" : "checkmark");
|
||||||
|
map.insert("toggle-state", action->isChecked() ? 1 : 0);
|
||||||
|
}
|
||||||
|
insertIconProperty(&map, action);
|
||||||
|
QKeySequence keySequence = action->shortcut();
|
||||||
|
if (!keySequence.isEmpty()) {
|
||||||
|
DBusMenuShortcut shortcut = DBusMenuShortcut::fromKeySequence(keySequence);
|
||||||
|
map.insert("shortcut", QVariant::fromValue(shortcut));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *DBusMenuExporterPrivate::menuForId(int id) const
|
||||||
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
return m_rootMenu;
|
||||||
|
}
|
||||||
|
QAction *action = m_actionForId.value(id);
|
||||||
|
// Action may not be in m_actionForId if it has been deleted between the
|
||||||
|
// time it was announced by the exporter and the time the importer asks for
|
||||||
|
// it.
|
||||||
|
return action ? action->menu() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::fillLayoutItem(DBusMenuLayoutItem *item, QMenu *menu, int id, int depth, const QStringList &propertyNames)
|
||||||
|
{
|
||||||
|
item->id = id;
|
||||||
|
item->properties = m_dbusObject->getProperties(id, propertyNames);
|
||||||
|
|
||||||
|
if (depth != 0 && menu) {
|
||||||
|
Q_FOREACH(QAction *action, menu->actions()) {
|
||||||
|
int actionId = m_idForAction.value(action, -1);
|
||||||
|
if (actionId == -1) {
|
||||||
|
DMWARNING << "No id for action";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuLayoutItem child;
|
||||||
|
fillLayoutItem(&child, action->menu(), actionId, depth - 1, propertyNames);
|
||||||
|
item->children << child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::updateAction(QAction *action)
|
||||||
|
{
|
||||||
|
int id = idForAction(action);
|
||||||
|
if (m_itemUpdatedIds.contains(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_itemUpdatedIds << id;
|
||||||
|
m_itemUpdatedTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::addAction(QAction *action, int parentId)
|
||||||
|
{
|
||||||
|
int id = m_idForAction.value(action, -1);
|
||||||
|
if (id != -1) {
|
||||||
|
DMWARNING << "Already tracking action" << action->text() << "under id" << id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVariantMap map = propertiesForAction(action);
|
||||||
|
id = m_nextId++;
|
||||||
|
QObject::connect(action, SIGNAL(destroyed(QObject*)), q, SLOT(slotActionDestroyed(QObject*)));
|
||||||
|
m_actionForId.insert(id, action);
|
||||||
|
m_idForAction.insert(action, id);
|
||||||
|
m_actionProperties.insert(action, map);
|
||||||
|
if (action->menu()) {
|
||||||
|
addMenu(action->menu(), id);
|
||||||
|
}
|
||||||
|
++m_revision;
|
||||||
|
emitLayoutUpdated(parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMPORTANT: action might have already been destroyed when this method is
|
||||||
|
* called, so don't dereference the pointer (it is a QObject to avoid being
|
||||||
|
* tempted to dereference)
|
||||||
|
*/
|
||||||
|
void DBusMenuExporterPrivate::removeActionInternal(QObject *object)
|
||||||
|
{
|
||||||
|
QAction* action = static_cast<QAction*>(object);
|
||||||
|
m_actionProperties.remove(action);
|
||||||
|
int id = m_idForAction.take(action);
|
||||||
|
m_actionForId.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::removeAction(QAction *action, int parentId)
|
||||||
|
{
|
||||||
|
removeActionInternal(action);
|
||||||
|
QObject::disconnect(action, SIGNAL(destroyed(QObject*)), q, SLOT(slotActionDestroyed(QObject*)));
|
||||||
|
++m_revision;
|
||||||
|
emitLayoutUpdated(parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::emitLayoutUpdated(int id)
|
||||||
|
{
|
||||||
|
if (m_layoutUpdatedIds.contains(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_layoutUpdatedIds << id;
|
||||||
|
m_layoutUpdatedTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterPrivate::insertIconProperty(QVariantMap *map, QAction *action) const
|
||||||
|
{
|
||||||
|
// provide the icon name for per-theme lookups
|
||||||
|
const QString iconName = q->iconNameForAction(action);
|
||||||
|
if (!iconName.isEmpty()) {
|
||||||
|
map->insert("icon-name", iconName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// provide the serialized icon data in case the icon
|
||||||
|
// is unnamed or the name isn't supported by the theme
|
||||||
|
const QIcon icon = action->icon();
|
||||||
|
if (!icon.isNull()) {
|
||||||
|
QBuffer buffer;
|
||||||
|
icon.pixmap(16).save(&buffer, "PNG");
|
||||||
|
map->insert("icon-data", buffer.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collapseSeparator(QAction* action)
|
||||||
|
{
|
||||||
|
action->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unless the separatorsCollapsible property is set to false, Qt will get rid
|
||||||
|
// of separators at the beginning and at the end of menus as well as collapse
|
||||||
|
// multiple separators in the middle. For example, a menu like this:
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// Open
|
||||||
|
// ---
|
||||||
|
// ---
|
||||||
|
// Quit
|
||||||
|
// ---
|
||||||
|
//
|
||||||
|
// is displayed like this:
|
||||||
|
//
|
||||||
|
// Open
|
||||||
|
// ---
|
||||||
|
// Quit
|
||||||
|
//
|
||||||
|
// We fake this by setting separators invisible before exporting them.
|
||||||
|
//
|
||||||
|
// cf. https://bugs.launchpad.net/libdbusmenu-qt/+bug/793339
|
||||||
|
void DBusMenuExporterPrivate::collapseSeparators(QMenu* menu)
|
||||||
|
{
|
||||||
|
QList<QAction*> actions = menu->actions();
|
||||||
|
if (actions.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QAction*>::Iterator it, begin = actions.begin(), end = actions.end();
|
||||||
|
|
||||||
|
// Get rid of separators at end
|
||||||
|
it = end - 1;
|
||||||
|
for (; it != begin; --it) {
|
||||||
|
if ((*it)->isSeparator()) {
|
||||||
|
collapseSeparator(*it);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end now points after the last visible entry
|
||||||
|
end = it + 1;
|
||||||
|
it = begin;
|
||||||
|
|
||||||
|
// Get rid of separators at beginnning
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
if ((*it)->isSeparator()) {
|
||||||
|
collapseSeparator(*it);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapse separators in between
|
||||||
|
bool previousWasSeparator = false;
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
QAction* action = *it;
|
||||||
|
if (action->isSeparator()) {
|
||||||
|
if (previousWasSeparator) {
|
||||||
|
collapseSeparator(action);
|
||||||
|
} else {
|
||||||
|
previousWasSeparator = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
previousWasSeparator = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
//
|
||||||
|
// DBusMenuExporter
|
||||||
|
//
|
||||||
|
//-------------------------------------------------
|
||||||
|
DBusMenuExporter::DBusMenuExporter(const QString &objectPath, QMenu *menu, const QDBusConnection &_connection)
|
||||||
|
: QObject(menu)
|
||||||
|
, d(new DBusMenuExporterPrivate)
|
||||||
|
{
|
||||||
|
d->q = this;
|
||||||
|
d->m_objectPath = objectPath;
|
||||||
|
d->m_rootMenu = menu;
|
||||||
|
d->m_nextId = 1;
|
||||||
|
d->m_revision = 1;
|
||||||
|
d->m_emittedLayoutUpdatedOnce = false;
|
||||||
|
d->m_itemUpdatedTimer = new QTimer(this);
|
||||||
|
d->m_layoutUpdatedTimer = new QTimer(this);
|
||||||
|
d->m_dbusObject = new DBusMenuExporterDBus(this);
|
||||||
|
|
||||||
|
d->addMenu(d->m_rootMenu, 0);
|
||||||
|
|
||||||
|
d->m_itemUpdatedTimer->setInterval(0);
|
||||||
|
d->m_itemUpdatedTimer->setSingleShot(true);
|
||||||
|
connect(d->m_itemUpdatedTimer, SIGNAL(timeout()), SLOT(doUpdateActions()));
|
||||||
|
|
||||||
|
d->m_layoutUpdatedTimer->setInterval(0);
|
||||||
|
d->m_layoutUpdatedTimer->setSingleShot(true);
|
||||||
|
connect(d->m_layoutUpdatedTimer, SIGNAL(timeout()), SLOT(doEmitLayoutUpdated()));
|
||||||
|
|
||||||
|
QDBusConnection connection(_connection);
|
||||||
|
connection.registerObject(objectPath, d->m_dbusObject, QDBusConnection::ExportAllContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuExporter::~DBusMenuExporter()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporter::doUpdateActions()
|
||||||
|
{
|
||||||
|
if (d->m_itemUpdatedIds.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DBusMenuItemList updatedList;
|
||||||
|
DBusMenuItemKeysList removedList;
|
||||||
|
|
||||||
|
Q_FOREACH(int id, d->m_itemUpdatedIds) {
|
||||||
|
QAction *action = d->m_actionForId.value(id);
|
||||||
|
if (!action) {
|
||||||
|
// Action does not exist anymore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap& oldProperties = d->m_actionProperties[action];
|
||||||
|
QVariantMap newProperties = d->propertiesForAction(action);
|
||||||
|
QVariantMap updatedProperties;
|
||||||
|
QStringList removedProperties;
|
||||||
|
|
||||||
|
// Find updated and removed properties
|
||||||
|
QVariantMap::ConstIterator newEnd = newProperties.constEnd();
|
||||||
|
|
||||||
|
QVariantMap::ConstIterator
|
||||||
|
oldIt = oldProperties.constBegin(),
|
||||||
|
oldEnd = oldProperties.constEnd();
|
||||||
|
for(; oldIt != oldEnd; ++oldIt) {
|
||||||
|
QString key = oldIt.key();
|
||||||
|
QVariantMap::ConstIterator newIt = newProperties.constFind(key);
|
||||||
|
if (newIt != newEnd) {
|
||||||
|
if (newIt.value() != oldIt.value()) {
|
||||||
|
updatedProperties.insert(key, newIt.value());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removedProperties << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find new properties (treat them as updated properties)
|
||||||
|
QVariantMap::ConstIterator newIt = newProperties.constBegin();
|
||||||
|
for (; newIt != newEnd; ++newIt) {
|
||||||
|
QString key = newIt.key();
|
||||||
|
oldIt = oldProperties.constFind(key);
|
||||||
|
if (oldIt == oldEnd) {
|
||||||
|
updatedProperties.insert(key, newIt.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update our data (oldProperties is a reference)
|
||||||
|
oldProperties = newProperties;
|
||||||
|
QMenu *menu = action->menu();
|
||||||
|
if (menu) {
|
||||||
|
d->addMenu(menu, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!updatedProperties.isEmpty()) {
|
||||||
|
DBusMenuItem item;
|
||||||
|
item.id = id;
|
||||||
|
item.properties = updatedProperties;
|
||||||
|
updatedList << item;
|
||||||
|
}
|
||||||
|
if (!removedProperties.isEmpty()) {
|
||||||
|
DBusMenuItemKeys itemKeys;
|
||||||
|
itemKeys.id = id;
|
||||||
|
itemKeys.properties = removedProperties;
|
||||||
|
removedList << itemKeys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d->m_itemUpdatedIds.clear();
|
||||||
|
if (!d->m_emittedLayoutUpdatedOnce) {
|
||||||
|
// No need to tell the world about action changes: nobody knows the
|
||||||
|
// menu layout so nobody knows about the actions.
|
||||||
|
// Note: We can't stop in DBusMenuExporterPrivate::addAction(), we
|
||||||
|
// still need to reach this method because we want our properties to be
|
||||||
|
// updated, even if we don't announce changes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!updatedList.isEmpty() || !removedList.isEmpty()) {
|
||||||
|
d->m_dbusObject->ItemsPropertiesUpdated(updatedList, removedList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporter::doEmitLayoutUpdated()
|
||||||
|
{
|
||||||
|
// Collapse separators for all updated menus
|
||||||
|
Q_FOREACH(int id, d->m_layoutUpdatedIds) {
|
||||||
|
QMenu* menu = d->menuForId(id);
|
||||||
|
if (menu && menu->separatorsCollapsible()) {
|
||||||
|
d->collapseSeparators(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the world about the update
|
||||||
|
if (d->m_emittedLayoutUpdatedOnce) {
|
||||||
|
Q_FOREACH(int id, d->m_layoutUpdatedIds) {
|
||||||
|
d->m_dbusObject->LayoutUpdated(d->m_revision, id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// First time we emit LayoutUpdated, no need to emit several layout
|
||||||
|
// updates, signals the whole layout (id==0) has been updated
|
||||||
|
d->m_dbusObject->LayoutUpdated(d->m_revision, 0);
|
||||||
|
d->m_emittedLayoutUpdatedOnce = true;
|
||||||
|
}
|
||||||
|
d->m_layoutUpdatedIds.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DBusMenuExporter::iconNameForAction(QAction *action)
|
||||||
|
{
|
||||||
|
DMRETURN_VALUE_IF_FAIL(action, QString());
|
||||||
|
#ifdef HAVE_QICON_NAME
|
||||||
|
QIcon icon = action->icon();
|
||||||
|
if (action->isIconVisibleInMenu() && !icon.isNull()) {
|
||||||
|
return icon.name();
|
||||||
|
} else {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return QString();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporter::activateAction(QAction *action)
|
||||||
|
{
|
||||||
|
int id = d->idForAction(action);
|
||||||
|
DMRETURN_IF_FAIL(id >= 0);
|
||||||
|
uint timeStamp = QDateTime::currentDateTime().toTime_t();
|
||||||
|
d->m_dbusObject->ItemActivationRequested(id, timeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporter::slotActionDestroyed(QObject* object)
|
||||||
|
{
|
||||||
|
d->removeActionInternal(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporter::setStatus(const QString& status)
|
||||||
|
{
|
||||||
|
d->m_dbusObject->setStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DBusMenuExporter::status() const
|
||||||
|
{
|
||||||
|
return d->m_dbusObject->status();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dbusmenuexporter.moc"
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUEXPORTER_H
|
||||||
|
#define DBUSMENUEXPORTER_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtDBus/QDBusConnection>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <dbusmenu_export.h>
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
class DBusMenuExporterPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DBusMenuExporter instance can serialize a menu over DBus
|
||||||
|
*/
|
||||||
|
class DBUSMENU_EXPORT DBusMenuExporter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a DBusMenuExporter exporting menu at the dbus object path
|
||||||
|
* dbusObjectPath, using the given dbusConnection.
|
||||||
|
* The instance adds itself to the menu children.
|
||||||
|
*/
|
||||||
|
DBusMenuExporter(const QString &dbusObjectPath, QMenu *menu, const QDBusConnection &dbusConnection = QDBusConnection::sessionBus());
|
||||||
|
|
||||||
|
virtual ~DBusMenuExporter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the matching DBusMenuImporter to activate @p action. For menus it
|
||||||
|
* means popup them, for items it means triggering the associated action.
|
||||||
|
*/
|
||||||
|
void activateAction(QAction *action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The status of the menu. Can be one of "normal" or "notice". This can be
|
||||||
|
* used to notify the other side the menu should be made more visible.
|
||||||
|
* For example, appmenu uses it to tell Unity panel to show/hide the menubar
|
||||||
|
* when the Alt modifier is pressed/released.
|
||||||
|
*/
|
||||||
|
void setStatus(const QString &status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the menu.
|
||||||
|
* @ref setStatus
|
||||||
|
*/
|
||||||
|
QString status() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Must extract the icon name for action. This is the name which will
|
||||||
|
* be used to present the icon over DBus.
|
||||||
|
* Default implementation returns action->icon().name() when built on Qt
|
||||||
|
* >= 4.7 and a null string otherwise.
|
||||||
|
*/
|
||||||
|
virtual QString iconNameForAction(QAction *action);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void doUpdateActions();
|
||||||
|
void doEmitLayoutUpdated();
|
||||||
|
void slotActionDestroyed(QObject*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(DBusMenuExporter)
|
||||||
|
DBusMenuExporterPrivate *const d;
|
||||||
|
|
||||||
|
friend class DBusMenuExporterPrivate;
|
||||||
|
friend class DBusMenuExporterDBus;
|
||||||
|
friend class DBusMenu;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUEXPORTER_H */
|
|
@ -0,0 +1,186 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "dbusmenuexporterdbus_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QDBusMessage>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenuadaptor.h"
|
||||||
|
#include "dbusmenuexporterprivate_p.h"
|
||||||
|
#include "dbusmenushortcut_p.h"
|
||||||
|
#include "debug_p.h"
|
||||||
|
|
||||||
|
static const char *DBUSMENU_INTERFACE = "com.canonical.dbusmenu";
|
||||||
|
static const char *FDO_PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
|
||||||
|
|
||||||
|
DBusMenuExporterDBus::DBusMenuExporterDBus(DBusMenuExporter *exporter)
|
||||||
|
: QObject(exporter)
|
||||||
|
, m_exporter(exporter)
|
||||||
|
, m_status("normal")
|
||||||
|
{
|
||||||
|
DBusMenuTypes_register();
|
||||||
|
new DbusmenuAdaptor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint DBusMenuExporterDBus::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item)
|
||||||
|
{
|
||||||
|
QMenu *menu = m_exporter->d->menuForId(parentId);
|
||||||
|
DMRETURN_VALUE_IF_FAIL(menu, 0);
|
||||||
|
|
||||||
|
// Process pending actions, we need them *now*
|
||||||
|
QMetaObject::invokeMethod(m_exporter, "doUpdateActions");
|
||||||
|
m_exporter->d->fillLayoutItem(&item, menu, parentId, recursionDepth, propertyNames);
|
||||||
|
|
||||||
|
return m_exporter->d->m_revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterDBus::Event(int id, const QString &eventType, const QDBusVariant &/*data*/, uint /*timestamp*/)
|
||||||
|
{
|
||||||
|
if (eventType == "clicked") {
|
||||||
|
QAction *action = m_exporter->d->m_actionForId.value(id);
|
||||||
|
if (!action) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// dbusmenu-glib seems to ignore the Q_NOREPLY and blocks when calling
|
||||||
|
// Event(), so trigger the action asynchronously
|
||||||
|
QMetaObject::invokeMethod(action, "trigger", Qt::QueuedConnection);
|
||||||
|
} else if (eventType == "hovered") {
|
||||||
|
QMenu *menu = m_exporter->d->menuForId(id);
|
||||||
|
if (menu) {
|
||||||
|
QMetaObject::invokeMethod(menu, "aboutToShow");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDBusVariant DBusMenuExporterDBus::GetProperty(int id, const QString &name)
|
||||||
|
{
|
||||||
|
QAction *action = m_exporter->d->m_actionForId.value(id);
|
||||||
|
DMRETURN_VALUE_IF_FAIL(action, QDBusVariant());
|
||||||
|
return QDBusVariant(m_exporter->d->m_actionProperties.value(action).value(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap DBusMenuExporterDBus::getProperties(int id, const QStringList &names) const
|
||||||
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert("children-display", "submenu");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
QAction *action = m_exporter->d->m_actionForId.value(id);
|
||||||
|
DMRETURN_VALUE_IF_FAIL(action, QVariantMap());
|
||||||
|
QVariantMap all = m_exporter->d->m_actionProperties.value(action);
|
||||||
|
if (names.isEmpty()) {
|
||||||
|
return all;
|
||||||
|
} else {
|
||||||
|
QVariantMap map;
|
||||||
|
Q_FOREACH(const QString &name, names) {
|
||||||
|
QVariant value = all.value(name);
|
||||||
|
if (value.isValid()) {
|
||||||
|
map.insert(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuItemList DBusMenuExporterDBus::GetGroupProperties(const QList<int> &ids, const QStringList &names)
|
||||||
|
{
|
||||||
|
DBusMenuItemList list;
|
||||||
|
Q_FOREACH(int id, ids) {
|
||||||
|
DBusMenuItem item;
|
||||||
|
item.id = id;
|
||||||
|
item.properties = getProperties(item.id, names);
|
||||||
|
list << item;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An helper class for ::AboutToShow, which sets mChanged to true if a menu
|
||||||
|
* changes after its aboutToShow() signal has been emitted.
|
||||||
|
*/
|
||||||
|
class ActionEventFilter: public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionEventFilter()
|
||||||
|
: mChanged(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool mChanged;
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *object, QEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::ActionAdded:
|
||||||
|
case QEvent::ActionChanged:
|
||||||
|
case QEvent::ActionRemoved:
|
||||||
|
mChanged = true;
|
||||||
|
// We noticed a change, no need to filter anymore
|
||||||
|
object->removeEventFilter(this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool DBusMenuExporterDBus::AboutToShow(int id)
|
||||||
|
{
|
||||||
|
QMenu *menu = m_exporter->d->menuForId(id);
|
||||||
|
DMRETURN_VALUE_IF_FAIL(menu, false);
|
||||||
|
|
||||||
|
ActionEventFilter filter;
|
||||||
|
menu->installEventFilter(&filter);
|
||||||
|
QMetaObject::invokeMethod(menu, "aboutToShow");
|
||||||
|
return filter.mChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterDBus::setStatus(const QString& status)
|
||||||
|
{
|
||||||
|
if (m_status == status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_status = status;
|
||||||
|
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert("Status", QVariant(status));
|
||||||
|
|
||||||
|
QDBusMessage msg = QDBusMessage::createSignal(m_exporter->d->m_objectPath, FDO_PROPERTIES_INTERFACE, "PropertiesChanged");
|
||||||
|
QVariantList args = QVariantList()
|
||||||
|
<< DBUSMENU_INTERFACE
|
||||||
|
<< map
|
||||||
|
<< QStringList() // New properties: none
|
||||||
|
;
|
||||||
|
msg.setArguments(args);
|
||||||
|
QDBusConnection::sessionBus().send(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DBusMenuExporterDBus::status() const
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "dbusmenuexporterdbus_p.moc"
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUEXPORTERDBUS_P_H
|
||||||
|
#define DBUSMENUEXPORTERDBUS_P_H
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <dbusmenutypes_p.h>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QVariant>
|
||||||
|
#include <QtDBus/QDBusAbstractAdaptor>
|
||||||
|
#include <QtDBus/QDBusVariant>
|
||||||
|
|
||||||
|
class DBusMenuExporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class implementing the DBus side of DBusMenuExporter
|
||||||
|
* This avoid exposing the implementation of the DBusMenu spec to the outside
|
||||||
|
* world.
|
||||||
|
*/
|
||||||
|
class DBusMenuExporterDBus : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_CLASSINFO("D-Bus Interface", "com.canonical.dbusmenu")
|
||||||
|
Q_PROPERTY(uint Version READ Version)
|
||||||
|
Q_PROPERTY(QString Status READ status)
|
||||||
|
public:
|
||||||
|
DBusMenuExporterDBus(DBusMenuExporter *m_exporter);
|
||||||
|
|
||||||
|
uint Version() const { return 2; }
|
||||||
|
|
||||||
|
QString status() const;
|
||||||
|
void setStatus(const QString &status);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
Q_NOREPLY void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp);
|
||||||
|
QDBusVariant GetProperty(int id, const QString &property);
|
||||||
|
uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, DBusMenuLayoutItem &item);
|
||||||
|
DBusMenuItemList GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames);
|
||||||
|
bool AboutToShow(int id);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void ItemsPropertiesUpdated(DBusMenuItemList, DBusMenuItemKeysList);
|
||||||
|
void LayoutUpdated(uint revision, int parentId);
|
||||||
|
void ItemActivationRequested(int id, uint timeStamp);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DBusMenuExporter *m_exporter;
|
||||||
|
QString m_status;
|
||||||
|
|
||||||
|
friend class DBusMenuExporter;
|
||||||
|
friend class DBusMenuExporterPrivate;
|
||||||
|
|
||||||
|
QVariantMap getProperties(int id, const QStringList &names) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUEXPORTERDBUS_P_H */
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUEXPORTERPRIVATE_P_H
|
||||||
|
#define DBUSMENUEXPORTERPRIVATE_P_H
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenuexporter.h"
|
||||||
|
#include "dbusmenutypes_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QHash>
|
||||||
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QSet>
|
||||||
|
#include <QtCore/QVariant>
|
||||||
|
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
class DBusMenuExporterDBus;
|
||||||
|
|
||||||
|
class DBusMenuExporterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DBusMenuExporter *q;
|
||||||
|
|
||||||
|
QString m_objectPath;
|
||||||
|
|
||||||
|
DBusMenuExporterDBus *m_dbusObject;
|
||||||
|
|
||||||
|
QMenu *m_rootMenu;
|
||||||
|
QHash<QAction *, QVariantMap> m_actionProperties;
|
||||||
|
QMap<int, QAction *> m_actionForId;
|
||||||
|
QMap<QAction *, int> m_idForAction;
|
||||||
|
int m_nextId;
|
||||||
|
uint m_revision;
|
||||||
|
bool m_emittedLayoutUpdatedOnce;
|
||||||
|
|
||||||
|
QSet<int> m_itemUpdatedIds;
|
||||||
|
QTimer *m_itemUpdatedTimer;
|
||||||
|
|
||||||
|
QSet<int> m_layoutUpdatedIds;
|
||||||
|
QTimer *m_layoutUpdatedTimer;
|
||||||
|
|
||||||
|
int idForAction(QAction *action) const;
|
||||||
|
void addMenu(QMenu *menu, int parentId);
|
||||||
|
QVariantMap propertiesForAction(QAction *action) const;
|
||||||
|
QVariantMap propertiesForKMenuTitleAction(QAction *action_) const;
|
||||||
|
QVariantMap propertiesForSeparatorAction(QAction *action) const;
|
||||||
|
QVariantMap propertiesForStandardAction(QAction *action) const;
|
||||||
|
QMenu *menuForId(int id) const;
|
||||||
|
void fillLayoutItem(DBusMenuLayoutItem *item, QMenu *menu, int id, int depth, const QStringList &propertyNames);
|
||||||
|
|
||||||
|
void addAction(QAction *action, int parentId);
|
||||||
|
void updateAction(QAction *action);
|
||||||
|
void removeAction(QAction *action, int parentId);
|
||||||
|
/**
|
||||||
|
* Removes any reference from action in the exporter, but do not notify the
|
||||||
|
* change outside. This is useful when a submenu is destroyed because we do
|
||||||
|
* not receive QEvent::ActionRemoved events for its actions.
|
||||||
|
* IMPORTANT: action might have already been destroyed when this method is
|
||||||
|
* called, so don't dereference the pointer (it is a QObject to avoid being
|
||||||
|
* tempted to dereference)
|
||||||
|
*/
|
||||||
|
void removeActionInternal(QObject *action);
|
||||||
|
|
||||||
|
void emitLayoutUpdated(int id);
|
||||||
|
|
||||||
|
void insertIconProperty(QVariantMap* map, QAction *action) const;
|
||||||
|
|
||||||
|
void collapseSeparators(QMenu*);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* DBUSMENUEXPORTERPRIVATE_P_H */
|
|
@ -0,0 +1,585 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "dbusmenuimporter.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include <QDBusVariant>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QSignalMapper>
|
||||||
|
#include <QTime>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QWidgetAction>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "dbusmenutypes_p.h"
|
||||||
|
#include "dbusmenushortcut_p.h"
|
||||||
|
#include "debug_p.h"
|
||||||
|
#include "utils_p.h"
|
||||||
|
|
||||||
|
//#define BENCHMARK
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
#include <QTime>
|
||||||
|
static QTime sChrono;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char *DBUSMENU_INTERFACE = "com.canonical.dbusmenu";
|
||||||
|
|
||||||
|
static const int ABOUT_TO_SHOW_TIMEOUT = 3000;
|
||||||
|
static const int REFRESH_TIMEOUT = 4000;
|
||||||
|
|
||||||
|
static const char *DBUSMENU_PROPERTY_ID = "_dbusmenu_id";
|
||||||
|
static const char *DBUSMENU_PROPERTY_ICON_NAME = "_dbusmenu_icon_name";
|
||||||
|
static const char *DBUSMENU_PROPERTY_ICON_DATA_HASH = "_dbusmenu_icon_data_hash";
|
||||||
|
|
||||||
|
static QAction *createKdeTitle(QAction *action, QWidget *parent)
|
||||||
|
{
|
||||||
|
QToolButton *titleWidget = new QToolButton(0);
|
||||||
|
QFont font = titleWidget->font();
|
||||||
|
font.setBold(true);
|
||||||
|
titleWidget->setFont(font);
|
||||||
|
titleWidget->setIcon(action->icon());
|
||||||
|
titleWidget->setText(action->text());
|
||||||
|
titleWidget->setDown(true);
|
||||||
|
titleWidget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||||
|
|
||||||
|
QWidgetAction *titleAction = new QWidgetAction(parent);
|
||||||
|
titleAction->setDefaultWidget(titleWidget);
|
||||||
|
return titleAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DBusMenuImporterPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DBusMenuImporter *q;
|
||||||
|
|
||||||
|
QDBusAbstractInterface *m_interface;
|
||||||
|
QMenu *m_menu;
|
||||||
|
typedef QMap<int, QPointer<QAction> > ActionForId;
|
||||||
|
ActionForId m_actionForId;
|
||||||
|
QSignalMapper m_mapper;
|
||||||
|
QTimer *m_pendingLayoutUpdateTimer;
|
||||||
|
|
||||||
|
QSet<int> m_idsRefreshedByAboutToShow;
|
||||||
|
QSet<int> m_pendingLayoutUpdates;
|
||||||
|
|
||||||
|
bool m_mustEmitMenuUpdated;
|
||||||
|
|
||||||
|
DBusMenuImporterType m_type;
|
||||||
|
|
||||||
|
QDBusPendingCallWatcher *refresh(int id)
|
||||||
|
{
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
DMDEBUG << "Starting refresh chrono for id" << id;
|
||||||
|
sChrono.start();
|
||||||
|
#endif
|
||||||
|
QDBusPendingCall call = m_interface->asyncCall("GetLayout", id, 1, QStringList());
|
||||||
|
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, q);
|
||||||
|
watcher->setProperty(DBUSMENU_PROPERTY_ID, id);
|
||||||
|
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||||
|
q, SLOT(slotGetLayoutFinished(QDBusPendingCallWatcher*)));
|
||||||
|
|
||||||
|
return watcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *createMenu(QWidget *parent)
|
||||||
|
{
|
||||||
|
QMenu *menu = q->createMenu(parent);
|
||||||
|
QObject::connect(menu, SIGNAL(aboutToShow()),
|
||||||
|
q, SLOT(slotMenuAboutToShow()));
|
||||||
|
QObject::connect(menu, SIGNAL(aboutToHide()),
|
||||||
|
q, SLOT(slotMenuAboutToHide()));
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init all the immutable action properties here
|
||||||
|
* TODO: Document immutable properties?
|
||||||
|
*
|
||||||
|
* Note: we remove properties we handle from the map (using QMap::take()
|
||||||
|
* instead of QMap::value()) to avoid warnings about these properties in
|
||||||
|
* updateAction()
|
||||||
|
*/
|
||||||
|
QAction *createAction(int id, const QVariantMap &_map, QWidget *parent)
|
||||||
|
{
|
||||||
|
QVariantMap map = _map;
|
||||||
|
QAction *action = new QAction(parent);
|
||||||
|
action->setProperty(DBUSMENU_PROPERTY_ID, id);
|
||||||
|
|
||||||
|
QString type = map.take("type").toString();
|
||||||
|
if (type == "separator") {
|
||||||
|
action->setSeparator(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.take("children-display").toString() == "submenu") {
|
||||||
|
QMenu *menu = createMenu(parent);
|
||||||
|
action->setMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toggleType = map.take("toggle-type").toString();
|
||||||
|
if (!toggleType.isEmpty()) {
|
||||||
|
action->setCheckable(true);
|
||||||
|
if (toggleType == "radio") {
|
||||||
|
QActionGroup *group = new QActionGroup(action);
|
||||||
|
group->addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isKdeTitle = map.take("x-kde-title").toBool();
|
||||||
|
updateAction(action, map, map.keys());
|
||||||
|
|
||||||
|
if (isKdeTitle) {
|
||||||
|
action = createKdeTitle(action, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update mutable properties of an action. A property may be listed in
|
||||||
|
* requestedProperties but not in map, this means we should use the default value
|
||||||
|
* for this property.
|
||||||
|
*
|
||||||
|
* @param action the action to update
|
||||||
|
* @param map holds the property values
|
||||||
|
* @param requestedProperties which properties has been requested
|
||||||
|
*/
|
||||||
|
void updateAction(QAction *action, const QVariantMap &map, const QStringList &requestedProperties)
|
||||||
|
{
|
||||||
|
Q_FOREACH(const QString &key, requestedProperties) {
|
||||||
|
updateActionProperty(action, key, map.value(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionProperty(QAction *action, const QString &key, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (key == "label") {
|
||||||
|
updateActionLabel(action, value);
|
||||||
|
} else if (key == "enabled") {
|
||||||
|
updateActionEnabled(action, value);
|
||||||
|
} else if (key == "toggle-state") {
|
||||||
|
updateActionChecked(action, value);
|
||||||
|
} else if (key == "icon-name") {
|
||||||
|
updateActionIconByName(action, value);
|
||||||
|
} else if (key == "icon-data") {
|
||||||
|
updateActionIconByData(action, value);
|
||||||
|
} else if (key == "visible") {
|
||||||
|
updateActionVisible(action, value);
|
||||||
|
} else if (key == "shortcut") {
|
||||||
|
updateActionShortcut(action, value);
|
||||||
|
} else if (key == "children-display") {
|
||||||
|
} else {
|
||||||
|
DMWARNING << "Unhandled property update" << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionLabel(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
QString text = swapMnemonicChar(value.toString(), '_', '&');
|
||||||
|
action->setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionEnabled(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
action->setEnabled(value.isValid() ? value.toBool(): true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionChecked(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (action->isCheckable() && value.isValid()) {
|
||||||
|
action->setChecked(value.toInt() == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionIconByName(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
QString iconName = value.toString();
|
||||||
|
QString previous = action->property(DBUSMENU_PROPERTY_ICON_NAME).toString();
|
||||||
|
if (previous == iconName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setProperty(DBUSMENU_PROPERTY_ICON_NAME, iconName);
|
||||||
|
if (iconName.isEmpty()) {
|
||||||
|
action->setIcon(QIcon());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setIcon(q->iconForName(iconName));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionIconByData(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
QByteArray data = value.toByteArray();
|
||||||
|
uint dataHash = qHash(data);
|
||||||
|
uint previousDataHash = action->property(DBUSMENU_PROPERTY_ICON_DATA_HASH).toUInt();
|
||||||
|
if (previousDataHash == dataHash) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setProperty(DBUSMENU_PROPERTY_ICON_DATA_HASH, dataHash);
|
||||||
|
QPixmap pix;
|
||||||
|
if (!pix.loadFromData(data)) {
|
||||||
|
DMWARNING << "Failed to decode icon-data property for action" << action->text();
|
||||||
|
action->setIcon(QIcon());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
action->setIcon(QIcon(pix));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionVisible(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
action->setVisible(value.isValid() ? value.toBool() : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateActionShortcut(QAction *action, const QVariant &value)
|
||||||
|
{
|
||||||
|
QDBusArgument arg = value.value<QDBusArgument>();
|
||||||
|
DBusMenuShortcut dmShortcut;
|
||||||
|
arg >> dmShortcut;
|
||||||
|
QKeySequence keySequence = dmShortcut.toKeySequence();
|
||||||
|
action->setShortcut(keySequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *menuForId(int id) const
|
||||||
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
return q->menu();
|
||||||
|
}
|
||||||
|
QAction *action = m_actionForId.value(id);
|
||||||
|
if (!action) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return action->menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList);
|
||||||
|
|
||||||
|
void sendEvent(int id, const QString &eventId)
|
||||||
|
{
|
||||||
|
QVariant empty = QVariant::fromValue(QDBusVariant(QString()));
|
||||||
|
m_interface->asyncCall("Event", id, eventId, empty, 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitForWatcher(QDBusPendingCallWatcher * _watcher, int maxWait)
|
||||||
|
{
|
||||||
|
QPointer<QDBusPendingCallWatcher> watcher(_watcher);
|
||||||
|
|
||||||
|
if(m_type == ASYNCHRONOUS) {
|
||||||
|
QTimer timer;
|
||||||
|
timer.setSingleShot(true);
|
||||||
|
QEventLoop loop;
|
||||||
|
loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
|
||||||
|
loop.connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), SLOT(quit()));
|
||||||
|
timer.start(maxWait);
|
||||||
|
loop.exec();
|
||||||
|
timer.stop();
|
||||||
|
|
||||||
|
if (!watcher) {
|
||||||
|
// Watcher died. This can happen if importer got deleted while we were
|
||||||
|
// waiting. See:
|
||||||
|
// https://bugs.kde.org/show_bug.cgi?id=237156
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!watcher->isFinished()) {
|
||||||
|
// Timed out
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
watcher->waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watcher->isError()) {
|
||||||
|
DMWARNING << watcher->error().message();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBusMenuImporter::DBusMenuImporter(const QString &service, const QString &path, QObject *parent)
|
||||||
|
: DBusMenuImporter(service, path, ASYNCHRONOUS, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuImporter::DBusMenuImporter(const QString &service, const QString &path, DBusMenuImporterType type, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, d(new DBusMenuImporterPrivate)
|
||||||
|
{
|
||||||
|
DBusMenuTypes_register();
|
||||||
|
|
||||||
|
d->q = this;
|
||||||
|
d->m_interface = new QDBusInterface(service, path, DBUSMENU_INTERFACE, QDBusConnection::sessionBus(), this);
|
||||||
|
d->m_menu = 0;
|
||||||
|
d->m_mustEmitMenuUpdated = false;
|
||||||
|
|
||||||
|
d->m_type = type;
|
||||||
|
|
||||||
|
connect(&d->m_mapper, SIGNAL(mapped(int)), SLOT(sendClickedEvent(int)));
|
||||||
|
|
||||||
|
d->m_pendingLayoutUpdateTimer = new QTimer(this);
|
||||||
|
d->m_pendingLayoutUpdateTimer->setSingleShot(true);
|
||||||
|
connect(d->m_pendingLayoutUpdateTimer, SIGNAL(timeout()), SLOT(processPendingLayoutUpdates()));
|
||||||
|
|
||||||
|
// For some reason, using QObject::connect() does not work but
|
||||||
|
// QDBusConnect::connect() does
|
||||||
|
QDBusConnection::sessionBus().connect(service, path, DBUSMENU_INTERFACE, "LayoutUpdated", "ui",
|
||||||
|
this, SLOT(slotLayoutUpdated(uint, int)));
|
||||||
|
QDBusConnection::sessionBus().connect(service, path, DBUSMENU_INTERFACE, "ItemsPropertiesUpdated", "a(ia{sv})a(ias)",
|
||||||
|
this, SLOT(slotItemsPropertiesUpdated(DBusMenuItemList, DBusMenuItemKeysList)));
|
||||||
|
QDBusConnection::sessionBus().connect(service, path, DBUSMENU_INTERFACE, "ItemActivationRequested", "iu",
|
||||||
|
this, SLOT(slotItemActivationRequested(int, uint)));
|
||||||
|
|
||||||
|
d->refresh(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuImporter::~DBusMenuImporter()
|
||||||
|
{
|
||||||
|
// Do not use "delete d->m_menu": even if we are being deleted we should
|
||||||
|
// leave enough time for the menu to finish what it was doing, for example
|
||||||
|
// if it was being displayed.
|
||||||
|
d->m_menu->deleteLater();
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotLayoutUpdated(uint revision, int parentId)
|
||||||
|
{
|
||||||
|
if (d->m_idsRefreshedByAboutToShow.remove(parentId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->m_pendingLayoutUpdates << parentId;
|
||||||
|
if (!d->m_pendingLayoutUpdateTimer->isActive()) {
|
||||||
|
d->m_pendingLayoutUpdateTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::processPendingLayoutUpdates()
|
||||||
|
{
|
||||||
|
QSet<int> ids = d->m_pendingLayoutUpdates;
|
||||||
|
d->m_pendingLayoutUpdates.clear();
|
||||||
|
Q_FOREACH(int id, ids) {
|
||||||
|
d->refresh(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *DBusMenuImporter::menu() const
|
||||||
|
{
|
||||||
|
if (!d->m_menu) {
|
||||||
|
d->m_menu = d->createMenu(0);
|
||||||
|
}
|
||||||
|
return d->m_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterPrivate::slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList)
|
||||||
|
{
|
||||||
|
Q_FOREACH(const DBusMenuItem &item, updatedList) {
|
||||||
|
QAction *action = m_actionForId.value(item.id);
|
||||||
|
if (!action) {
|
||||||
|
// We don't know this action. It probably is in a menu we haven't fetched yet.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap::ConstIterator
|
||||||
|
it = item.properties.constBegin(),
|
||||||
|
end = item.properties.constEnd();
|
||||||
|
for(; it != end; ++it) {
|
||||||
|
updateActionProperty(action, it.key(), it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_FOREACH(const DBusMenuItemKeys &item, removedList) {
|
||||||
|
QAction *action = m_actionForId.value(item.id);
|
||||||
|
if (!action) {
|
||||||
|
// We don't know this action. It probably is in a menu we haven't fetched yet.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_FOREACH(const QString &key, item.properties) {
|
||||||
|
updateActionProperty(action, key, QVariant());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotItemActivationRequested(int id, uint /*timestamp*/)
|
||||||
|
{
|
||||||
|
QAction *action = d->m_actionForId.value(id);
|
||||||
|
DMRETURN_IF_FAIL(action);
|
||||||
|
actionActivationRequested(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotGetLayoutFinished(QDBusPendingCallWatcher *watcher)
|
||||||
|
{
|
||||||
|
int parentId = watcher->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
watcher->deleteLater();
|
||||||
|
|
||||||
|
QDBusPendingReply<uint, DBusMenuLayoutItem> reply = *watcher;
|
||||||
|
if (!reply.isValid()) {
|
||||||
|
DMWARNING << reply.error().message();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
DMDEBUG << "- items received:" << sChrono.elapsed() << "ms";
|
||||||
|
#endif
|
||||||
|
DBusMenuLayoutItem rootItem = reply.argumentAt<1>();
|
||||||
|
|
||||||
|
QMenu *menu = d->menuForId(parentId);
|
||||||
|
if (!menu) {
|
||||||
|
DMWARNING << "No menu for id" << parentId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->clear();
|
||||||
|
|
||||||
|
Q_FOREACH(const DBusMenuLayoutItem &dbusMenuItem, rootItem.children) {
|
||||||
|
QAction *action = d->createAction(dbusMenuItem.id, dbusMenuItem.properties, menu);
|
||||||
|
DBusMenuImporterPrivate::ActionForId::Iterator it = d->m_actionForId.find(dbusMenuItem.id);
|
||||||
|
if (it == d->m_actionForId.end()) {
|
||||||
|
d->m_actionForId.insert(dbusMenuItem.id, action);
|
||||||
|
} else {
|
||||||
|
delete *it;
|
||||||
|
*it = action;
|
||||||
|
}
|
||||||
|
menu->addAction(action);
|
||||||
|
|
||||||
|
connect(action, SIGNAL(triggered()),
|
||||||
|
&d->m_mapper, SLOT(map()));
|
||||||
|
d->m_mapper.setMapping(action, dbusMenuItem.id);
|
||||||
|
|
||||||
|
if( action->menu() )
|
||||||
|
{
|
||||||
|
d->refresh( dbusMenuItem.id )->waitForFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
DMDEBUG << "- Menu filled:" << sChrono.elapsed() << "ms";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::sendClickedEvent(int id)
|
||||||
|
{
|
||||||
|
d->sendEvent(id, QString("clicked"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::updateMenu()
|
||||||
|
{
|
||||||
|
d->m_mustEmitMenuUpdated = true;
|
||||||
|
QMetaObject::invokeMethod(menu(), "aboutToShow");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotMenuAboutToShow()
|
||||||
|
{
|
||||||
|
QMenu *menu = qobject_cast<QMenu*>(sender());
|
||||||
|
Q_ASSERT(menu);
|
||||||
|
|
||||||
|
QAction *action = menu->menuAction();
|
||||||
|
Q_ASSERT(action);
|
||||||
|
|
||||||
|
int id = action->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
QTime time;
|
||||||
|
time.start();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QDBusPendingCall call = d->m_interface->asyncCall("AboutToShow", id);
|
||||||
|
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||||
|
watcher->setProperty(DBUSMENU_PROPERTY_ID, id);
|
||||||
|
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||||
|
SLOT(slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher*)));
|
||||||
|
|
||||||
|
QPointer<QObject> guard(this);
|
||||||
|
|
||||||
|
if (!d->waitForWatcher(watcher, ABOUT_TO_SHOW_TIMEOUT)) {
|
||||||
|
DMWARNING << "Application did not answer to AboutToShow() before timeout";
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BENCHMARK
|
||||||
|
DMVAR(time.elapsed());
|
||||||
|
#endif
|
||||||
|
// "this" got deleted during the call to waitForWatcher(), get out
|
||||||
|
if (!guard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu == d->m_menu && d->m_mustEmitMenuUpdated) {
|
||||||
|
d->m_mustEmitMenuUpdated = false;
|
||||||
|
menuUpdated();
|
||||||
|
}
|
||||||
|
if (menu == d->m_menu) {
|
||||||
|
menuReadyToBeShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
d->sendEvent(id, QString("opened"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher *watcher)
|
||||||
|
{
|
||||||
|
int id = watcher->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
watcher->deleteLater();
|
||||||
|
|
||||||
|
QDBusPendingReply<bool> reply = *watcher;
|
||||||
|
if (reply.isError()) {
|
||||||
|
DMWARNING << "Call to AboutToShow() failed:" << reply.error().message();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool needRefresh = reply.argumentAt<0>();
|
||||||
|
|
||||||
|
QMenu *menu = d->menuForId(id);
|
||||||
|
DMRETURN_IF_FAIL(menu);
|
||||||
|
|
||||||
|
if (needRefresh || menu->actions().isEmpty()) {
|
||||||
|
d->m_idsRefreshedByAboutToShow << id;
|
||||||
|
QDBusPendingCallWatcher *watcher2 = d->refresh(id);
|
||||||
|
if (!d->waitForWatcher(watcher2, REFRESH_TIMEOUT)) {
|
||||||
|
DMWARNING << "Application did not refresh before timeout";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporter::slotMenuAboutToHide()
|
||||||
|
{
|
||||||
|
QMenu *menu = qobject_cast<QMenu*>(sender());
|
||||||
|
Q_ASSERT(menu);
|
||||||
|
|
||||||
|
QAction *action = menu->menuAction();
|
||||||
|
Q_ASSERT(action);
|
||||||
|
|
||||||
|
int id = action->property(DBUSMENU_PROPERTY_ID).toInt();
|
||||||
|
d->sendEvent(id, QString("closed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu *DBusMenuImporter::createMenu(QWidget *parent)
|
||||||
|
{
|
||||||
|
return new QMenu(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon DBusMenuImporter::iconForName(const QString &/*name*/)
|
||||||
|
{
|
||||||
|
return QIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dbusmenuimporter.moc"
|
|
@ -0,0 +1,143 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUIMPORTER_H
|
||||||
|
#define DBUSMENUIMPORTER_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <dbusmenu_export.h>
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QDBusAbstractInterface;
|
||||||
|
class QDBusPendingCallWatcher;
|
||||||
|
class QDBusVariant;
|
||||||
|
class QIcon;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
class DBusMenuImporterPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether internal method calls should allow the Qt event loop
|
||||||
|
* to execute or not
|
||||||
|
*/
|
||||||
|
enum DBusMenuImporterType {
|
||||||
|
ASYNCHRONOUS,
|
||||||
|
SYNCHRONOUS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DBusMenuImporter instance can recreate a menu serialized over DBus by
|
||||||
|
* DBusMenuExporter
|
||||||
|
*/
|
||||||
|
class DBUSMENU_EXPORT DBusMenuImporter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a DBusMenuImporter listening over DBus on service, path
|
||||||
|
*/
|
||||||
|
DBusMenuImporter(const QString &service, const QString &path, QObject *parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DBusMenuImporter listening over DBus on service, path, with either async
|
||||||
|
* or sync DBus calls
|
||||||
|
*/
|
||||||
|
DBusMenuImporter(const QString &service, const QString &path, DBusMenuImporterType type, QObject *parent = 0);
|
||||||
|
|
||||||
|
virtual ~DBusMenuImporter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu created from listening to the DBusMenuExporter over DBus
|
||||||
|
*/
|
||||||
|
QMenu *menu() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
/**
|
||||||
|
* Simulates a QMenu::aboutToShow() signal on the menu returned by menu(),
|
||||||
|
* ensuring it is up to date in case the menu is populated on the fly. It
|
||||||
|
* is not mandatory to call this method, showing the menu with
|
||||||
|
* QMenu::popup() or QMenu::exec() will generates an aboutToShow() signal,
|
||||||
|
* but calling it before ensures the size-hint of the menu is correct when
|
||||||
|
* it is time to show it, avoiding wrong positioning.
|
||||||
|
*
|
||||||
|
* menuUpdated() will be emitted when the menu is ready.
|
||||||
|
*
|
||||||
|
* Not that the aboutToShow() signal is only sent to the root menu, not to
|
||||||
|
* any submenu.
|
||||||
|
*/
|
||||||
|
void updateMenu();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
/**
|
||||||
|
* Emitted after a call to updateMenu().
|
||||||
|
* @see updateMenu()
|
||||||
|
*/
|
||||||
|
void menuUpdated();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted after every aboutToShow of the root menu.
|
||||||
|
* This signal is deprecated and only kept to keep compatibility with
|
||||||
|
* dbusmenu-qt 0.3.x. New code should use updateMenu() and menuUpdated()
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
void menuReadyToBeShown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the exporter was asked to activate an action
|
||||||
|
*/
|
||||||
|
void actionActivationRequested(QAction *);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Must create a menu, may be customized to fit host appearance.
|
||||||
|
* Default implementation creates a simple QMenu.
|
||||||
|
*/
|
||||||
|
virtual QMenu *createMenu(QWidget *parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must convert a name into an icon.
|
||||||
|
* Default implementation returns a null icon.
|
||||||
|
*/
|
||||||
|
virtual QIcon iconForName(const QString &);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void sendClickedEvent(int);
|
||||||
|
void slotMenuAboutToShow();
|
||||||
|
void slotMenuAboutToHide();
|
||||||
|
void slotAboutToShowDBusCallFinished(QDBusPendingCallWatcher *);
|
||||||
|
void slotItemActivationRequested(int id, uint timestamp);
|
||||||
|
void processPendingLayoutUpdates();
|
||||||
|
void slotLayoutUpdated(uint revision, int parentId);
|
||||||
|
void slotGetLayoutFinished(QDBusPendingCallWatcher *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(DBusMenuImporter)
|
||||||
|
DBusMenuImporterPrivate *const d;
|
||||||
|
friend class DBusMenuImporterPrivate;
|
||||||
|
|
||||||
|
// Use Q_PRIVATE_SLOT to avoid exposing DBusMenuItemList
|
||||||
|
Q_PRIVATE_SLOT(d, void slotItemsPropertiesUpdated(const DBusMenuItemList &updatedList, const DBusMenuItemKeysList &removedList))
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUIMPORTER_H */
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "dbusmenushortcut_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtGui/QKeySequence>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "debug_p.h"
|
||||||
|
|
||||||
|
static const int QT_COLUMN = 0;
|
||||||
|
static const int DM_COLUMN = 1;
|
||||||
|
|
||||||
|
static void processKeyTokens(QStringList* tokens, int srcCol, int dstCol)
|
||||||
|
{
|
||||||
|
struct Row {
|
||||||
|
const char* zero;
|
||||||
|
const char* one;
|
||||||
|
const char* operator[](int col) const { return col == 0 ? zero : one; }
|
||||||
|
};
|
||||||
|
static const Row table[] =
|
||||||
|
{ {"Meta", "Super"},
|
||||||
|
{"Ctrl", "Control"},
|
||||||
|
// Special cases for compatibility with libdbusmenu-glib which uses
|
||||||
|
// "plus" for "+" and "minus" for "-".
|
||||||
|
// cf https://bugs.launchpad.net/libdbusmenu-qt/+bug/712565
|
||||||
|
{"+", "plus"},
|
||||||
|
{"-", "minus"},
|
||||||
|
{0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Row* ptr = table;
|
||||||
|
for (; ptr->zero != 0; ++ptr) {
|
||||||
|
const char* from = (*ptr)[srcCol];
|
||||||
|
const char* to = (*ptr)[dstCol];
|
||||||
|
tokens->replaceInStrings(from, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuShortcut DBusMenuShortcut::fromKeySequence(const QKeySequence& sequence)
|
||||||
|
{
|
||||||
|
QString string = sequence.toString();
|
||||||
|
DBusMenuShortcut shortcut;
|
||||||
|
QStringList tokens = string.split(", ");
|
||||||
|
Q_FOREACH(QString token, tokens) {
|
||||||
|
// Hack: Qt::CTRL | Qt::Key_Plus is turned into the string "Ctrl++",
|
||||||
|
// but we don't want the call to token.split() to consider the
|
||||||
|
// second '+' as a separator so we replace it with its final value.
|
||||||
|
token.replace("++", "+plus");
|
||||||
|
QStringList keyTokens = token.split('+');
|
||||||
|
processKeyTokens(&keyTokens, QT_COLUMN, DM_COLUMN);
|
||||||
|
shortcut << keyTokens;
|
||||||
|
}
|
||||||
|
return shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence DBusMenuShortcut::toKeySequence() const
|
||||||
|
{
|
||||||
|
QStringList tmp;
|
||||||
|
Q_FOREACH(const QStringList& keyTokens_, *this) {
|
||||||
|
QStringList keyTokens = keyTokens_;
|
||||||
|
processKeyTokens(&keyTokens, DM_COLUMN, QT_COLUMN);
|
||||||
|
tmp << keyTokens.join(QLatin1String("+"));
|
||||||
|
}
|
||||||
|
QString string = tmp.join(QLatin1String(", "));
|
||||||
|
return QKeySequence::fromString(string);
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUSHORTCUT_H
|
||||||
|
#define DBUSMENUSHORTCUT_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QMetaType>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <dbusmenu_export.h>
|
||||||
|
|
||||||
|
|
||||||
|
class QKeySequence;
|
||||||
|
|
||||||
|
class DBUSMENU_EXPORT DBusMenuShortcut : public QList<QStringList>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QKeySequence toKeySequence() const;
|
||||||
|
static DBusMenuShortcut fromKeySequence(const QKeySequence&);
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuShortcut)
|
||||||
|
|
||||||
|
#endif /* DBUSMENUSHORTCUT_H */
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "dbusmenutypes_p.h"
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <dbusmenushortcut_p.h>
|
||||||
|
#include <debug_p.h>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QDBusArgument>
|
||||||
|
#include <QDBusMetaType>
|
||||||
|
|
||||||
|
//// DBusMenuItem
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << obj.id << obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> obj.id >> obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// DBusMenuItemKeys
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItemKeys &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << obj.id << obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItemKeys &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> obj.id >> obj.properties;
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// DBusMenuLayoutItem
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument << obj.id << obj.properties;
|
||||||
|
argument.beginArray(qMetaTypeId<QDBusVariant>());
|
||||||
|
Q_FOREACH(const DBusMenuLayoutItem& child, obj.children) {
|
||||||
|
argument << QDBusVariant(QVariant::fromValue<DBusMenuLayoutItem>(child));
|
||||||
|
}
|
||||||
|
argument.endArray();
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &obj)
|
||||||
|
{
|
||||||
|
argument.beginStructure();
|
||||||
|
argument >> obj.id >> obj.properties;
|
||||||
|
argument.beginArray();
|
||||||
|
while (!argument.atEnd()) {
|
||||||
|
QDBusVariant dbusVariant;
|
||||||
|
argument >> dbusVariant;
|
||||||
|
QDBusArgument childArgument = dbusVariant.variant().value<QDBusArgument>();
|
||||||
|
|
||||||
|
DBusMenuLayoutItem child;
|
||||||
|
childArgument >> child;
|
||||||
|
obj.children.append(child);
|
||||||
|
}
|
||||||
|
argument.endArray();
|
||||||
|
argument.endStructure();
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuTypes_register()
|
||||||
|
{
|
||||||
|
static bool registered = false;
|
||||||
|
if (registered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDBusRegisterMetaType<DBusMenuItem>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuItemList>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuItemKeys>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuItemKeysList>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuLayoutItem>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuLayoutItemList>();
|
||||||
|
qDBusRegisterMetaType<DBusMenuShortcut>();
|
||||||
|
registered = true;
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUTYPES_P_H
|
||||||
|
#define DBUSMENUTYPES_P_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
#include <QtCore/QVariant>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <dbusmenu_export.h>
|
||||||
|
|
||||||
|
class QDBusArgument;
|
||||||
|
|
||||||
|
//// DBusMenuItem
|
||||||
|
/**
|
||||||
|
* Internal struct used to communicate on DBus
|
||||||
|
*/
|
||||||
|
struct DBUSMENU_EXPORT DBusMenuItem
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
QVariantMap properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItem)
|
||||||
|
|
||||||
|
DBUSMENU_EXPORT QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItem &item);
|
||||||
|
DBUSMENU_EXPORT const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItem &item);
|
||||||
|
|
||||||
|
typedef QList<DBusMenuItem> DBusMenuItemList;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItemList)
|
||||||
|
|
||||||
|
|
||||||
|
//// DBusMenuItemKeys
|
||||||
|
/**
|
||||||
|
* Represents a list of keys for a menu item
|
||||||
|
*/
|
||||||
|
struct DBUSMENU_EXPORT DBusMenuItemKeys
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
QStringList properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItemKeys)
|
||||||
|
|
||||||
|
DBUSMENU_EXPORT QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuItemKeys &);
|
||||||
|
DBUSMENU_EXPORT const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuItemKeys &);
|
||||||
|
|
||||||
|
typedef QList<DBusMenuItemKeys> DBusMenuItemKeysList;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuItemKeysList)
|
||||||
|
|
||||||
|
//// DBusMenuLayoutItem
|
||||||
|
/**
|
||||||
|
* Represents an item with its children. GetLayout() returns a
|
||||||
|
* DBusMenuLayoutItemList.
|
||||||
|
*/
|
||||||
|
struct DBusMenuLayoutItem;
|
||||||
|
struct DBUSMENU_EXPORT DBusMenuLayoutItem
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
QVariantMap properties;
|
||||||
|
QList<DBusMenuLayoutItem> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuLayoutItem)
|
||||||
|
|
||||||
|
DBUSMENU_EXPORT QDBusArgument &operator<<(QDBusArgument &argument, const DBusMenuLayoutItem &);
|
||||||
|
DBUSMENU_EXPORT const QDBusArgument &operator>>(const QDBusArgument &argument, DBusMenuLayoutItem &);
|
||||||
|
|
||||||
|
typedef QList<DBusMenuLayoutItem> DBusMenuLayoutItemList;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(DBusMenuLayoutItemList)
|
||||||
|
|
||||||
|
void DBusMenuTypes_register();
|
||||||
|
#endif /* DBUSMENUTYPES_P_H */
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DEBUG_P_H
|
||||||
|
#define DEBUG_P_H
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#define _DMBLUE "\033[34m"
|
||||||
|
#define _DMRED "\033[31m"
|
||||||
|
#define _DMRESET "\033[0m"
|
||||||
|
#define _DMTRACE(level, color) (level().nospace() << color << __PRETTY_FUNCTION__ << _DMRESET ":").space()
|
||||||
|
|
||||||
|
// Simple macros to get KDebug like support
|
||||||
|
#define DMDEBUG _DMTRACE(qDebug, _DMBLUE)
|
||||||
|
#define DMWARNING _DMTRACE(qWarning, _DMRED)
|
||||||
|
|
||||||
|
// Log a variable name and value
|
||||||
|
#define DMVAR(var) DMDEBUG << #var ":" << var
|
||||||
|
|
||||||
|
#define DMRETURN_IF_FAIL(cond) if (!(cond)) { \
|
||||||
|
DMWARNING << "Condition failed: " #cond; \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DMRETURN_VALUE_IF_FAIL(cond, value) if (!(cond)) { \
|
||||||
|
DMWARNING << "Condition failed: " #cond; \
|
||||||
|
return (value); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DEBUG_P_H */
|
|
@ -0,0 +1,64 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "utils_p.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QString swapMnemonicChar(const QString &in, const char src, const char dst)
|
||||||
|
{
|
||||||
|
QString out;
|
||||||
|
bool mnemonicFound = false;
|
||||||
|
|
||||||
|
for (int pos = 0; pos < in.length(); ) {
|
||||||
|
QChar ch = in[pos];
|
||||||
|
if (ch == src) {
|
||||||
|
if (pos == in.length() - 1) {
|
||||||
|
// 'src' at the end of string, skip it
|
||||||
|
++pos;
|
||||||
|
} else {
|
||||||
|
if (in[pos + 1] == src) {
|
||||||
|
// A real 'src'
|
||||||
|
out += src;
|
||||||
|
pos += 2;
|
||||||
|
} else if (!mnemonicFound) {
|
||||||
|
// We found the mnemonic
|
||||||
|
mnemonicFound = true;
|
||||||
|
out += dst;
|
||||||
|
++pos;
|
||||||
|
} else {
|
||||||
|
// We already have a mnemonic, just skip the char
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ch == dst) {
|
||||||
|
// Escape 'dst'
|
||||||
|
out += dst;
|
||||||
|
out += dst;
|
||||||
|
++pos;
|
||||||
|
} else {
|
||||||
|
out += ch;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef UTILS_P_H
|
||||||
|
#define UTILS_P_H
|
||||||
|
|
||||||
|
class QString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap mnemonic char: Qt uses '&', while dbusmenu uses '_'
|
||||||
|
*/
|
||||||
|
QString swapMnemonicChar(const QString &in, const char src, const char dst);
|
||||||
|
|
||||||
|
#endif /* UTILS_P_H */
|
|
@ -0,0 +1,124 @@
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
qt4_automoc(slowmenu.cpp)
|
||||||
|
endif()
|
||||||
|
add_executable(slowmenu slowmenu.cpp)
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
target_link_libraries(slowmenu
|
||||||
|
${QT_QTGUI_LIBRARIES}
|
||||||
|
${QT_QTDBUS_LIBRARIES}
|
||||||
|
${QT_QTCORE_LIBRARIES}
|
||||||
|
dbusmenu-qt
|
||||||
|
)
|
||||||
|
|
||||||
|
set(test_LIBRARIES
|
||||||
|
${QT_QTGUI_LIBRARY}
|
||||||
|
${QT_QTCORE_LIBRARY}
|
||||||
|
${QT_QTDBUS_LIBRARY}
|
||||||
|
${QT_QTTEST_LIBRARY}
|
||||||
|
dbusmenu-qt
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/../src
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${QT_QTTEST_INCLUDE_DIR}
|
||||||
|
${QT_QTDBUS_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
find_package(Qt5Test REQUIRED)
|
||||||
|
|
||||||
|
target_link_libraries(slowmenu
|
||||||
|
${Qt5Gui_LIBRARIES}
|
||||||
|
${Qt5Core_LIBRARIES}
|
||||||
|
${Qt5DBus_LIBRARIES}
|
||||||
|
dbusmenu-qt5
|
||||||
|
)
|
||||||
|
|
||||||
|
set(test_LIBRARIES
|
||||||
|
${Qt5Gui_LIBRARIES}
|
||||||
|
${Qt5Core_LIBRARIES}
|
||||||
|
${Qt5DBus_LIBRARIES}
|
||||||
|
${Qt5Test_LIBRARIES}
|
||||||
|
dbusmenu-qt5
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/../src
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${Qt5Test_INCLUDE_DIRS}
|
||||||
|
${Qt5DBus_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Macros to create "check" target
|
||||||
|
set(_test_executable_list "")
|
||||||
|
|
||||||
|
macro(add_test_executable _executable)
|
||||||
|
add_test(${_executable} ${_executable})
|
||||||
|
set(_test_executable_list "${_test_executable_list};${_executable}")
|
||||||
|
add_executable(${_executable} ${ARGN})
|
||||||
|
endmacro(add_test_executable)
|
||||||
|
|
||||||
|
# Call this at the end
|
||||||
|
macro(create_check_target)
|
||||||
|
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose
|
||||||
|
DEPENDS ${_test_executable_list})
|
||||||
|
endmacro(create_check_target)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
|
||||||
|
# dbusmenuexportertest
|
||||||
|
set(dbusmenuexportertest_SRCS
|
||||||
|
dbusmenuexportertest.cpp
|
||||||
|
testutils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
qt4_automoc(${dbusmenuexportertest_SRCS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_test_executable(dbusmenuexportertest ${dbusmenuexportertest_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(dbusmenuexportertest
|
||||||
|
${test_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# dbusmenuimportertest
|
||||||
|
set(dbusmenuimportertest_SRCS
|
||||||
|
dbusmenuimportertest.cpp
|
||||||
|
testutils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
qt4_automoc(${dbusmenuimportertest_SRCS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_test_executable(dbusmenuimportertest ${dbusmenuimportertest_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(dbusmenuimportertest
|
||||||
|
${test_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# dbusmenushortcuttest
|
||||||
|
set(dbusmenushortcuttest_SRCS
|
||||||
|
dbusmenushortcuttest.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
qt4_automoc(${dbusmenushortcuttest_SRCS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_test_executable(dbusmenushortcuttest ${dbusmenushortcuttest_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(dbusmenushortcuttest
|
||||||
|
${test_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Keep this at the end
|
||||||
|
create_check_target()
|
|
@ -0,0 +1,815 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
// Self
|
||||||
|
#include "dbusmenuexportertest.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
// DBusMenuQt
|
||||||
|
#include <dbusmenuexporter.h>
|
||||||
|
#include <dbusmenutypes_p.h>
|
||||||
|
#include <dbusmenushortcut_p.h>
|
||||||
|
#include <debug_p.h>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "testutils.h"
|
||||||
|
|
||||||
|
QTEST_MAIN(DBusMenuExporterTest)
|
||||||
|
|
||||||
|
static const char *TEST_SERVICE = "org.kde.dbusmenu-qt-test";
|
||||||
|
static const char *TEST_OBJECT_PATH = "/TestMenuBar";
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QList<int>)
|
||||||
|
|
||||||
|
static DBusMenuLayoutItemList getChildren(QDBusAbstractInterface* iface, int parentId, const QStringList &propertyNames)
|
||||||
|
{
|
||||||
|
QDBusPendingReply<uint, DBusMenuLayoutItem> reply = iface->call("GetLayout", parentId, /*recursionDepth=*/ 1, propertyNames);
|
||||||
|
reply.waitForFinished();
|
||||||
|
if (!reply.isValid()) {
|
||||||
|
qFatal("%s", qPrintable(reply.error().message()));
|
||||||
|
return DBusMenuLayoutItemList();
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuLayoutItem rootItem = reply.argumentAt<1>();
|
||||||
|
return rootItem.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::init()
|
||||||
|
{
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::cleanup()
|
||||||
|
{
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().unregisterService(TEST_SERVICE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testGetSomeProperties_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("label");
|
||||||
|
QTest::addColumn<QString>("iconName");
|
||||||
|
QTest::addColumn<bool>("enabled");
|
||||||
|
|
||||||
|
QTest::newRow("label only") << "label" << QString() << true;
|
||||||
|
QTest::newRow("disabled, label only") << "label" << QString() << false;
|
||||||
|
QTest::newRow("icon name") << "label" << "edit-undo" << true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testGetSomeProperties()
|
||||||
|
{
|
||||||
|
QFETCH(QString, label);
|
||||||
|
QFETCH(QString, iconName);
|
||||||
|
QFETCH(bool, enabled);
|
||||||
|
|
||||||
|
// Create an exporter for a menu with one action, defined by the test data
|
||||||
|
QMenu inputMenu;
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *action = new QAction(label, &inputMenu);
|
||||||
|
if (!iconName.isEmpty()) {
|
||||||
|
QIcon icon = QIcon::fromTheme(iconName);
|
||||||
|
QVERIFY(!icon.isNull());
|
||||||
|
action->setIcon(icon);
|
||||||
|
}
|
||||||
|
action->setEnabled(enabled);
|
||||||
|
inputMenu.addAction(action);
|
||||||
|
|
||||||
|
// Check out exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
// Get exported menu info
|
||||||
|
QStringList propertyNames = QStringList() << "type" << "enabled" << "label" << "icon-name";
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, /*parentId=*/0, propertyNames);
|
||||||
|
DBusMenuLayoutItem item = list.first();
|
||||||
|
QVERIFY(item.id != 0);
|
||||||
|
QVERIFY(item.children.isEmpty());
|
||||||
|
QVERIFY(!item.properties.contains("type"));
|
||||||
|
QCOMPARE(item.properties.value("label").toString(), label);
|
||||||
|
if (enabled) {
|
||||||
|
QVERIFY(!item.properties.contains("enabled"));
|
||||||
|
} else {
|
||||||
|
QCOMPARE(item.properties.value("enabled").toBool(), false);
|
||||||
|
}
|
||||||
|
if (iconName.isEmpty()) {
|
||||||
|
QVERIFY(!item.properties.contains("icon-name"));
|
||||||
|
} else {
|
||||||
|
QCOMPARE(item.properties.value("icon-name").toString(), iconName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testGetAllProperties()
|
||||||
|
{
|
||||||
|
// set of properties which must be returned because their values are not
|
||||||
|
// the default values
|
||||||
|
const QSet<QString> a1Properties = QSet<QString>()
|
||||||
|
<< "label"
|
||||||
|
;
|
||||||
|
|
||||||
|
const QSet<QString> separatorProperties = QSet<QString>()
|
||||||
|
<< "type";
|
||||||
|
|
||||||
|
const QSet<QString> a2Properties = QSet<QString>()
|
||||||
|
<< "label"
|
||||||
|
<< "enabled"
|
||||||
|
<< "icon-name"
|
||||||
|
<< "icon-data" // Icon data is always provided if the icon is valid.
|
||||||
|
<< "visible"
|
||||||
|
;
|
||||||
|
|
||||||
|
// Create the menu items
|
||||||
|
QMenu inputMenu;
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
inputMenu.addAction("a1");
|
||||||
|
|
||||||
|
inputMenu.addSeparator();
|
||||||
|
|
||||||
|
QAction *a2 = new QAction("a2", &inputMenu);
|
||||||
|
a2->setEnabled(false);
|
||||||
|
QIcon icon = QIcon::fromTheme("edit-undo");
|
||||||
|
QVERIFY(!icon.isNull());
|
||||||
|
a2->setIcon(icon);
|
||||||
|
a2->setVisible(false);
|
||||||
|
inputMenu.addAction(a2);
|
||||||
|
|
||||||
|
// Export them
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
// Get children
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 3);
|
||||||
|
|
||||||
|
// Check we get the right properties
|
||||||
|
DBusMenuLayoutItem item = list.takeFirst();
|
||||||
|
QCOMPARE(QSet<QString>::fromList(item.properties.keys()), a1Properties);
|
||||||
|
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(QSet<QString>::fromList(item.properties.keys()), separatorProperties);
|
||||||
|
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(QSet<QString>::fromList(item.properties.keys()), a2Properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testGetNonExistentProperty()
|
||||||
|
{
|
||||||
|
const char* NON_EXISTENT_KEY = "i-do-not-exist";
|
||||||
|
|
||||||
|
QMenu inputMenu;
|
||||||
|
inputMenu.addAction("a1");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList() << NON_EXISTENT_KEY);
|
||||||
|
QCOMPARE(list.count(), 1);
|
||||||
|
|
||||||
|
DBusMenuLayoutItem item = list.takeFirst();
|
||||||
|
QVERIFY(!item.properties.contains(NON_EXISTENT_KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testClickedEvent()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *action = inputMenu.addAction("a1");
|
||||||
|
QSignalSpy spy(action, SIGNAL(triggered()));
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 1);
|
||||||
|
int id = list.first().id;
|
||||||
|
|
||||||
|
QVariant empty = QVariant::fromValue(QDBusVariant(QString()));
|
||||||
|
uint timestamp = QDateTime::currentDateTime().toTime_t();
|
||||||
|
iface.call("Event", id, "clicked", empty, timestamp);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testSubMenu()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QMenu *subMenu = inputMenu.addMenu("menu");
|
||||||
|
QAction *a1 = subMenu->addAction("a1");
|
||||||
|
QAction *a2 = subMenu->addAction("a2");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 1);
|
||||||
|
int id = list.first().id;
|
||||||
|
|
||||||
|
list = getChildren(&iface, id, QStringList());
|
||||||
|
QCOMPARE(list.count(), 2);
|
||||||
|
|
||||||
|
DBusMenuLayoutItem item = list.takeFirst();
|
||||||
|
QVERIFY(item.id != 0);
|
||||||
|
QCOMPARE(item.properties.value("label").toString(), a1->text());
|
||||||
|
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("label").toString(), a2->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testDynamicSubMenu()
|
||||||
|
{
|
||||||
|
// Track LayoutUpdated() signal: we don't want this signal to be emitted
|
||||||
|
// too often because it causes refreshes
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
ManualSignalSpy layoutUpdatedSpy;
|
||||||
|
QDBusConnection::sessionBus().connect(TEST_SERVICE, TEST_OBJECT_PATH, "com.canonical.dbusmenu", "LayoutUpdated", "ui", &layoutUpdatedSpy, SLOT(receiveCall(uint, int)));
|
||||||
|
|
||||||
|
// Create our test menu
|
||||||
|
QMenu inputMenu;
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
QAction *action = inputMenu.addAction("menu");
|
||||||
|
QMenu *subMenu = new QMenu(&inputMenu);
|
||||||
|
action->setMenu(subMenu);
|
||||||
|
MenuFiller filler(subMenu);
|
||||||
|
filler.addAction(new QAction("a1", subMenu));
|
||||||
|
filler.addAction(new QAction("a2", subMenu));
|
||||||
|
|
||||||
|
// Get id of submenu
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 1);
|
||||||
|
int id = list.first().id;
|
||||||
|
|
||||||
|
// Nothing for now
|
||||||
|
QCOMPARE(subMenu->actions().count(), 0);
|
||||||
|
|
||||||
|
// LayoutUpdated should be emitted once because inputMenu is filled
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(layoutUpdatedSpy.count(), 1);
|
||||||
|
QCOMPARE(layoutUpdatedSpy.takeFirst().at(1).toInt(), 0);
|
||||||
|
|
||||||
|
// Pretend we show the menu
|
||||||
|
QDBusReply<bool> aboutToShowReply = iface.call("AboutToShow", id);
|
||||||
|
QVERIFY2(aboutToShowReply.isValid(), qPrintable(aboutToShowReply.error().message()));
|
||||||
|
QVERIFY(aboutToShowReply.value());
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(layoutUpdatedSpy.count(), 1);
|
||||||
|
QCOMPARE(layoutUpdatedSpy.takeFirst().at(1).toInt(), id);
|
||||||
|
|
||||||
|
// Get submenu items
|
||||||
|
list = getChildren(&iface, id, QStringList());
|
||||||
|
QVERIFY(subMenu->actions().count() > 0);
|
||||||
|
QCOMPARE(list.count(), subMenu->actions().count());
|
||||||
|
|
||||||
|
for (int pos=0; pos< list.count(); ++pos) {
|
||||||
|
DBusMenuLayoutItem item = list.at(pos);
|
||||||
|
QVERIFY(item.id != 0);
|
||||||
|
QAction *action = subMenu->actions().at(pos);
|
||||||
|
QVERIFY(action);
|
||||||
|
QCOMPARE(item.properties.value("label").toString(), action->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testRadioItems()
|
||||||
|
{
|
||||||
|
DBusMenuLayoutItem item;
|
||||||
|
DBusMenuLayoutItemList list;
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Create 2 radio items, check first one
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
a1->setCheckable(true);
|
||||||
|
QAction *a2 = inputMenu.addAction("a1");
|
||||||
|
a2->setCheckable(true);
|
||||||
|
|
||||||
|
QActionGroup group(0);
|
||||||
|
group.addAction(a1);
|
||||||
|
group.addAction(a2);
|
||||||
|
a1->setChecked(true);
|
||||||
|
|
||||||
|
QVERIFY(!a2->isChecked());
|
||||||
|
|
||||||
|
// Get item ids
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 2);
|
||||||
|
|
||||||
|
// Check items are radios and correctly toggled
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("toggle-type").toString(), QString("radio"));
|
||||||
|
QCOMPARE(item.properties.value("toggle-state").toInt(), 1);
|
||||||
|
int a1Id = item.id;
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("toggle-type").toString(), QString("radio"));
|
||||||
|
QCOMPARE(item.properties.value("toggle-state").toInt(), 0);
|
||||||
|
int a2Id = item.id;
|
||||||
|
|
||||||
|
// Click a2
|
||||||
|
ManualSignalSpy spy;
|
||||||
|
QDBusConnection::sessionBus().connect(TEST_SERVICE, TEST_OBJECT_PATH, "com.canonical.dbusmenu", "ItemsPropertiesUpdated", "a(ia{sv})a(ias)",
|
||||||
|
&spy, SLOT(receiveCall(DBusMenuItemList, DBusMenuItemKeysList)));
|
||||||
|
QVariant empty = QVariant::fromValue(QDBusVariant(QString()));
|
||||||
|
uint timestamp = QDateTime::currentDateTime().toTime_t();
|
||||||
|
iface.call("Event", a2Id, "clicked", empty, timestamp);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Check a1 is not checked, but a2 is
|
||||||
|
list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 2);
|
||||||
|
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("toggle-state").toInt(), 0);
|
||||||
|
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("toggle-state").toInt(), 1);
|
||||||
|
|
||||||
|
// Did we get notified?
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
QSet<int> updatedIds;
|
||||||
|
{
|
||||||
|
QVariantList lst = spy.takeFirst().at(0).toList();
|
||||||
|
Q_FOREACH(QVariant variant, lst) {
|
||||||
|
updatedIds << variant.toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<int> expectedIds;
|
||||||
|
expectedIds << a1Id << a2Id;
|
||||||
|
|
||||||
|
QCOMPARE(updatedIds, expectedIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testNonExclusiveActionGroup()
|
||||||
|
{
|
||||||
|
DBusMenuLayoutItem item;
|
||||||
|
DBusMenuLayoutItemList list;
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Create 2 checkable items
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
a1->setCheckable(true);
|
||||||
|
QAction *a2 = inputMenu.addAction("a1");
|
||||||
|
a2->setCheckable(true);
|
||||||
|
|
||||||
|
// Put them into a non exclusive group
|
||||||
|
QActionGroup group(0);
|
||||||
|
group.addAction(a1);
|
||||||
|
group.addAction(a2);
|
||||||
|
group.setExclusive(false);
|
||||||
|
|
||||||
|
// Get item ids
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 2);
|
||||||
|
|
||||||
|
// Check items are checkmark, not radio
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("toggle-type").toString(), QString("checkmark"));
|
||||||
|
int a1Id = item.id;
|
||||||
|
item = list.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("toggle-type").toString(), QString("checkmark"));
|
||||||
|
int a2Id = item.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testClickDeletedAction()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
|
||||||
|
// Get id
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), 1);
|
||||||
|
int id = list.takeFirst().id;
|
||||||
|
|
||||||
|
// Delete a1, it should not cause a crash when trying to trigger it
|
||||||
|
delete a1;
|
||||||
|
|
||||||
|
// Send a click to deleted a1
|
||||||
|
QVariant empty = QVariant::fromValue(QDBusVariant(QString()));
|
||||||
|
uint timestamp = QDateTime::currentDateTime().toTime_t();
|
||||||
|
iface.call("Event", id, "clicked", empty, timestamp);
|
||||||
|
QTest::qWait(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reproduce LP BUG 521011
|
||||||
|
// https://bugs.launchpad.net/bugs/521011
|
||||||
|
void DBusMenuExporterTest::testDeleteExporterBeforeMenu()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
delete exporter;
|
||||||
|
inputMenu.removeAction(a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testUpdateAndDeleteSubMenu()
|
||||||
|
{
|
||||||
|
// Create a menu with a submenu
|
||||||
|
QMenu inputMenu;
|
||||||
|
QMenu *subMenu = inputMenu.addMenu("menu");
|
||||||
|
QAction *a1 = subMenu->addAction("a1");
|
||||||
|
|
||||||
|
// Export it
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Update a1 (which is in subMenu) and delete subMenu right after that. If
|
||||||
|
// DBusMenuExporter is not careful it will crash in the qWait() because it
|
||||||
|
// tries to send itemUpdated() for a1.
|
||||||
|
a1->setText("Not a menu anymore");
|
||||||
|
delete subMenu;
|
||||||
|
QTest::qWait(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testMenuShortcut()
|
||||||
|
{
|
||||||
|
// Create a menu containing an action with a shortcut
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
a1->setShortcut(Qt::CTRL | Qt::Key_A);
|
||||||
|
|
||||||
|
QAction *a2 = inputMenu.addAction("a2");
|
||||||
|
a2->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_A, Qt::ALT | Qt::Key_B));
|
||||||
|
|
||||||
|
// No shortcut, to test the property is not added in this case
|
||||||
|
QAction *a3 = inputMenu.addAction("a3");
|
||||||
|
|
||||||
|
QList<QAction*> actionList;
|
||||||
|
actionList << a1 << a2 << a3;
|
||||||
|
|
||||||
|
// Check out exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
// Get exported menu info
|
||||||
|
QStringList propertyNames = QStringList() << "label" << "shortcut";
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, propertyNames);
|
||||||
|
QCOMPARE(list.count(), actionList.count());
|
||||||
|
|
||||||
|
Q_FOREACH(const QAction* action, actionList) {
|
||||||
|
DBusMenuLayoutItem item = list.takeFirst();
|
||||||
|
if (action->shortcut().isEmpty()) {
|
||||||
|
QVERIFY(!item.properties.contains("shortcut"));
|
||||||
|
} else {
|
||||||
|
QVERIFY(item.properties.contains("shortcut"));
|
||||||
|
QDBusArgument arg = item.properties.value("shortcut").value<QDBusArgument>();
|
||||||
|
DBusMenuShortcut shortcut;
|
||||||
|
arg >> shortcut;
|
||||||
|
QCOMPARE(shortcut.toKeySequence(), action->shortcut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testGetGroupProperties()
|
||||||
|
{
|
||||||
|
// Create a menu containing two actions
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
QAction *a2 = inputMenu.addAction("a2");
|
||||||
|
|
||||||
|
// Check exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
// Get item ids
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), inputMenu.actions().count());
|
||||||
|
|
||||||
|
int id1 = list.at(0).id;
|
||||||
|
int id2 = list.at(1).id;
|
||||||
|
|
||||||
|
// Get group properties
|
||||||
|
QList<int> ids = QList<int>() << id1 << id2;
|
||||||
|
QDBusReply<DBusMenuItemList> reply = iface.call("GetGroupProperties", QVariant::fromValue(ids), QStringList());
|
||||||
|
QVERIFY2(reply.isValid(), qPrintable(reply.error().message()));
|
||||||
|
DBusMenuItemList groupPropertiesList = reply.value();
|
||||||
|
|
||||||
|
// Check the info we received
|
||||||
|
QCOMPARE(groupPropertiesList.count(), inputMenu.actions().count());
|
||||||
|
|
||||||
|
Q_FOREACH(const QAction* action, inputMenu.actions()) {
|
||||||
|
DBusMenuItem item = groupPropertiesList.takeFirst();
|
||||||
|
QCOMPARE(item.properties.value("label").toString(), action->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testActivateAction()
|
||||||
|
{
|
||||||
|
// Create a menu containing two actions
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
QAction *a2 = inputMenu.addAction("a2");
|
||||||
|
|
||||||
|
// Check exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
ManualSignalSpy spy;
|
||||||
|
QDBusConnection::sessionBus().connect(TEST_SERVICE, TEST_OBJECT_PATH, "com.canonical.dbusmenu", "ItemActivationRequested", "iu", &spy, SLOT(receiveCall(int, uint)));
|
||||||
|
|
||||||
|
// Get item ids
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(list.count(), inputMenu.actions().count());
|
||||||
|
|
||||||
|
int id1 = list.at(0).id;
|
||||||
|
int id2 = list.at(1).id;
|
||||||
|
|
||||||
|
// Trigger actions
|
||||||
|
exporter->activateAction(a1);
|
||||||
|
exporter->activateAction(a2);
|
||||||
|
|
||||||
|
// Check we received the signals in the correct order
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(spy.count(), 2);
|
||||||
|
QCOMPARE(spy.takeFirst().at(0).toInt(), id1);
|
||||||
|
QCOMPARE(spy.takeFirst().at(0).toInt(), id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trackCount(QMenu* menu)
|
||||||
|
{
|
||||||
|
QList<QObject*> lst = menu->findChildren<QObject*>();
|
||||||
|
int count = 0;
|
||||||
|
Q_FOREACH(QObject* child, lst) {
|
||||||
|
if (qstrcmp(child->metaObject()->className(), "DBusMenu") == 0) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we do not create more than one DBusMenu object for each menu
|
||||||
|
// See KDE bug 254066
|
||||||
|
void DBusMenuExporterTest::testTrackActionsOnlyOnce()
|
||||||
|
{
|
||||||
|
// Create a menu with a submenu, unplug the submenu and plug it back. The
|
||||||
|
// submenu should not have more than one DBusMenu child object.
|
||||||
|
QMenu mainMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &mainMenu);
|
||||||
|
|
||||||
|
QMenu* subMenu = new QMenu("File");
|
||||||
|
subMenu->addAction("a1");
|
||||||
|
mainMenu.addAction(subMenu->menuAction());
|
||||||
|
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(trackCount(subMenu), 1);
|
||||||
|
|
||||||
|
mainMenu.removeAction(subMenu->menuAction());
|
||||||
|
|
||||||
|
mainMenu.addAction(subMenu->menuAction());
|
||||||
|
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(trackCount(subMenu), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If desktop does not want icon in menus, check we do not export them
|
||||||
|
void DBusMenuExporterTest::testHonorDontShowIconsInMenusAttribute()
|
||||||
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, true);
|
||||||
|
QMenu inputMenu;
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *action = new QAction("Undo", &inputMenu);
|
||||||
|
QIcon icon = QIcon::fromTheme("edit-undo");
|
||||||
|
QVERIFY(!icon.isNull());
|
||||||
|
action->setIcon(icon);
|
||||||
|
inputMenu.addAction(action);
|
||||||
|
|
||||||
|
// Check out exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
// Get exported menu info
|
||||||
|
QStringList propertyNames = QStringList() << "icon-name";
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, /*parentId=*/0, propertyNames);
|
||||||
|
DBusMenuLayoutItem item = list.first();
|
||||||
|
QVERIFY(item.id != 0);
|
||||||
|
QVERIFY(!item.properties.contains("icon-name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasInternalDBusMenuObject(QMenu* menu)
|
||||||
|
{
|
||||||
|
Q_FOREACH(QObject* obj, menu->children()) {
|
||||||
|
if (obj->inherits("DBusMenu")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBusMenuExporter adds an instance of an internal class named "DBusMenu" to
|
||||||
|
// any QMenu it tracks. Check they go away when the exporter is deleted.
|
||||||
|
void DBusMenuExporterTest::testDBusMenuObjectIsDeletedWhenExporterIsDeleted()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
QVERIFY2(hasInternalDBusMenuObject(&inputMenu), "Test setup failed");
|
||||||
|
delete exporter;
|
||||||
|
QVERIFY(!hasInternalDBusMenuObject(&inputMenu));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testSeparatorCollapsing_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("input");
|
||||||
|
QTest::addColumn<QString>("expected");
|
||||||
|
|
||||||
|
QTest::newRow("one-separator") << "a-b" << "a-b";
|
||||||
|
QTest::newRow("two-separators") << "a-b-c" << "a-b-c";
|
||||||
|
QTest::newRow("middle-separators") << "a--b" << "a-b";
|
||||||
|
QTest::newRow("separators-at-begin") << "--a-b" << "a-b";
|
||||||
|
QTest::newRow("separators-at-end") << "a-b--" << "a-b";
|
||||||
|
QTest::newRow("separators-everywhere") << "--a---bc--d--" << "a-bc-d";
|
||||||
|
QTest::newRow("empty-menu") << "" << "";
|
||||||
|
QTest::newRow("separators-only") << "---" << "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testSeparatorCollapsing()
|
||||||
|
{
|
||||||
|
QFETCH(QString, input);
|
||||||
|
QFETCH(QString, expected);
|
||||||
|
|
||||||
|
// Create menu from menu string
|
||||||
|
QMenu inputMenu;
|
||||||
|
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
if (input.isEmpty()) {
|
||||||
|
// Pretend there was an action so that doEmitLayoutUpdated() is called
|
||||||
|
// even if the new menu is empty. If we don't do this we don't test
|
||||||
|
// DBusMenuExporterPrivate::collapseSeparators() for empty menus.
|
||||||
|
delete inputMenu.addAction("dummy");
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_FOREACH(QChar ch, input) {
|
||||||
|
if (ch == '-') {
|
||||||
|
inputMenu.addSeparator();
|
||||||
|
} else {
|
||||||
|
inputMenu.addAction(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Check out exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
// Get exported menu info
|
||||||
|
QStringList propertyNames = QStringList();
|
||||||
|
DBusMenuLayoutItemList list = getChildren(&iface, /*parentId=*/0, propertyNames);
|
||||||
|
|
||||||
|
// Recreate a menu string from the item list
|
||||||
|
QString output;
|
||||||
|
Q_FOREACH(const DBusMenuLayoutItem& item, list) {
|
||||||
|
QVariantMap properties = item.properties;
|
||||||
|
if (properties.contains("visible") && !properties.value("visible").toBool()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString type = properties.value("type").toString();
|
||||||
|
if (type == "separator") {
|
||||||
|
output += '-';
|
||||||
|
} else {
|
||||||
|
output += properties.value("label").toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check it matches
|
||||||
|
QCOMPARE(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkPropertiesChangedArgs(const QVariantList& args, const QString& name, const QVariant& value)
|
||||||
|
{
|
||||||
|
QCOMPARE(args[0].toString(), QString("com.canonical.dbusmenu"));
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert(name, value);
|
||||||
|
QCOMPARE(args[1].toMap(), map);
|
||||||
|
QCOMPARE(args[2].toStringList(), QStringList());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testSetStatus()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
DBusMenuExporter *exporter = new DBusMenuExporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
ManualSignalSpy spy;
|
||||||
|
QDBusConnection::sessionBus().connect(TEST_SERVICE, TEST_OBJECT_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged", "sa{sv}as", &spy, SLOT(receiveCall(QString, QVariantMap, QStringList)));
|
||||||
|
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Check our exporter is on DBus
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QVERIFY2(iface.isValid(), qPrintable(iface.lastError().message()));
|
||||||
|
|
||||||
|
QCOMPARE(exporter->status(), QString("normal"));
|
||||||
|
|
||||||
|
// Change status, a DBus signal should be emitted
|
||||||
|
exporter->setStatus("notice");
|
||||||
|
QCOMPARE(exporter->status(), QString("notice"));
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
checkPropertiesChangedArgs(spy.takeFirst(), "Status", "notice");
|
||||||
|
|
||||||
|
// Same status => no signal
|
||||||
|
exporter->setStatus("notice");
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(spy.count(), 0);
|
||||||
|
|
||||||
|
// Change status, a DBus signal should be emitted
|
||||||
|
exporter->setStatus("normal");
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
checkPropertiesChangedArgs(spy.takeFirst(), "Status", "normal");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuExporterTest::testGetIconDataProperty()
|
||||||
|
{
|
||||||
|
// Create an icon
|
||||||
|
QImage img(16, 16, QImage::Format_ARGB32);
|
||||||
|
{
|
||||||
|
QPainter painter(&img);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
QRect rect = img.rect();
|
||||||
|
painter.fillRect(rect, Qt::transparent);
|
||||||
|
rect.adjust(2, 2, -2, -2);
|
||||||
|
painter.fillRect(rect, Qt::red);
|
||||||
|
rect.adjust(2, 2, -2, -2);
|
||||||
|
painter.fillRect(rect, Qt::green);
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon icon(QPixmap::fromImage(img));
|
||||||
|
|
||||||
|
// Create a menu with the icon and export it
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction* a1 = inputMenu.addAction("a1");
|
||||||
|
a1->setIcon(icon);
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Get properties
|
||||||
|
QDBusInterface iface(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
DBusMenuLayoutItemList layoutItemlist = getChildren(&iface, 0, QStringList());
|
||||||
|
QCOMPARE(layoutItemlist.count(), 1);
|
||||||
|
|
||||||
|
QList<int> ids = QList<int>() << layoutItemlist[0].id;
|
||||||
|
|
||||||
|
QDBusReply<DBusMenuItemList> reply = iface.call("GetGroupProperties", QVariant::fromValue(ids), QStringList());
|
||||||
|
|
||||||
|
DBusMenuItemList itemlist = reply.value();
|
||||||
|
QCOMPARE(itemlist.count(), 1);
|
||||||
|
|
||||||
|
// Check we have the right property
|
||||||
|
DBusMenuItem item = itemlist.takeFirst();
|
||||||
|
QVERIFY(!item.properties.contains("icon-name"));
|
||||||
|
QVERIFY(item.properties.contains("icon-data"));
|
||||||
|
|
||||||
|
// Check saved image is the same
|
||||||
|
QByteArray data = item.properties.value("icon-data").toByteArray();
|
||||||
|
QVERIFY(!data.isEmpty());
|
||||||
|
QImage result;
|
||||||
|
QVERIFY(result.loadFromData(data, "PNG"));
|
||||||
|
QCOMPARE(result, img);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dbusmenuexportertest.moc"
|
|
@ -0,0 +1,63 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2009 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUEXPORTERTEST_H
|
||||||
|
#define DBUSMENUEXPORTERTEST_H
|
||||||
|
|
||||||
|
#define QT_GUI_LIB
|
||||||
|
#include <QtGui>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
|
||||||
|
class DBusMenuExporterTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private Q_SLOTS:
|
||||||
|
void testGetSomeProperties();
|
||||||
|
void testGetSomeProperties_data();
|
||||||
|
void testGetAllProperties();
|
||||||
|
void testGetNonExistentProperty();
|
||||||
|
void testClickedEvent();
|
||||||
|
void testSubMenu();
|
||||||
|
void testDynamicSubMenu();
|
||||||
|
void testRadioItems();
|
||||||
|
void testNonExclusiveActionGroup();
|
||||||
|
void testClickDeletedAction();
|
||||||
|
void testDeleteExporterBeforeMenu();
|
||||||
|
void testUpdateAndDeleteSubMenu();
|
||||||
|
void testMenuShortcut();
|
||||||
|
void testGetGroupProperties();
|
||||||
|
void testActivateAction();
|
||||||
|
void testTrackActionsOnlyOnce();
|
||||||
|
void testHonorDontShowIconsInMenusAttribute();
|
||||||
|
void testDBusMenuObjectIsDeletedWhenExporterIsDeleted();
|
||||||
|
void testSeparatorCollapsing_data();
|
||||||
|
void testSeparatorCollapsing();
|
||||||
|
void testSetStatus();
|
||||||
|
void testGetIconDataProperty();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void cleanup();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUEXPORTERTEST_H */
|
|
@ -0,0 +1,343 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
// Self
|
||||||
|
#include "dbusmenuimportertest.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
// DBusMenuQt
|
||||||
|
#include <dbusmenuexporter.h>
|
||||||
|
#include <dbusmenuimporter.h>
|
||||||
|
#include <debug_p.h>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include "testutils.h"
|
||||||
|
|
||||||
|
QTEST_MAIN(DBusMenuImporterTest)
|
||||||
|
|
||||||
|
static const char *TEST_SERVICE = "com.canonical.dbusmenu-qt-test";
|
||||||
|
static const char *TEST_OBJECT_PATH = "/TestMenuBar";
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QAction*)
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::initTestCase()
|
||||||
|
{
|
||||||
|
qRegisterMetaType<QAction*>("QAction*");
|
||||||
|
QVERIFY(QDBusConnection::sessionBus().registerService(TEST_SERVICE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::cleanup()
|
||||||
|
{
|
||||||
|
waitForDeferredDeletes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testStandardItem()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *action = inputMenu.addAction("Test");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 1);
|
||||||
|
QAction *outputAction = outputMenu->actions().first();
|
||||||
|
QCOMPARE(outputAction->text(), QString("Test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testAddingNewItem()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *action = inputMenu.addAction("Test");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
QCOMPARE(outputMenu->actions().count(), inputMenu.actions().count());
|
||||||
|
|
||||||
|
inputMenu.addAction("Test2");
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(outputMenu->actions().count(), inputMenu.actions().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testShortcut()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *action = inputMenu.addAction("Test");
|
||||||
|
action->setShortcut(Qt::CTRL | Qt::Key_S);
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
|
||||||
|
QAction *outputAction = outputMenu->actions().at(0);
|
||||||
|
QCOMPARE(outputAction->shortcut(), action->shortcut());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testDeletingImporterWhileWaitingForAboutToShow()
|
||||||
|
{
|
||||||
|
// Start test program and wait for it to be ready
|
||||||
|
QProcess slowMenuProcess;
|
||||||
|
slowMenuProcess.start("./slowmenu");
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Create importer and wait for the menu
|
||||||
|
DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
QMenu *outputMenu = importer->menu();
|
||||||
|
QTimer::singleShot(100, importer, SLOT(deleteLater()));
|
||||||
|
outputMenu->popup(QPoint(0, 0));
|
||||||
|
|
||||||
|
// If it crashes, it will crash while waiting there
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Done, stop our test program
|
||||||
|
slowMenuProcess.close();
|
||||||
|
slowMenuProcess.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testDynamicMenu()
|
||||||
|
{
|
||||||
|
QMenu rootMenu;
|
||||||
|
QAction* a1 = new QAction("a1", &rootMenu);
|
||||||
|
QAction* a2 = new QAction("a2", &rootMenu);
|
||||||
|
MenuFiller rootMenuFiller(&rootMenu);
|
||||||
|
rootMenuFiller.addAction(a1);
|
||||||
|
rootMenuFiller.addAction(a2);
|
||||||
|
|
||||||
|
QMenu subMenu;
|
||||||
|
MenuFiller subMenuFiller(&subMenu);
|
||||||
|
subMenuFiller.addAction(new QAction("a3", &subMenu));
|
||||||
|
|
||||||
|
a1->setMenu(&subMenu);
|
||||||
|
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &rootMenu);
|
||||||
|
|
||||||
|
// Import this menu
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
|
||||||
|
// There should be no children for now
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 0);
|
||||||
|
|
||||||
|
// Update menu, a1 and a2 should get added
|
||||||
|
QSignalSpy spy(&importer, SIGNAL(menuUpdated()));
|
||||||
|
QSignalSpy spyOld(&importer, SIGNAL(menuReadyToBeShown()));
|
||||||
|
importer.updateMenu();
|
||||||
|
while (spy.isEmpty()) {
|
||||||
|
QTest::qWait(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 2);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QAction* a1Output = outputMenu->actions().first();
|
||||||
|
|
||||||
|
// a1Output should have an empty menu
|
||||||
|
QMenu* a1OutputMenu = a1Output->menu();
|
||||||
|
QVERIFY(a1OutputMenu);
|
||||||
|
QCOMPARE(a1OutputMenu->actions().count(), 0);
|
||||||
|
|
||||||
|
// Show a1OutputMenu, a3 should get added
|
||||||
|
QMetaObject::invokeMethod(a1OutputMenu, "aboutToShow");
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
QCOMPARE(a1OutputMenu->actions().count(), 1);
|
||||||
|
|
||||||
|
// menuUpdated() and menuReadyToBeShown() should only have been emitted
|
||||||
|
// once
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
QCOMPARE(spyOld.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testActionActivationRequested()
|
||||||
|
{
|
||||||
|
// Export a menu
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *inputA1 = inputMenu.addAction("a1");
|
||||||
|
QAction *inputA2 = inputMenu.addAction("a2");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Import the menu
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QSignalSpy spy(&importer, SIGNAL(actionActivationRequested(QAction*)));
|
||||||
|
|
||||||
|
QTest::qWait(500);
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
|
||||||
|
// Get matching output actions
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 2);
|
||||||
|
QAction *outputA1 = outputMenu->actions().at(0);
|
||||||
|
QAction *outputA2 = outputMenu->actions().at(1);
|
||||||
|
|
||||||
|
// Request activation
|
||||||
|
exporter.activateAction(inputA1);
|
||||||
|
exporter.activateAction(inputA2);
|
||||||
|
|
||||||
|
// Check we received the signal in the right order
|
||||||
|
QTest::qWait(500);
|
||||||
|
QCOMPARE(spy.count(), 2);
|
||||||
|
QCOMPARE(spy.takeFirst().at(0).value<QAction*>(), outputA1);
|
||||||
|
QCOMPARE(spy.takeFirst().at(0).value<QAction*>(), outputA2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testActionsAreDeletedWhenImporterIs()
|
||||||
|
{
|
||||||
|
// Export a menu
|
||||||
|
QMenu inputMenu;
|
||||||
|
inputMenu.addAction("a1");
|
||||||
|
QMenu *inputSubMenu = inputMenu.addMenu("subMenu");
|
||||||
|
inputSubMenu->addAction("a2");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Import the menu
|
||||||
|
DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Put all items of the menu in a list of QPointers
|
||||||
|
QList< QPointer<QObject> > children;
|
||||||
|
|
||||||
|
QMenu *outputMenu = importer->menu();
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 2);
|
||||||
|
QMenu *outputSubMenu = outputMenu->actions().at(1)->menu();
|
||||||
|
QVERIFY(outputSubMenu);
|
||||||
|
// Fake aboutToShow so that outputSubMenu is populated
|
||||||
|
QMetaObject::invokeMethod(outputSubMenu, "aboutToShow");
|
||||||
|
QCOMPARE(outputSubMenu->actions().count(), 1);
|
||||||
|
|
||||||
|
children << outputMenu->actions().at(0);
|
||||||
|
children << outputMenu->actions().at(1);
|
||||||
|
children << outputSubMenu;
|
||||||
|
children << outputSubMenu->actions().at(0);
|
||||||
|
|
||||||
|
delete importer;
|
||||||
|
waitForDeferredDeletes();
|
||||||
|
|
||||||
|
// There should be only invalid pointers in children
|
||||||
|
Q_FOREACH(QPointer<QObject> child, children) {
|
||||||
|
//qDebug() << child;
|
||||||
|
QVERIFY(child.isNull());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testIconData()
|
||||||
|
{
|
||||||
|
// Create an icon
|
||||||
|
QImage img(16, 16, QImage::Format_ARGB32);
|
||||||
|
{
|
||||||
|
QPainter painter(&img);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
QRect rect = img.rect();
|
||||||
|
painter.fillRect(rect, Qt::transparent);
|
||||||
|
rect.adjust(2, 2, -2, -2);
|
||||||
|
painter.fillRect(rect, Qt::red);
|
||||||
|
rect.adjust(2, 2, -2, -2);
|
||||||
|
painter.fillRect(rect, Qt::green);
|
||||||
|
}
|
||||||
|
QIcon inputIcon(QPixmap::fromImage(img));
|
||||||
|
|
||||||
|
// Export a menu
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *a1 = inputMenu.addAction("a1");
|
||||||
|
a1->setIcon(inputIcon);
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
// Import the menu
|
||||||
|
DBusMenuImporter *importer = new DBusMenuImporter(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
// Check icon of action
|
||||||
|
QMenu *outputMenu = importer->menu();
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 1);
|
||||||
|
|
||||||
|
QIcon outputIcon = outputMenu->actions().first()->icon();
|
||||||
|
QVERIFY(!outputIcon.isNull());
|
||||||
|
|
||||||
|
QImage result = outputIcon.pixmap(16).toImage();
|
||||||
|
QByteArray origBytes, resultBytes;
|
||||||
|
img.save(origBytes);
|
||||||
|
result.save(resultBytes);
|
||||||
|
QCOMPARE(origBytes,resultBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testInvisibleItem()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *action = inputMenu.addAction("Test");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 1);
|
||||||
|
QAction *outputAction = outputMenu->actions().first();
|
||||||
|
|
||||||
|
QVERIFY(outputAction->isVisible());
|
||||||
|
|
||||||
|
// Hide the action
|
||||||
|
action->setVisible(false);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QVERIFY(!outputAction->isVisible());
|
||||||
|
|
||||||
|
// Show the action
|
||||||
|
action->setVisible(true);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QVERIFY(outputAction->isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuImporterTest::testDisabledItem()
|
||||||
|
{
|
||||||
|
QMenu inputMenu;
|
||||||
|
QAction *action = inputMenu.addAction("Test");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, &inputMenu);
|
||||||
|
|
||||||
|
DBusMenuImporter importer(TEST_SERVICE, TEST_OBJECT_PATH);
|
||||||
|
QTest::qWait(500);
|
||||||
|
|
||||||
|
QMenu *outputMenu = importer.menu();
|
||||||
|
QCOMPARE(outputMenu->actions().count(), 1);
|
||||||
|
QAction *outputAction = outputMenu->actions().first();
|
||||||
|
QVERIFY(outputAction->isEnabled());
|
||||||
|
|
||||||
|
// Disable the action
|
||||||
|
DMDEBUG << "Disabling";
|
||||||
|
action->setEnabled(false);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QVERIFY(!outputAction->isEnabled());
|
||||||
|
|
||||||
|
// Enable the action
|
||||||
|
action->setEnabled(true);
|
||||||
|
QTest::qWait(500);
|
||||||
|
QVERIFY(outputAction->isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dbusmenuimportertest.moc"
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUIMPORTERTEST_H
|
||||||
|
#define DBUSMENUIMPORTERTEST_H
|
||||||
|
|
||||||
|
#define QT_GUI_LIB
|
||||||
|
#include <QtGui>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
|
||||||
|
class DBusMenuImporterTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private Q_SLOTS:
|
||||||
|
void cleanup();
|
||||||
|
void testStandardItem();
|
||||||
|
void testAddingNewItem();
|
||||||
|
void testShortcut();
|
||||||
|
void testDeletingImporterWhileWaitingForAboutToShow();
|
||||||
|
void testDynamicMenu();
|
||||||
|
void testActionActivationRequested();
|
||||||
|
void testActionsAreDeletedWhenImporterIs();
|
||||||
|
void testIconData();
|
||||||
|
void testInvisibleItem();
|
||||||
|
void testDisabledItem();
|
||||||
|
|
||||||
|
void initTestCase();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUIMPORTERTEST_H */
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
// Self
|
||||||
|
#include "dbusmenushortcuttest.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
// DBusMenuQt
|
||||||
|
#include <dbusmenushortcut_p.h>
|
||||||
|
#include <debug_p.h>
|
||||||
|
|
||||||
|
QTEST_MAIN(DBusMenuShortcutTest)
|
||||||
|
|
||||||
|
namespace QTest
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
char *toString(const DBusMenuShortcut &dmShortcut)
|
||||||
|
{
|
||||||
|
QByteArray ba = "DBusMenuShortcut(";
|
||||||
|
Q_FOREACH(const QStringList& tokens, dmShortcut) {
|
||||||
|
ba += "(";
|
||||||
|
ba += tokens.join("+").toUtf8();
|
||||||
|
ba += ")";
|
||||||
|
}
|
||||||
|
ba += ")";
|
||||||
|
return qstrdup(ba.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuShortcut createKeyList(const QString& txt)
|
||||||
|
{
|
||||||
|
DBusMenuShortcut lst;
|
||||||
|
QStringList tokens = txt.split(',');
|
||||||
|
Q_FOREACH(const QString& token, tokens) {
|
||||||
|
lst << token.split('+');
|
||||||
|
}
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADD_ROW(ksArgs, klArgs) QTest::newRow(#ksArgs) << QKeySequence ksArgs << createKeyList(klArgs)
|
||||||
|
|
||||||
|
void DBusMenuShortcutTest::testConverter_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QKeySequence>("keySequence");
|
||||||
|
QTest::addColumn<DBusMenuShortcut>("keyList");
|
||||||
|
|
||||||
|
ADD_ROW((Qt::ALT | Qt::Key_F4), "Alt+F4");
|
||||||
|
ADD_ROW((Qt::CTRL | Qt::Key_S), "Control+S");
|
||||||
|
ADD_ROW((Qt::CTRL | Qt::Key_X, Qt::ALT | Qt::SHIFT | Qt::Key_Q), "Control+X,Alt+Shift+Q");
|
||||||
|
ADD_ROW((Qt::META | Qt::Key_E), "Super+E");
|
||||||
|
ADD_ROW((Qt::CTRL | Qt::Key_Plus), "Control+plus");
|
||||||
|
ADD_ROW((Qt::CTRL | Qt::Key_Minus), "Control+minus");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMenuShortcutTest::testConverter()
|
||||||
|
{
|
||||||
|
QFETCH(QKeySequence, keySequence);
|
||||||
|
QFETCH(DBusMenuShortcut, keyList);
|
||||||
|
|
||||||
|
DBusMenuShortcut list = DBusMenuShortcut::fromKeySequence(keySequence);
|
||||||
|
QCOMPARE(list, keyList);
|
||||||
|
QKeySequence sequence = keyList.toKeySequence();
|
||||||
|
QCOMPARE(sequence.toString(), keySequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "dbusmenushortcuttest.moc"
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef DBUSMENUSHORTCUTTEST_H
|
||||||
|
#define DBUSMENUSHORTCUTTEST_H
|
||||||
|
|
||||||
|
#define QT_GUI_LIB
|
||||||
|
#include <QtGui>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
// Local
|
||||||
|
|
||||||
|
class DBusMenuShortcutTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private Q_SLOTS:
|
||||||
|
void testConverter_data();
|
||||||
|
void testConverter();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DBUSMENUSHORTCUTTEST_H */
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include <slowmenu.moc>
|
||||||
|
|
||||||
|
#include <dbusmenuexporter.h>
|
||||||
|
|
||||||
|
#include <QtDBus>
|
||||||
|
#include <QtGui>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
static const char *TEST_SERVICE = "org.kde.dbusmenu-qt-test";
|
||||||
|
static const char *TEST_OBJECT_PATH = "/TestMenuBar";
|
||||||
|
|
||||||
|
SlowMenu::SlowMenu()
|
||||||
|
: QMenu()
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(aboutToShow()), SLOT(slotAboutToShow()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlowMenu::slotAboutToShow()
|
||||||
|
{
|
||||||
|
qDebug() << __FUNCTION__ << "Entering";
|
||||||
|
QTime time;
|
||||||
|
time.start();
|
||||||
|
while (time.elapsed() < 2000) {
|
||||||
|
qApp->processEvents();
|
||||||
|
}
|
||||||
|
qDebug() << __FUNCTION__ << "Leaving";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
QDBusConnection::sessionBus().registerService(TEST_SERVICE);
|
||||||
|
SlowMenu* inputMenu = new SlowMenu;
|
||||||
|
inputMenu->addAction("Test");
|
||||||
|
DBusMenuExporter exporter(TEST_OBJECT_PATH, inputMenu);
|
||||||
|
qDebug() << "Looping";
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef SLOWMENU_H
|
||||||
|
#define SLOWMENU_H
|
||||||
|
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
class SlowMenu : public QMenu
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SlowMenu();
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void slotAboutToShow();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SLOWMENU_H */
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "testutils.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
void waitForDeferredDeletes()
|
||||||
|
{
|
||||||
|
while (QCoreApplication::hasPendingEvents()) {
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "testutils.moc"
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef TESTUTILS_H
|
||||||
|
#define TESTUTILS_H
|
||||||
|
|
||||||
|
// Local
|
||||||
|
#include <debug_p.h>
|
||||||
|
#include <dbusmenutypes_p.h>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
class ManualSignalSpy : public QObject, public QList<QVariantList>
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public Q_SLOTS:
|
||||||
|
void receiveCall(int value)
|
||||||
|
{
|
||||||
|
append(QVariantList() << value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiveCall(uint v1, int v2)
|
||||||
|
{
|
||||||
|
append(QVariantList() << v1 << v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiveCall(int v1, uint v2)
|
||||||
|
{
|
||||||
|
append(QVariantList() << v1 << v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiveCall(DBusMenuItemList itemList, DBusMenuItemKeysList removedPropsList)
|
||||||
|
{
|
||||||
|
QVariantList propsIds;
|
||||||
|
Q_FOREACH(DBusMenuItem item, itemList) {
|
||||||
|
propsIds << item.id;
|
||||||
|
}
|
||||||
|
QVariantList removedPropsIds;
|
||||||
|
Q_FOREACH(DBusMenuItemKeys props, removedPropsList) {
|
||||||
|
removedPropsIds << props.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList args;
|
||||||
|
args.push_back(propsIds);
|
||||||
|
args.push_back(removedPropsIds);
|
||||||
|
append(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receiveCall(const QString& service, const QVariantMap& modifiedProperties, const QStringList& newProperties)
|
||||||
|
{
|
||||||
|
QVariantList args;
|
||||||
|
args.push_back(service);
|
||||||
|
args.push_back(modifiedProperties);
|
||||||
|
args.push_back(newProperties);
|
||||||
|
append(args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MenuFiller : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MenuFiller(QMenu *menu)
|
||||||
|
: m_menu(menu)
|
||||||
|
{
|
||||||
|
connect(m_menu, SIGNAL(aboutToShow()), SLOT(fillMenu()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAction(QAction *action)
|
||||||
|
{
|
||||||
|
m_actions << action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void fillMenu()
|
||||||
|
{
|
||||||
|
while (!m_actions.isEmpty()) {
|
||||||
|
m_menu->addAction(m_actions.takeFirst());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMenu *m_menu;
|
||||||
|
QList<QAction *> m_actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
void waitForDeferredDeletes();
|
||||||
|
|
||||||
|
#endif /* TESTUTILS_H */
|
|
@ -0,0 +1,7 @@
|
||||||
|
find_package(QJSON)
|
||||||
|
if (QJSON_FOUND)
|
||||||
|
message(STATUS "QJSON found, testapp will be built")
|
||||||
|
add_subdirectory(testapp)
|
||||||
|
else (QJSON_FOUND)
|
||||||
|
message(STATUS "QJSON not found, testapp will not be built")
|
||||||
|
endif (QJSON_FOUND)
|
|
@ -0,0 +1,46 @@
|
||||||
|
set(qtapp_SRCS
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(dbusmenubench-qtapp ${qtapp_SRCS})
|
||||||
|
|
||||||
|
if (NOT USE_QT5)
|
||||||
|
# Qt4
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../../src
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/../../src
|
||||||
|
${QT_INCLUDE_DIR}
|
||||||
|
${QT_QTCORE_INCLUDE_DIR}
|
||||||
|
${QT_QTGUI_INCLUDE_DIR}
|
||||||
|
${QT_QTDBUS_INCLUDE_DIR}
|
||||||
|
${QJSON_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(dbusmenubench-qtapp
|
||||||
|
dbusmenu-qt
|
||||||
|
${QT_QTGUI_LIBRARY}
|
||||||
|
${QT_QTCORE_LIBRARY}
|
||||||
|
${QT_QTDBUS_LIBRARY}
|
||||||
|
${QJSON_LIBRARIES}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
# Qt5
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../../src
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/../../src
|
||||||
|
${Qt5Widgets_INCLUDE_DIRS}
|
||||||
|
${Qt5Core_INCLUDE_DIRS}
|
||||||
|
${Qt5Gui_INCLUDE_DIRS}
|
||||||
|
${Qt5DBus_INCLUDE_DIRS}
|
||||||
|
${QJSON_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(dbusmenubench-qtapp
|
||||||
|
dbusmenu-qt5
|
||||||
|
${Qt5Gui_LIBRARIES}
|
||||||
|
${Qt5Core_LIBRARIES}
|
||||||
|
${Qt5DBus_LIBRARIES}
|
||||||
|
${Qt5Widgets_LIBRARIES}
|
||||||
|
${QJSON_LIBRARIES}
|
||||||
|
)
|
||||||
|
endif()
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* This file is part of the dbusmenu-qt library
|
||||||
|
Copyright 2010 Canonical
|
||||||
|
Author: Aurelien Gateau <aurelien.gateau@canonical.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License (LGPL) as published by the Free Software Foundation;
|
||||||
|
either version 2 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
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
|
#include <dbusmenuexporter.h>
|
||||||
|
|
||||||
|
static const char *DBUS_SERVICE = "org.dbusmenu.test";
|
||||||
|
static const char *DBUS_PATH = "/MenuBar";
|
||||||
|
static const char *USAGE = "dbusmenubench-qtapp <path/to/menu.json>";
|
||||||
|
|
||||||
|
void createMenuItem(QMenu *menu, const QVariant &item)
|
||||||
|
{
|
||||||
|
QVariantMap map = item.toMap();
|
||||||
|
|
||||||
|
if (map.value("visible").toString() == "false") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString type = map.value("type").toString();
|
||||||
|
if (type == "separator") {
|
||||||
|
menu->addSeparator();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString label = map.value("label").toString();
|
||||||
|
QAction *action = menu->addAction(label);
|
||||||
|
action->setEnabled(map.value("sensitive").toString() == "true");
|
||||||
|
if (map.contains("submenu")) {
|
||||||
|
QVariantList items = map.value("submenu").toList();
|
||||||
|
Q_FOREACH(const QVariant &item, items) {
|
||||||
|
QMenu *subMenu = new QMenu;
|
||||||
|
action->setMenu(subMenu);
|
||||||
|
createMenuItem(subMenu, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initMenu(QMenu *menu, const QString &fileName)
|
||||||
|
{
|
||||||
|
QJson::Parser parser;
|
||||||
|
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
qCritical() << "Could not open file" << fileName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
QVariant tree = parser.parse(&file, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
qCritical() << "Could not parse json data from" << fileName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList list = tree.toList();
|
||||||
|
Q_FOREACH(const QVariant &item, list) {
|
||||||
|
createMenuItem(menu, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
QMenu menu;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
qCritical() << USAGE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
QString jsonFileName = argv[1];
|
||||||
|
initMenu(&menu, jsonFileName);
|
||||||
|
|
||||||
|
QDBusConnection connection = QDBusConnection::sessionBus();
|
||||||
|
if (!connection.registerService(DBUS_SERVICE)) {
|
||||||
|
qCritical() << "Could not register" << DBUS_SERVICE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMenuExporter exporter(DBUS_PATH, &menu);
|
||||||
|
return app.exec();
|
||||||
|
}
|
Loading…
Reference in New Issue