qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

77
src/dbus/CMakeLists.txt Normal file
View File

@ -0,0 +1,77 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## DBus Module:
#####################################################################
qt_internal_add_module(DBus
QMAKE_MODULE_CONFIG dbusadaptors dbusinterfaces
SOURCES
dbus_minimal_p.h
qdbus_symbols.cpp qdbus_symbols_p.h
qdbusabstractadaptor.cpp qdbusabstractadaptor.h qdbusabstractadaptor_p.h
qdbusabstractinterface.cpp qdbusabstractinterface.h qdbusabstractinterface_p.h
qdbusargument.cpp qdbusargument.h qdbusargument_p.h
qdbusconnection.cpp qdbusconnection.h qdbusconnection_p.h
qdbusconnectioninterface.cpp qdbusconnectioninterface.h
qdbusconnectionmanager_p.h
qdbuscontext.cpp qdbuscontext.h qdbuscontext_p.h
qdbuserror.cpp qdbuserror.h
qdbusextratypes.cpp qdbusextratypes.h
qdbusintegrator.cpp qdbusintegrator_p.h
qdbusinterface.cpp qdbusinterface.h qdbusinterface_p.h
qdbusinternalfilters.cpp
qdbusintrospection.cpp qdbusintrospection_p.h
qdbusmarshaller.cpp
qdbusmessage.cpp qdbusmessage.h qdbusmessage_p.h
qdbusmetaobject.cpp qdbusmetaobject_p.h
qdbusmetatype.cpp qdbusmetatype.h qdbusmetatype_p.h
qdbusmisc.cpp
qdbuspendingcall.cpp qdbuspendingcall.h qdbuspendingcall_p.h
qdbuspendingreply.cpp qdbuspendingreply.h
qdbusreply.cpp qdbusreply.h
qdbusserver.cpp qdbusserver.h
qdbusservicewatcher.cpp qdbusservicewatcher.h
qdbusthreaddebug_p.h
qdbusunixfiledescriptor.cpp qdbusunixfiledescriptor.h
qdbusutil.cpp qdbusutil_p.h
qdbusvirtualobject.cpp qdbusvirtualobject.h
qdbusxmlgenerator.cpp
qdbusxmlparser.cpp qdbusxmlparser_p.h
qtdbusglobal.h qtdbusglobal_p.h
DEFINES
DBUS_API_SUBJECT_TO_CHANGE
QT_NO_FOREACH
LIBRARIES
Qt::CorePrivate
PUBLIC_LIBRARIES
Qt::Core
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
GENERATE_CPP_EXPORTS
)
set_source_files_properties(qdbusmarshaller.cpp
PROPERTIES HEADER_FILE_ONLY ON) # special case: This file is included by qdbusargument.cpp
## Scopes:
#####################################################################
qt_internal_extend_target(DBus CONDITION QT_FEATURE_dbus_linked
DEFINES
QT_LINKED_LIBDBUS
LIBRARIES
dbus-1
)
qt_internal_extend_target(DBus CONDITION WIN32
LIBRARIES
advapi32
netapi32
user32
ws2_32
)
qt_internal_add_docs(DBus
doc/qtdbus.qdocconf
)

View File

@ -0,0 +1,157 @@
Copyright (C) 2002, 2003 CodeFactory AB
Copyright (C) 2004, 2005 Red Hat, Inc.
Licensed under the Academic Free License version 2.1
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
---
The Academic Free License
v.2.1
This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following notice immediately following the copyright notice for the Original Work:
Licensed under the Academic Free License version 2.1
1) Grant of Copyright License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license to do the following:
a) to reproduce the Original Work in copies;
b) to prepare derivative works ("Derivative Works") based upon the Original Work;
c) to distribute copies of the Original Work and Derivative Works to the public;
d) to perform the Original Work publicly; and
e) to display the Original Work publicly.
2) Grant of Patent License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, to make, use, sell and offer for sale the Original Work and Derivative Works.
3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor hereby agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work, and by publishing the address of that information repository in a notice immediately following the copyright notice that applies to the Original Work.
4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior written permission of the Licensor. Nothing in this License shall be deemed to grant any rights to trademarks, copyrights, patents, trade secrets or any other intellectual property of Licensor except as expressly stated herein. No patent license is granted to make, use, sell or offer to sell embodiments of any patent claims other than the licensed claims defined in Section 2. No right is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under different terms from this License any Original Work that Licensor otherwise would have a right to license.
5) This section intentionally omitted.
6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately proceeding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to Original Work is granted hereunder except under this disclaimer.
8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to any person for any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to liability for death or personal injury resulting from Licensor's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.
9) Acceptance and Termination. If You distribute copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. Nothing else but this License (or another written agreement between Licensor and You) grants You permission to create Derivative Works based upon the Original Work or to exercise any of the rights granted in Section 1 herein, and any attempt to do so except under the terms of this License (or another written agreement between Licensor and You) is expressly prohibited by U.S. copyright law, the equivalent laws of other countries, and by international treaty. Therefore, by exercising any of the rights granted to You in Section 1 herein, You indicate Your acceptance of this License and all of its terms and conditions.
10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq., the equivalent laws of other countries, and international treaty. This section shall survive the termination of this License.
12) Attorneys Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
13) Miscellaneous. This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved.
Permission is hereby granted to copy and distribute this license without modification. This license may not be modified without the express written permission of its copyright owner.
---
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, 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 software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, 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 redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's 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 give any other recipients of the Program a copy of this License along with the Program.
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 Program or any portion of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, 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 Program, 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 Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) 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; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, 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 executable. 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.
If distribution of executable or 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 counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program 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.
5. 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 Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program 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.
7. 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 Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program 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 Program.
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.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program 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.
9. The Free Software Foundation may publish revised and/or new versions of the 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 Program 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 Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 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 Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. 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 program's name and an idea of what it does.>
Copyright (C) <yyyy> <name of author>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice

View File

@ -0,0 +1,236 @@
# Copyright 2005-2011 Kitware, Inc.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
include(MacroAddFileDependencies)
function(qt6_add_dbus_interface _sources _interface _relativename)
get_filename_component(_infile ${_interface} ABSOLUTE)
get_filename_component(_basepath ${_relativename} DIRECTORY)
get_filename_component(_basename ${_relativename} NAME)
set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.h")
set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.cpp")
if(_basepath)
set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/moc_${_basename}.cpp")
else()
set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp")
endif()
get_source_file_property(_nonamespace ${_interface} NO_NAMESPACE)
if(_nonamespace)
set(_params -N -m)
else()
set(_params -m)
endif()
get_source_file_property(_classname ${_interface} CLASSNAME)
if(_classname)
set(_params ${_params} -c ${_classname})
endif()
get_source_file_property(_include ${_interface} INCLUDE)
if(_include)
set(_params ${_params} -i ${_include})
endif()
add_custom_command(OUTPUT "${_impl}" "${_header}"
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${_params} -p ${_relativename} ${_infile}
DEPENDS ${_infile} ${QT_CMAKE_EXPORT_NAMESPACE}::qdbuscpp2xml
VERBATIM
)
set_source_files_properties("${_impl}" "${_header}" PROPERTIES
SKIP_AUTOMOC TRUE
SKIP_AUTOUIC TRUE
)
qt6_generate_moc("${_header}" "${_moc}")
list(APPEND ${_sources} "${_impl}" "${_header}")
macro_add_file_dependencies("${_impl}" "${_moc}")
set(${_sources} ${${_sources}} PARENT_SCOPE)
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
# All three positional arguments are mandatory and there are no optional
# arguments, so we can preserve them exactly. As an added bonus, if the
# caller doesn't provide enough arguments, they will get an error message
# for their call site instead of here in the wrapper.
function(qt_add_dbus_interface sources interface relativename)
if(ARGC GREATER 3)
message(FATAL_ERROR "Unexpected arguments: ${ARGN}")
endif()
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
qt5_add_dbus_interface("${sources}" "${interface}" "${relativename}")
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_add_dbus_interface("${sources}" "${interface}" "${relativename}")
endif()
set("${sources}" "${${sources}}" PARENT_SCOPE)
endfunction()
endif()
function(qt6_add_dbus_interfaces _sources)
foreach(_current_FILE ${ARGN})
get_filename_component(_infile ${_current_FILE} ABSOLUTE)
get_filename_component(_basename ${_current_FILE} NAME)
# get the part before the ".xml" suffix
string(TOLOWER ${_basename} _basename)
string(REGEX REPLACE "(.*\\.)?([^\\.]+)\\.xml" "\\2" _basename ${_basename})
qt6_add_dbus_interface(${_sources} ${_infile} ${_basename}interface)
endforeach()
set(${_sources} ${${_sources}} PARENT_SCOPE)
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_dbus_interfaces sources)
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
qt5_add_dbus_interfaces("${sources}" ${ARGN})
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_add_dbus_interfaces("${sources}" ${ARGN})
endif()
set("${sources}" "${${sources}}" PARENT_SCOPE)
endfunction()
endif()
function(qt6_generate_dbus_interface _header) # _customName OPTIONS -some -options )
set(options)
set(oneValueArgs)
set(multiValueArgs OPTIONS)
cmake_parse_arguments(_DBUS_INTERFACE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(_customName ${_DBUS_INTERFACE_UNPARSED_ARGUMENTS})
get_filename_component(_in_file ${_header} ABSOLUTE)
get_filename_component(_basename ${_header} NAME_WE)
if(_customName)
if(IS_ABSOLUTE ${_customName})
get_filename_component(_containingDir ${_customName} PATH)
if(NOT EXISTS ${_containingDir})
file(MAKE_DIRECTORY "${_containingDir}")
endif()
set(_target ${_customName})
else()
set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_customName})
endif()
else()
set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.xml)
endif()
add_custom_command(OUTPUT ${_target}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbuscpp2xml ${_DBUS_INTERFACE_OPTIONS} ${_in_file} -o ${_target}
DEPENDS ${_in_file} ${QT_CMAKE_EXPORT_NAMESPACE}::qdbuscpp2xml
VERBATIM
)
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_generate_dbus_interface)
# The versioned function's implementation doesn't preserve empty options,
# so we don't need to here either. Using ARGV is fine under those assumptions.
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
qt5_generate_dbus_interface(${ARGV})
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_generate_dbus_interface(${ARGV})
endif()
endfunction()
endif()
function(qt6_add_dbus_adaptor _sources _xml_file _include) # _optionalParentClass _optionalRelativename _optionalClassName)
get_filename_component(_infile ${_xml_file} ABSOLUTE)
set(_optionalParentClass "${ARGV3}")
if(_optionalParentClass)
set(_parentClassOption "-l")
set(_parentClass "${_optionalParentClass}")
endif()
set(_optionalRelativename "${ARGV4}")
if(_optionalRelativename)
set(_relativename ${_optionalRelativename})
else()
string(REGEX REPLACE "(.*[/\\.])?([^\\.]+)\\.xml" "\\2adaptor" _relativename ${_infile})
string(TOLOWER ${_relativename} _relativename)
endif()
get_filename_component(_basepath ${_relativename} DIRECTORY)
get_filename_component(_basename ${_relativename} NAME)
set(_optionalClassName "${ARGV5}")
set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.h")
set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.cpp")
if(_basepath)
set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/moc_${_basename}.cpp")
else()
set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp")
endif()
if(_optionalClassName)
add_custom_command(OUTPUT "${_impl}" "${_header}"
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp -m -a ${_relativename} -c ${_optionalClassName} -i ${_include} ${_parentClassOption} ${_parentClass} ${_infile}
DEPENDS ${_infile} ${QT_CMAKE_EXPORT_NAMESPACE}::qdbuscpp2xml
VERBATIM
)
else()
add_custom_command(OUTPUT "${_impl}" "${_header}"
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp -m -a ${_relativename} -i ${_include} ${_parentClassOption} ${_parentClass} ${_infile}
DEPENDS ${_infile} ${QT_CMAKE_EXPORT_NAMESPACE}::qdbuscpp2xml
VERBATIM
)
endif()
qt6_generate_moc("${_header}" "${_moc}")
set_source_files_properties("${_impl}" "${_header}" PROPERTIES
SKIP_AUTOMOC TRUE
SKIP_AUTOUIC TRUE
)
macro_add_file_dependencies("${_impl}" "${_moc}")
list(APPEND ${_sources} "${_impl}" "${_header}")
set(${_sources} ${${_sources}} PARENT_SCOPE)
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_dbus_adaptor sources dbus_spec header)
# We need to preserve empty values in both positional and optional arguments.
# The following explicit use of ARGVx variables ensures we don't silently
# drop any empty values, which is especially important if there are any
# non-empty values after empty ones. Note that we must not try to read
# ARGVx variables where x >= ARGC, as that is undefined behavior.
# Also note that the parent_class argument is required for qt5, but is
# optional for qt6.
if(ARGC LESS 4)
set(parent_class "")
else()
set(parent_class "${ARGV3}")
endif()
if(ARGC LESS 5)
set(basename "")
else()
set(basename "${ARGV4}")
endif()
if(ARGC LESS 6)
set(classname "")
else()
set(classname "${ARGV5}")
endif()
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
qt5_add_dbus_adaptor(
"${sources}" "${dbus_spec}" "${header}"
"${parent_class}" "${basename}" "${classname}"
)
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_add_dbus_adaptor(
"${sources}" "${dbus_spec}" "${header}"
"${parent_class}" "${basename}" "${classname}"
)
endif()
set("${sources}" "${${sources}}" PARENT_SCOPE)
endfunction()
endif()

263
src/dbus/dbus_minimal_p.h Normal file
View File

@ -0,0 +1,263 @@
// Copyright (C) 2002, 2003 CodeFactory AB
// Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
#ifndef DBUS_MINIMAL_P_H
#define DBUS_MINIMAL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of other Qt classes. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
// These structures are not ours, so ELFVERSION:stop
extern "C" {
// Equivalent to dbus-arch-deps.h (generated from dbus-arch-deps.h.in)
typedef qint64 dbus_int64_t;
typedef quint64 dbus_uint64_t;
typedef qint32 dbus_int32_t;
typedef quint32 dbus_uint32_t;
typedef qint16 dbus_int16_t;
typedef quint16 dbus_uint16_t;
// simulate minimum version we support
#define DBUS_MAJOR_VERSION 1
#define DBUS_MINOR_VERSION 2
#define DBUS_VERSION ((1 << 16) | (2 << 8))
// forward declaration to opaque types we use
struct DBusConnection;
struct DBusMessage;
struct DBusPendingCall;
struct DBusServer;
struct DBusTimeout;
struct DBusWatch;
// This file contains constants and typedefs from libdbus-1 headers,
// which carry the following copyright:
/*
* Copyright (C) 2002, 2003 CodeFactory AB
* Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/* dbus-types.h */
typedef dbus_uint32_t dbus_unichar_t;
typedef dbus_uint32_t dbus_bool_t;
/* dbus-shared.h */
typedef enum
{
DBUS_BUS_SESSION, /**< The login session bus */
DBUS_BUS_SYSTEM, /**< The systemwide bus */
DBUS_BUS_STARTER /**< The bus that started us, if any */
} DBusBusType;
typedef enum
{
DBUS_HANDLER_RESULT_HANDLED, /**< Message has had its effect - no need to run more handlers. */
DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect - see if other handlers want it. */
DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */
} DBusHandlerResult;
#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
#define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local"
#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable"
#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
#define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local"
#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */
#define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 /**< Request to replace the current primary owner */
#define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 /**< If we can not become the primary owner do not place us in the queue */
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 /**< Service has become the primary owner of the requested name */
#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 /**< Service could not become the primary owner and has been placed in the queue */
#define DBUS_REQUEST_NAME_REPLY_EXISTS 3 /**< Service is already in the queue */
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 /**< Service is already the primary owner */
#define DBUS_RELEASE_NAME_REPLY_RELEASED 1 /**< Service was released from the given name */
#define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 /**< The given name does not exist on the bus */
#define DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 /**< Service is not an owner of the given name */
/* dbus-memory.h */
typedef void (* DBusFreeFunction) (void *memory);
/* dbus-connection.h */
typedef enum
{
DBUS_WATCH_READABLE = 1 << 0, /**< As in POLLIN */
DBUS_WATCH_WRITABLE = 1 << 1, /**< As in POLLOUT */
DBUS_WATCH_ERROR = 1 << 2, /**< As in POLLERR (can't watch for
* this, but can be present in
* current state passed to
* dbus_watch_handle()).
*/
DBUS_WATCH_HANGUP = 1 << 3 /**< As in POLLHUP (can't watch for
* it, but can be present in current
* state passed to
* dbus_watch_handle()).
*/
/* Internal to libdbus, there is also _DBUS_WATCH_NVAL in dbus-watch.h */
} DBusWatchFlags;
typedef enum
{
DBUS_DISPATCH_DATA_REMAINS, /**< There is more data to potentially convert to messages. */
DBUS_DISPATCH_COMPLETE, /**< All currently available data has been processed. */
DBUS_DISPATCH_NEED_MEMORY /**< More memory is needed to continue. */
} DBusDispatchStatus;
typedef dbus_bool_t (* DBusAddWatchFunction) (DBusWatch *watch,
void *data);
typedef void (* DBusWatchToggledFunction) (DBusWatch *watch,
void *data);
typedef void (* DBusRemoveWatchFunction) (DBusWatch *watch,
void *data);
typedef dbus_bool_t (* DBusAddTimeoutFunction) (DBusTimeout *timeout,
void *data);
typedef void (* DBusTimeoutToggledFunction) (DBusTimeout *timeout,
void *data);
typedef void (* DBusRemoveTimeoutFunction) (DBusTimeout *timeout,
void *data);
typedef void (* DBusDispatchStatusFunction) (DBusConnection *connection,
DBusDispatchStatus new_status,
void *data);
typedef void (* DBusWakeupMainFunction) (void *data);
typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending,
void *user_data);
typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection *connection,
DBusMessage *message,
void *user_data);
/* dbus-errors.h */
struct DBusError
{
const char *name; /**< public error name field */
const char *message; /**< public error message field */
unsigned int dummy1 : 1; /**< placeholder */
unsigned int dummy2 : 1; /**< placeholder */
unsigned int dummy3 : 1; /**< placeholder */
unsigned int dummy4 : 1; /**< placeholder */
unsigned int dummy5 : 1; /**< placeholder */
void *padding1; /**< placeholder */
};
/* dbus-message.h */
struct DBusMessageIter
{
void *dummy1; /**< Don't use this */
void *dummy2; /**< Don't use this */
dbus_uint32_t dummy3; /**< Don't use this */
int dummy4; /**< Don't use this */
int dummy5; /**< Don't use this */
int dummy6; /**< Don't use this */
int dummy7; /**< Don't use this */
int dummy8; /**< Don't use this */
int dummy9; /**< Don't use this */
int dummy10; /**< Don't use this */
int dummy11; /**< Don't use this */
int pad1; /**< Don't use this */
void *pad2; /**< Don't use this */ /* Was int; changed to void* at 1.10.8 */
void *pad3; /**< Don't use this */
};
/* dbus-protocol.h */
#define DBUS_TYPE_INVALID ((int) '\0')
#define DBUS_TYPE_INVALID_AS_STRING "\0"
#define DBUS_TYPE_BYTE ((int) 'y')
#define DBUS_TYPE_BYTE_AS_STRING "y"
#define DBUS_TYPE_BOOLEAN ((int) 'b')
#define DBUS_TYPE_BOOLEAN_AS_STRING "b"
#define DBUS_TYPE_INT16 ((int) 'n')
#define DBUS_TYPE_INT16_AS_STRING "n"
#define DBUS_TYPE_UINT16 ((int) 'q')
#define DBUS_TYPE_UINT16_AS_STRING "q"
#define DBUS_TYPE_INT32 ((int) 'i')
#define DBUS_TYPE_INT32_AS_STRING "i"
#define DBUS_TYPE_UINT32 ((int) 'u')
#define DBUS_TYPE_UINT32_AS_STRING "u"
#define DBUS_TYPE_INT64 ((int) 'x')
#define DBUS_TYPE_INT64_AS_STRING "x"
#define DBUS_TYPE_UINT64 ((int) 't')
#define DBUS_TYPE_UINT64_AS_STRING "t"
#define DBUS_TYPE_DOUBLE ((int) 'd')
#define DBUS_TYPE_DOUBLE_AS_STRING "d"
#define DBUS_TYPE_STRING ((int) 's')
#define DBUS_TYPE_STRING_AS_STRING "s"
#define DBUS_TYPE_OBJECT_PATH ((int) 'o')
#define DBUS_TYPE_OBJECT_PATH_AS_STRING "o"
#define DBUS_TYPE_SIGNATURE ((int) 'g')
#define DBUS_TYPE_SIGNATURE_AS_STRING "g"
#define DBUS_TYPE_UNIX_FD ((int) 'h')
#define DBUS_TYPE_UNIX_FD_AS_STRING "h"
#define DBUS_TYPE_ARRAY ((int) 'a')
#define DBUS_TYPE_ARRAY_AS_STRING "a"
#define DBUS_TYPE_VARIANT ((int) 'v')
#define DBUS_TYPE_VARIANT_AS_STRING "v"
#define DBUS_TYPE_STRUCT ((int) 'r')
#define DBUS_TYPE_STRUCT_AS_STRING "r"
#define DBUS_TYPE_DICT_ENTRY ((int) 'e')
#define DBUS_TYPE_DICT_ENTRY_AS_STRING "e"
#define DBUS_STRUCT_BEGIN_CHAR ((int) '(')
#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING "("
#define DBUS_STRUCT_END_CHAR ((int) ')')
#define DBUS_STRUCT_END_CHAR_AS_STRING ")"
#define DBUS_DICT_ENTRY_BEGIN_CHAR ((int) '{')
#define DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING "{"
#define DBUS_DICT_ENTRY_END_CHAR ((int) '}')
#define DBUS_DICT_ENTRY_END_CHAR_AS_STRING "}"
#define DBUS_MAXIMUM_NAME_LENGTH 255
#define DBUS_MESSAGE_TYPE_INVALID 0
#define DBUS_MESSAGE_TYPE_METHOD_CALL 1
#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
#define DBUS_MESSAGE_TYPE_ERROR 3
#define DBUS_MESSAGE_TYPE_SIGNAL 4
#define DBUS_INTROSPECT_1_0_XML_NAMESPACE "http://www.freedesktop.org/standards/dbus"
#define DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
#define DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"
#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "\">\n"
/* dbus-server.h */
typedef void (* DBusNewConnectionFunction) (DBusServer *server,
DBusConnection *new_connection,
void *data);
} // extern "C"
#endif // DBUS_MINIMAL_P_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,70 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
include($QT_INSTALL_DOCS/config/exampleurl-qtbase.qdocconf)
# Name of the project which must match the outputdir. Determines the .index file
project = QtDBus
description = Qt D-Bus Reference Documentation
version = $QT_VERSION
# Directories in which to search for files to document and images.
# By default set to the root directory of the project for sources
# and headers and qdoc will therefore generate output for each file.
# Images should be placed in <rootdir>/dic/images and examples in
# <rootdir>/examples.
# Paths are relative to the location of this file.
exampledirs += . \
snippets \
../../../examples/dbus
headerdirs += ..
imagedirs += images \
../../../examples/dbus/doc/images
sourcedirs += .. \
../../../examples/dbus/doc/src
excludedirs += ../../../examples/widgets/doc
examplesinstallpath = dbus
tagfile = qtdbus.tags
depends += qtcore qtdoc qmake qtcmake
# The following parameters are for creating a qhp file, the qhelpgenerator
# program can convert the qhp file into a qch file which can be opened in
# Qt Assistant and/or Qt Creator.
# Defines the name of the project. You cannot use operators (+, =, -) in
# the name. Properties for this project are set using a qhp.<projectname>.property
# format.
qhp.projects = QtDBus
# Sets the name of the output qhp file.
qhp.QtDBus.file = qtdbus.qhp
# Namespace for the output file. This namespace is used to distinguish between
# different documentation files in Creator/Assistant.
qhp.QtDBus.namespace = org.qt-project.qtdbus.$QT_VERSION_TAG
# Title for the package, will be the main title for the package in
# Assistant/Creator.
qhp.QtDBus.indexTitle = Qt D-Bus
# Only update the name of the project for the next variables.
qhp.QtDBus.virtualFolder = qtdbus
qhp.QtDBus.subprojects = classes examples
qhp.QtDBus.subprojects.classes.title = C++ Classes
qhp.QtDBus.subprojects.classes.indexTitle = Qt D-Bus C++ Classes
qhp.QtDBus.subprojects.classes.selectors = class fake:headerfile
qhp.QtDBus.subprojects.classes.sortPages = true
qhp.QtDBus.subprojects.examples.title = Examples
qhp.QtDBus.subprojects.examples.indexTitle = Qt D-Bus Examples
qhp.QtDBus.subprojects.examples.selectors = fake:example
navigation.landingpage = "Qt D-Bus"
navigation.cppclassespage = "Qt D-Bus C++ Classes"
manifestmeta.thumbnail.names = "QtDBus/D-Bus Ping Pong" \
"QtDBus/D-Bus Complex Ping Pong"
# Fail the documentation build if there are more warnings than the limit
warninglimit = 0

View File

@ -0,0 +1,7 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS DBus)
target_link_libraries(mytarget PRIVATE Qt6::DBus)
#! [cmake_use]

View File

@ -0,0 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#! [qt_add_dbus_adaptor]
qt_add_dbus_adaptor(GENERATED_SOURCES org.example.chat.xml chat.h ChatMainWindow)
#! [qt_add_dbus_adaptor]

View File

@ -0,0 +1,11 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
org.freedesktop.DBus
//! [0]
//! [QDBUS_DEBUG]
examples/dbus/remotecontrolledcar/controller/controller &
QDBUS_DEBUG=1 examples/dbus/remotecontrolledcar/car/car &
//! [QDBUS_DEBUG]

View File

@ -0,0 +1,49 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QString>
#include <QDBusMessage>
#include <QDBusConnection>
struct RequestData;
void appendRequest(RequestData *) {}; // stub
//! [10]
struct RequestData
{
QString request;
QString processedData;
QDBusMessage reply;
};
QString processRequest(const QString &request, const QDBusMessage &message)
{
RequestData *data = new RequestData;
data->request = request;
message.setDelayedReply(true);
data->reply = message.createReply();
appendRequest(data);
return QString();
}
//! [10]
//! [11]
void sendReply(RequestData *data)
{
// data->processedData has been initialized with the request's reply
QDBusMessage &reply = data->reply;
// send the reply over D-Bus:
reply << data->processedData;
QDBusConnection::sessionBus().send(reply);
// dispose of the transaction data
delete data;
}
//! [11]
//! [12]
Q_NOREPLY void myMethod();
//! [12]

View File

@ -0,0 +1,58 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QString>
#include <QDBusMessage>
#include <QDBusReply>
#include <QDBusInterface>
using namespace Qt::StringLiterals;
class Abstract_DBus_Interface : public QObject
{
Q_OBJECT
public:
Abstract_DBus_Interface(QObject *parent = nullptr)
: QObject(parent) {
interface = new QDBusInterface("org.example.Interface", "/Example/Methods");
}
~Abstract_DBus_Interface() { delete interface; }
void interfaceMain();
void asyncCall();
QString retrieveValue() { return QString(); }
public slots:
void callFinishedSlot();
private:
QDBusInterface *interface;
};
void Abstract_DBus_Interface::interfaceMain()
{
//! [0]
QString value = retrieveValue();
QDBusMessage reply;
QDBusReply<int> api = interface->call("GetAPIVersion"_L1);
if (api >= 14)
reply = interface->call("ProcessWorkUnicode"_L1, value);
else
reply = interface->call("ProcessWork"_L1, "UTF-8"_L1, value.toUtf8());
//! [0]
}
void Abstract_DBus_Interface::asyncCall()
{
//! [1]
QString value = retrieveValue();
QDBusPendingCall pcall = interface->asyncCall("Process"_L1, value);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall);
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
//! [1]
}

View File

@ -0,0 +1,258 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QString>
#include <QDBusArgument>
#include <QDBusMetaType>
#include <QDBusMessage>
#include <QDBusContext>
typedef QDBusVariant MyElement;
typedef QList<MyElement> MyArray;
typedef QHash<int, MyElement> MyDictionary;
typedef QDBusVariant MyType;
typedef QDBusVariant MyValue;
typedef QDBusVariant Type;
QDBusArgument argument;
class MyObject: public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.qtproject.QtDBus.MyObject")
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=\"org.qtproject.QtDBus.MyObject\" >\n"
" <property access=\"readwrite\" type=\"i\" name=\"prop1\" />\n"
" <property name=\"complexProp\" type=\"ai\" access=\"readwrite\">\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"QList&lt;int&gt;\"/>\n"
" </property>\n"
" <signal name=\"somethingHappened\" >\n"
" <arg direction=\"out\" type=\"s\" />\n"
" </signal>\n"
" <method name=\"ping\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"ping\" />\n"
" </method>\n"
" <method name=\"ping_invokable\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping_invokable\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"ping_invokable\" />\n"
" </method>\n"
" <method name=\"ping\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping1\" />\n"
" <arg direction=\"in\" type=\"v\" name=\"ping2\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong1\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong2\" />\n"
" </method>\n"
" <method name=\"ping_invokable\" >\n"
" <arg direction=\"in\" type=\"v\" name=\"ping1_invokable\" />\n"
" <arg direction=\"in\" type=\"v\" name=\"ping2_invokable\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong1_invokable\" />\n"
" <arg direction=\"out\" type=\"v\" name=\"pong2_invokable\" />\n"
" </method>\n"
" <method name=\"ping\" >\n"
" <arg direction=\"in\" type=\"ai\" name=\"ping\" />\n"
" <arg direction=\"out\" type=\"ai\" name=\"ping\" />\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
" </method>\n"
" <method name=\"ping_invokable\" >\n"
" <arg direction=\"in\" type=\"ai\" name=\"ping_invokable\" />\n"
" <arg direction=\"out\" type=\"ai\" name=\"ping_invokable\" />\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.In0\" value=\"QList&lt;int&gt;\"/>\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QList&lt;int&gt;\"/>\n"
" </method>\n"
" </interface>\n"
"")
Q_PROPERTY(int prop1 READ prop1 WRITE setProp1)
Q_PROPERTY(QList<int> complexProp READ complexProp WRITE setComplexProp)
public:
static int callCount;
static QVariantList callArgs;
MyObject()
{
QObject *subObject = new QObject(this);
subObject->setObjectName("subObject");
}
};
struct MyMember
{
int subMember1;
int subMember2;
};
//! [0-0]
struct MyStructure
{
int count;
QString name;
//! [0-0]
MyMember member1;
MyMember member2;
MyMember member3;
MyMember member4;
//! [0-1]
// ...
};
Q_DECLARE_METATYPE(MyStructure)
// Marshall the MyStructure data into a D-Bus argument
QDBusArgument &operator<<(QDBusArgument &argument, const MyStructure &myStruct)
{
argument.beginStructure();
argument << myStruct.count << myStruct.name;
argument.endStructure();
return argument;
}
// Retrieve the MyStructure data from the D-Bus argument
const QDBusArgument &operator>>(const QDBusArgument &argument, MyStructure &myStruct)
{
argument.beginStructure();
argument >> myStruct.count >> myStruct.name;
argument.endStructure();
return argument;
}
//! [0-1]
const QDBusArgument &operator<<(const QDBusArgument &argument, const MyMember &/*member*/)
{
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, const MyMember &/*member*/)
{
return argument;
}
void registerMyStructure()
{
//! [1]
qDBusRegisterMetaType<MyStructure>();
//! [1]
}
void castType()
{
QVariant argument = MyObject::callArgs.at(0);
QDBusVariant dv = qdbus_cast<QDBusVariant>(argument);
//! [2]
MyType item = qdbus_cast<Type>(argument);
//! [2]
}
void argumentItem()
{
//! [3]
MyType item;
argument >> item;
//! [3]
}
namespace QDBusSnippets
{
//! [4]
QDBusArgument &operator<<(QDBusArgument &argument, const MyStructure &myStruct)
{
argument.beginStructure();
argument << myStruct.member1 << myStruct.member2;
argument.endStructure();
return argument;
}
//! [4]
namespace Alt {
//! [5]
QDBusArgument &operator<<(QDBusArgument &argument, const MyStructure &myStruct)
{
argument.beginStructure();
argument << myStruct.member1 << myStruct.member2;
argument.beginStructure();
argument << myStruct.member3.subMember1 << myStruct.member3.subMember2;
argument.endStructure();
argument << myStruct.member4;
argument.endStructure();
return argument;
}
//! [5]
} // namespace
//! [6]
// Append an array of MyElement types
QDBusArgument &operator<<(QDBusArgument &argument, const MyArray &myArray)
{
argument.beginArray(qMetaTypeId<MyElement>());
for (const auto &element : myArray)
argument << element;
argument.endArray();
return argument;
}
//! [6]
//! [7]
// Append a dictionary that associates ints to MyValue types
QDBusArgument &operator<<(QDBusArgument &argument, const MyDictionary &myDict)
{
argument.beginMap(QMetaType::fromType<int>(), QMetaType::fromType<MyValue>());
MyDictionary::const_iterator i;
for (i = myDict.cbegin(); i != myDict.cend(); ++i) {
argument.beginMapEntry();
argument << i.key() << i.value();
argument.endMapEntry();
}
argument.endMap();
return argument;
}
//! [7]
//! [8]
const QDBusArgument &operator>>(const QDBusArgument &argument, MyStructure &myStruct)
{
argument.beginStructure();
argument >> myStruct.member1 >> myStruct.member2 >> myStruct.member3;
argument.endStructure();
return argument;
}
//! [8]
//! [9]
// Extract a MyArray array of MyElement elements
const QDBusArgument &operator>>(const QDBusArgument &argument, MyArray &myArray)
{
argument.beginArray();
myArray.clear();
while (!argument.atEnd()) {
MyElement element;
argument >> element;
myArray.append(element);
}
argument.endArray();
return argument;
}
//! [9]
//! [10]
// Extract a MyDictionary map that associates integers to MyElement items
const QDBusArgument &operator>>(const QDBusArgument &argument, MyDictionary &myDict)
{
argument.beginMap();
myDict.clear();
while (!argument.atEnd()) {
int key;
MyElement value;
argument.beginMapEntry();
argument >> key >> value;
argument.endMapEntry();
myDict.insert(key, value);
}
argument.endMap();
return argument;
}
//! [10]
}

View File

@ -0,0 +1,43 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QString>
#include <QDBusConnection>
#include <QDBusArgument>
#include <QDBusMetaType>
#include <QDBusMessage>
#include <QDBusContext>
//! [0]
class MyObject: public QObject,
protected QDBusContext
{
Q_OBJECT
QDBusConnection conn;
QDBusMessage msg;
//...
protected slots:
void process();
public slots:
void methodWithError();
QString methodWithDelayedReply();
};
void MyObject::methodWithError()
{
sendErrorReply(QDBusError::NotSupported,
"The method call 'methodWithError()' is not supported");
}
QString MyObject::methodWithDelayedReply()
{
conn = connection();
msg = message();
setDelayedReply(true);
QMetaObject::invokeMethod(this, "process", Qt::QueuedConnection);
return QString();
}
//! [0]

View File

@ -0,0 +1,19 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QDBusInterface>
#include <QDBusReply>
void DBusInterface_main()
{
//! [0]
QDBusInterface remoteApp( "com.example.Calculator", "/Calculator/Operations",
"org.mathematics.RPNCalculator" );
remoteApp.call( "PushOperand", 2 );
remoteApp.call( "PushOperand", 2 );
remoteApp.call( "ExecuteOperation", "+" );
QDBusReply<int> reply = remoteApp.call( "PopOperand" );
if ( reply.isValid() )
printf( "%d", reply.value() ); // prints 4
//! [0]
}

View File

@ -0,0 +1,14 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore/qlist.h>
typedef QList<QString> MyClass;
//! [0-0]
#include <QDBusMetaType>
//! [0-0]
void dbus() {
//! [0-1]
qDBusRegisterMetaType<MyClass>();
//! [0-1]
}

View File

@ -0,0 +1,55 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QDBusPendingCall>
#include <QDBusInterface>
#include <QDBusPendingReply>
class DBus_PendingCall_Interface : public QObject
{
Q_OBJECT
public:
DBus_PendingCall_Interface(QObject *parent = nullptr)
: QObject(parent) {
iface = new QDBusInterface("org.example.Interface", "/Example/Methods");
}
~DBus_PendingCall_Interface() { delete iface; }
void callInterfaceMain();
void showError();
void showReply(QString&, QByteArray&);
QString value1;
QString value2;
void callFinishedSlot(QDBusPendingCallWatcher *call);
public slots:
private:
QDBusInterface *iface;
};
void DBus_PendingCall_Interface::callInterfaceMain()
{
//! [0]
QDBusPendingCall async = iface->asyncCall("RemoteMethod", value1, value2);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
//! [0]
}
//! [1]
void DBus_PendingCall_Interface::callFinishedSlot(QDBusPendingCallWatcher *call)
{
QDBusPendingReply<QString, QByteArray> reply = *call;
if (reply.isError()) {
showError();
} else {
QString text = reply.argumentAt<0>();
QByteArray data = reply.argumentAt<1>();
showReply(text, data);
}
call->deleteLater();
}
//! [1]

View File

@ -0,0 +1,57 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QDBusPendingCall>
#include <QDBusInterface>
#include <QDBusPendingReply>
class DBus_PendingReply_Interface : public QObject
{
Q_OBJECT
public:
DBus_PendingReply_Interface(QObject *parent = nullptr)
: QObject(parent) {
iface = new QDBusInterface("org.example.Interface", "/Example/Methods");
}
~DBus_PendingReply_Interface() { delete iface; }
void callInterfaceMainR();
void PendingReplyString();
void PendingReplyBool();
void showErrorD(QDBusError);
void showSuccess(QVariant);
void showFailure(QVariant);
void useValue(QDBusPendingReplyTypes::Select<0, QString, void, void, void, void, void, void, void>::Type);
public slots:
private:
QDBusInterface *iface;
};
void DBus_PendingReply_Interface::PendingReplyString()
{
//! [0]
QDBusPendingReply<QString> reply = iface->asyncCall("RemoteMethod");
reply.waitForFinished();
if (reply.isError())
// call failed. Show an error condition.
showErrorD(reply.error());
else
// use the returned value
useValue(reply.value());
//! [0]
}
void DBus_PendingReply_Interface::PendingReplyBool()
{
//! [2]
QDBusPendingReply<bool, QString> reply = iface->asyncCall("RemoteMethod");
reply.waitForFinished();
if (!reply.isError()) {
if (reply.argumentAt<0>())
showSuccess(reply.argumentAt<1>());
else
showFailure(reply.argumentAt<1>());
}
//! [2]
}

View File

@ -0,0 +1,43 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QDBusPendingCall>
#include <QDBusInterface>
#include <QDBusPendingReply>
#include <QDBusReply>
class DBus_Process_String_Interface : public QObject
{
Q_OBJECT
public:
DBus_Process_String_Interface(QObject *parent = nullptr)
: QObject(parent) {
interface = new QDBusInterface("org.example.Interface", "/Example/Methods");
}
~DBus_Process_String_Interface() { delete interface; }
void QDBus_reply();
void useValue(QVariant);
void showError(const QDBusError&);
public slots:
private:
QDBusInterface *interface;
};
void DBus_Process_String_Interface::QDBus_reply()
{
//! [0]
QDBusReply<QString> reply = interface->call("RemoteMethod");
if (reply.isValid())
// use the returned value
useValue(reply.value());
else
// call failed. Show an error condition.
showError(reply.error());
//! [0]
//! [1]
reply = interface->call("RemoteMethod");
//! [1]
}

View File

@ -0,0 +1,29 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore>
static QVariant callMyDBusFunction() { return QVariant(); }
int main()
{
QDBusMessage myDBusMessage;
//! [0]
QList<QVariant> arguments;
arguments << QVariant(42) << QVariant::fromValue(QDBusVariant(43)) << QVariant("hello");
myDBusMessage.setArguments(arguments);
//! [0]
//! [1]
// call a D-Bus function that returns a D-Bus variant
QVariant v = callMyDBusFunction();
// retrieve the D-Bus variant
QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(v);
// retrieve the actual value stored in the D-Bus variant
QVariant result = dbusVariant.variant();
//! [1]
return 0;
}

View File

@ -0,0 +1,3 @@
#! [qmake_use]
QT += dbus
#! [qmake_use]

View File

@ -0,0 +1,331 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page usingadaptors.html
\title Using Qt D-Bus Adaptors
\brief How to create and use DBus adaptors in Qt.
\ingroup best-practices
Adaptors are special classes that are attached to any QObject-derived class
and provide the interface to the external world using D-Bus. Adaptors are
intended to be lightweight classes whose main purpose is to relay calls to
and from the real object, possibly validating or converting the input from
the external world and, thus, protecting the real object.
Unlike multiple inheritance, adaptors can be added at any time to any object
(but not removed), which allows for greater flexibility when exporting
existing classes. Another advantage of adaptors is to provide similar but not
identical functionality in methods of the same name in different interfaces,
a case which can be quite common when adding a new version of a standard
interface to an object.
In order to use an adaptor, one must create a class which inherits
QDBusAbstractAdaptor. Since that is a standard QObject-derived class, the
Q_OBJECT macro must appear in the declaration and the source file must be
processed with the \l {moc} tool. The class must also contain one
Q_CLASSINFO entry with the \c {"D-Bus Interface"} name, declaring which
interface it is exporting. Only one entry per class is supported.
Any public slot in the class will be accessible through the bus over messages
of the MethodCall type. (See \l {Declaring Slots in D-Bus Adaptors} for more
information). Signals in the class will be automatically relayed over D-Bus.
However, not all types are allowed signals or slots' parameter lists: see
\l {The Qt D-Bus Type System} for more information.
Also, any property declared with Q_PROPERTY will be automatically exposed
over the Properties interface on D-Bus. Since the QObject property system
does not allow for non-readable properties, it is not possible to declare
write-only properties using adaptors.
More information:
\list
\li \l{Declaring Slots in D-Bus Adaptors}
\li \l{Declaring Signals in D-Bus Adaptors}
\li \l{The Qt D-Bus Type System}
\li In the \l{D-Bus Complex Ping Pong} example, \c complexpong.h and
\c complexpong.cpp show an implementation of QDBusAbstractAdaptor.
\endlist
\sa QDBusAbstractAdaptor
*/
/*!
\page qdbusdeclaringslots.html
\title Declaring Slots in D-Bus Adaptors
\nextpage Declaring Signals in D-Bus Adaptors
Slots in D-Bus adaptors are declared just like normal, public slots, but their
parameters must follow certain rules (see \l{The Qt D-Bus Type System} for more
information). Slots whose parameters do not follow those rules or that are not
public will not be accessible via D-Bus.
Slots can have one parameter of type \c{const QDBusMessage &}, which must
appear at the end of the input parameter list, before any output parameters.
This parameter, if present, will be initialized with a copy of the
current message being processed, which allows the callee to obtain
information about the caller, such as its connection name.
Slots can be of three kinds:
\list 1
\li Asynchronous
\li Input-only
\li Input-and-output
\endlist
\section1 Asynchronous Slots
Asynchronous slots are those that do not normally return any reply to the
caller. For that reason, they cannot take any output parameters. In most
cases, by the time the first line of the slot is run, the caller function
has already resumed working.
However, slots must not rely on that behavior. Scheduling and message-dispatching
issues could change the order in which the slot is run. Code intending to
synchronize with the caller should provide its own method of synchronization.
Asynchronous slots are marked by the keyword \l Q_NOREPLY in the method
signature, before the \c void return type and the slot name. The \c quit()
slot in the \l {D-Bus Complex Ping Pong} example is an example of this.
\section1 Input-Only Slots
Input-only slots are normal slots that take parameters passed by value or
by constant reference. However, unlike asynchronous slots, the caller is
usually waiting for completion of the callee before resuming operation.
Therefore, non-asynchronous slots should not block or should state it its
documentation that they may do so.
Input-only slots have no special marking in their signature, except that
they take only parameters passed by value or by constant reference.
Optionally, slots can take a QDBusMessage parameter as a last parameter,
which can be used to perform additional analysis of the method call message.
\section1 Input and Output Slots
Like input-only slots, input-and-output slots are those that the caller is
waiting for a reply. Unlike input-only ones, though, this reply will contain
data. Slots that output data may contain non-constant references and may
return a value as well. However, the output parameters must all appear at
the end of the argument list and may not have input arguments interleaved.
Optionally, a QDBusMessage argument may appear between the input and the
output arguments.
\section1 Automatic Replies
Method replies are generated automatically with the contents of the output
parameters (if there were any) by the Qt D-Bus implementation. Slots need not
worry about constructing proper QDBusMessage objects and sending them over
the connection.
However, the possibility of doing so remains there. Should the slot find out
it needs to send a special reply or even an error, it can do so by using
QDBusMessage::createReply() or QDBusMessage::createErrorReply() on the
QDBusMessage parameter and send it with QDBusConnection::send(). The
Qt D-Bus implementation will not generate any reply if the slot did so.
\warning When a caller places a method call and waits for a reply, it will
only wait for a limited amount of time. Slots intending to take a long time
to complete should make that fact clear in documentation so that callers
properly set higher timeouts.
\section1 Delayed Replies
In some circumstances, the called slot may not be able to process
the request immediately. This is frequently the case when the
request involves an I/O or networking operation which may block.
If this is the case, the slot should return control to the
application's main loop to avoid freezing the user interface, and
resume the process later. To accomplish this, it should make use
of the extra \c QDBusMessage parameter at the end of the input
parameter list and request a delayed reply.
We do this by writing a slot that stores the request data in a
persistent structure, indicating to the caller using
\l{QDBusMessage::setDelayedReply()}{QDBusMessage::setDelayedReply(true)}
that the response will be sent later.
\snippet code/doc_src_qdbusadaptors.cpp 10
In this case, the return value is unimportant; we return an arbitrary value
to satisfy the compiler.
When the request is processed and a reply is available, it should be sent
using the \c QDBusMessage object that was obtained. In our example, the
reply code could be something as follows:
\snippet code/doc_src_qdbusadaptors.cpp 11
As can be seen in the example, when a delayed reply is in place,
the return value(s) from the slot will be ignored by Qt D-Bus. They
are used only to determine the slot's signature when communicating
the adaptor's description to remote applications, or in case the
code in the slot decides not to use a delayed reply.
The delayed reply itself is requested from Qt D-Bus by calling
QDBusMessage::reply() on the original message. It then becomes the
responsibility of the called code to eventually send a reply to the
caller.
\warning When a caller places a method call and waits for a reply, it will
only wait for a limited amount of time. Slots intending to take a long time
to complete should make that fact clear in documentation so that callers
properly set higher timeouts.
\sa {Using Qt D-Bus Adaptors}, {Declaring Signals in D-Bus Adaptors},
{The Qt D-Bus Type System}, QDBusConnection, QDBusMessage
*/
/*!
\page qdbusdeclaringsignals.html
\title Declaring Signals in D-Bus Adaptors
\previouspage Declaring Slots in D-Bus Adaptors
\nextpage The Qt D-Bus Type System
Any signal in a class derived from QDBusAbstractAdaptor will be automatically
relayed into D-Bus, provided that the signal's parameters conform to certain
rules (see \l{The Qt D-Bus Type System} for more information). No special code
is necessary to make this relay.
However, signals must still be emitted. The easiest way to emit an adaptor
signal is to connect another signal to it, so that Qt's signals and slots
mechanism automatically emits the adaptor signal, too. This can be done in
the adaptor's constructor, as you can see in the \l {D-Bus Complex Ping Pong}
example.
The QDBusAbstractAdaptor::setAutoRelaySignals() convenience function can also
be used to make and break connections between signals in the real object and
the corresponding signals in the adaptor. It will inspect the list of signals
in both classes and connect those whose parameters match exactly.
\sa {Using Qt D-Bus Adaptors},
{Declaring Slots in D-Bus Adaptors},
{The Qt D-Bus Type System}, QDBusAbstractAdaptor
*/
/*!
\page qdbustypesystem.html
\title The Qt D-Bus Type System
\previouspage Declaring Signals in D-Bus Adaptors
D-Bus has an extensible type system based on a few primitives and
composition of the primitives in arrays and structures. Qt D-Bus
implements the interface to that type system through the
QDBusArgument class, allowing user programs to send and receive
practically every C++ type over the bus.
\section1 Primitive Types
The primitive types are supported natively by QDBusArgument and
need no special customization to be sent or received. They are
listed below, along with the C++ class they relate to:
\table
\header
\li Qt type
\li D-Bus equivalent type
\row
\li uchar
\li BYTE
\row
\li bool
\li BOOLEAN
\row
\li short
\li INT16
\row
\li ushort
\li UINT16
\row
\li int
\li INT32
\row
\li uint
\li UINT32
\row
\li qlonglong
\li INT64
\row
\li qulonglong
\li UINT64
\row
\li double
\li DOUBLE
\row
\li QString
\li STRING
\row
\li QDBusVariant
\li VARIANT
\row
\li QDBusObjectPath
\li OBJECT_PATH
\row
\li QDBusSignature
\li SIGNATURE
\endtable
Aside from the primitive types, QDBusArgument also supports two
non-primitive types natively, due to their widespread use in Qt
applications: QStringList and QByteArray.
\section1 Compound Types
D-Bus specifies three types of aggregations of primitive types
that allow one to create compound types. They are \c ARRAY, \c
STRUCT and maps/dictionaries.
Arrays are sets of zero or more elements of the same type, while
structures are a set of a fixed number of elements, each of any
type. Maps or dictionaries are implemented as arrays of a pair of
elements, so there can be zero or more elements in one map.
\section1 Extending the Type System
In order to use one's own type with Qt D-Bus, the type has to be
declared as a Qt meta-type with the Q_DECLARE_METATYPE() macro and
registered with the qDBusRegisterMetaType() function. The
streaming operators \c{operator>>} and \c{operator<<} will be
automatically found by the registration system.
Qt D-Bus provides template specializations for arrays and maps for
use with Qt's \l{Container classes}{container classes}, such as
QMap and QList, so it is not necessary to write the streaming
operator functions for those. For other types, and specially for
types implementing structures, the operators have to be explicitly
implemented.
See the documentation for QDBusArgument for examples for
structures, arrays and maps.
\section1 The Type System in Use
All of the Qt D-Bus types (primitives and user-defined alike) can be
used to send and receive messages of all types over the bus.
\warning You may not use any type that is not on the list above,
including \a typedefs to the types listed. This also includes
QList<QVariant> and QMap<QString,QVariant>.
*/
/*!
\macro Q_NOREPLY
\relates QDBusAbstractAdaptor
\since 4.2
The Q_NOREPLY macro can be used to mark a method to be called and not wait for it to finish
processing before returning from QDBusInterface::call(). The called method cannot return any
output arguments and, if it does, any such arguments will be discarded.
You can use this macro in your own adaptors by placing it before your method's return value
(which must be "void") in the class declaration, as shown in the example:
\snippet code/doc_src_qdbusadaptors.cpp 12
Its presence in the method implementation (outside the class declaration) is optional.
\sa {Using Qt D-Bus Adaptors}
*/

View File

@ -0,0 +1,6 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\dontdocument (QTypeInfo QMetaTypeId QDBusAbstractInterfaceBase QDBusPendingReplyData QMetaTypeId2)
*/

View File

@ -0,0 +1,5 @@
The command is defined in the \c DBus component of the \c Qt6 package. Load the package with:
\code
find_package(Qt6 REQUIRED COMPONENTS DBus)
\endcode

View File

@ -0,0 +1,25 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qdbusxml2cpp.html
\title Qt D-Bus XML compiler (qdbusxml2cpp)
\keyword qdbusxml2cpp
The Qt D-Bus XML compiler is a tool that can be used to parse interface descriptions and produce
static code representing those interfaces, which can then be used to make calls to remote
objects or implement said interfaces.
\c qdbusxml2cpp has two modes of operation, that correspond to the two possible outputs it can
produce: the interface (proxy) class or the adaptor class. The latter consists of both a C++
header and a source file, which are meant to be edited and adapted to your needs.
The \c qdbusxml2cpp tool is not meant to be run every time you compile your
application. Instead, it's meant to be used when developing the code or when the interface
changes.
The adaptor classes generated by \c qdbusxml2cpp are just a skeleton that must be completed. It
generates, by default, calls to slots with the same name on the object the adaptor is attached
to. However, you may modify those slots or the property accessor functions to suit your needs.
*/

View File

@ -0,0 +1,44 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page dbus-changes-qt6.html
\title Changes to Qt D-Bus
\ingroup changes-qt-5-to-6
\brief Migrate Qt DBus to Qt 6.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
We try to maintain binary and source compatibility for all the public
APIs in each release. But some changes were inevitable in an effort to
make Qt a better framework.
In this topic we summarize those changes in Qt DBus, and provide
guidance to handle them.
\section1 API changes
The QtDBus module has undergone some basic consolidation and
cleanup. There should be minimal porting effort to be able to switch to Qt6.
\section2 The QDBusMessage class
The QDBusMessage::call() and QDBusMessage::asyncCall() methods with a fixed
size of arguments have been removed in Qt6.
\section2 The QDBusArgument class
The QDBusArgument::operator<<() specializations for QHash, QMap and QList
have been unified into common specializations for associative containers.
\section2 The QDBusConnection class
The QDBusConnection::sender() function has been removed in Qt6.
\section2 The QDBusMessage class
The QDBusMessage::createErrorReply() function now takes the QString \c name
argument by const reference instead of taking by value.
\section2 The QDBusPendingReply class
QDBusPendingReply has been changed to be a variadic template class in order
to support more than 8 template parameters now. The template parameters
are the types that will be used to extract the contents of the reply's data.
*/

View File

@ -0,0 +1,307 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\group cmake-commands-qtdbus
\title CMake Commands in Qt6 DBus
\brief Lists CMake commands defined in Qt6::DBus.
The following CMake commands are defined when Qt6::DBus is loaded, for instance
with
\code
find_package(Qt6 REQUIRED COMPONENTS DBus)
\endcode
\sa{CMake Command Reference}
*/
/*!
\page qtdbus-cmake-qt-add-dbus-interface.html
\ingroup cmake-commands-qtdbus
\title qt_add_dbus_interface
\keyword qt6_add_dbus_interface
\summary {Generates C++ sources implementing an interface for a D-Bus interface
description file.}
\include cmake-find-package-dbus.qdocinc
\cmakecommandsince 6.0
\section1 Synopsis
\badcode
qt_add_dbus_interface(<VAR> dbus_spec basename)
\endcode
\versionlessCMakeCommandsNote qt6_add_dbus_interface()
\section1 Description
Generates C++ sources implementing an interface for a D-Bus interface description
file defined in \c{dbus_spec}. The generated files are named after \c{basename}:
\c{basename.h}, \c{basename.cpp}, \c{basename.moc}. The paths of the files
are added to \c{<VAR>}.
The function sets up a call to the \l{Qt D-Bus XML compiler (qdbusxml2cpp)}
in interface (proxy) mode. By default, \c{qdbusxml2cpp} generates a C++
class named after the interface name, with a namespaced alias:
\table
\header
\li D-Bus Interface Name
\li Class name
\li Namespaced name
\row
\li \c{org.example.chat}
\li \c{OrgExampleChatInterface}
\li \c{org.example.chat}
\endtable
\section1 Options
Options can be set using \c set_source_files_properties on the \c dbus_spec:
\table
\header
\li Option
\li Value
\li Description
\row
\li \c CLASSNAME
\li \c class_name
\li Override the default interface class name with \c{class_name}.
\row
\li \c NO_NAMESPACE
\li boolean
\li Do not generate the namespaced name if set to \c{ON}.
\row
\li \c INCLUDE
\li \c path
\li Add an \c{#include "path"} in the generated code.
\endtable
*/
/*!
\page qtdbus-cmake-qt-add-dbus-interfaces.html
\ingroup cmake-commands-qtdbus
\title qt_add_dbus_interfaces
\keyword qt6_add_dbus_interfaces
\summary {Generates C++ sources implementing interfaces for D-Bus interface
description files.}
\include cmake-find-package-dbus.qdocinc
\cmakecommandsince 6.0
\section1 Synopsis
\badcode
qt_add_dbus_interfaces(<VAR> dbus_spec1 [dbus_spec2 ...])
\endcode
\versionlessCMakeCommandsNote qt6_add_dbus_interfaces()
\section1 Description
Generates C++ sources implementing D-Bus interfaces defined in \c{dbus_spec1},
\c{dbus_spec2}, where each argument needs to be the path to a valid D-Bus
interface description file. The paths of the generated files are added to
\c{<VAR>}.
For each argument, a call to the \l{Qt D-Bus XML compiler (qdbusxml2cpp)}
in interface (proxy) mode is set up.
The generated C++ source files are named after the XML file: For the file
\c{org.example.chat.xml} the generated header will be named
\c{orgexamplechatinterface.h}.
\section1 Options
Options can be set using \c set_source_files_properties on each of the file
arguments:
\table
\header
\li Option
\li Value
\li Description
\row
\li \c CLASSNAME
\li \c class_name
\li Override the default interface class name with \c{class_name}.
\row
\li \c NO_NAMESPACE
\li boolean
\li Do not generate the namespaced name if set to \c{ON}.
\row
\li \c INCLUDE
\li \c path
\li Add an \c{#include "path"} in the generated code.
\endtable
*/
/*!
\page qtdbus-cmake-qt-generate-dbus-interface.html
\ingroup cmake-commands-qtdbus
\title qt_generate_dbus_interface
\keyword qt6_generate_dbus_interface
\summary {Generates a D-Bus interface from a header file.}
\include cmake-find-package-dbus.qdocinc
\cmakecommandsince 6.0
\section1 Synopsis
\badcode
qt_generate_dbus_interface(header
[customName]
[OPTIONS options]
)
\endcode
\versionlessCMakeCommandsNote qt6_generate_dbus_interface()
\section1 Description
Parses the C++ source or header file containing a QObject-derived class
declaration and generates a file containing the D-BUS Introspection XML.
By default, the generated XML file is stored in the current binary directory,
and has the same base name as the header. You can specify a different name or
path by adding \c{customName} as an optional second argument.
\section1 Options
The function sets up a call to the \c{qdbuscpp2xml} command line tool. Further
arguments to the tool can be set after \c{OPTIONS}.
*/
/*!
\page qtdbus-cmake-qt-add-dbus-adaptor.html
\ingroup cmake-commands-qtdbus
\title qt_add_dbus_adaptor
\keyword qt6_add_dbus_adaptor
\summary {Generates an adaptor class for a D-Bus interface.}
\include cmake-find-package-dbus.qdocinc
\cmakecommandsince 6.0
\section1 Synopsis
\badcode
qt_add_dbus_adaptor(<VAR> dbus_spec header
[parent_class]
[basename]
[classname]
)
\endcode
\versionlessCMakeCommandsNote qt6_add_dbus_adaptor()
\section1 Description
Generates a C++ header file implementing an adaptor for a D-Bus interface
description file defined in \c{dbus_spec}. The path of the generated file is
added to \c{<VAR>}. The generated adaptor class takes a pointer to
\c{parent_class} as QObject parent. \c{parent_class} should be declared in
\c{header}, which is included in the generated code as \c{#include "header"}.
The function sets up a call to the \l{Qt D-Bus XML compiler (qdbusxml2cpp)}
in adaptor mode. The default file and class name are generated from the last
segment in the \c{dbus_spec} base name:
\table
\header
\li XML file
\li Header file
\li Class name
\row
\li \c{org.example.chat}
\li \c{chatadaptor.h}
\li \c{ChatAdaptor}
\endtable
You can change the name of the header file to be generated by passing
\c{basename} as the fifth argument. The \c{.h} suffix is always added.
You can change the default class name by passing \c{classname} as the sixth
argument.
\section1 Examples
\snippet cmake/examples.cmake qt_add_dbus_adaptor
*/
/*!
\group cmake-source-file-properties-qtdbus
\title CMake Source File Properties in Qt6 DBus
\brief Lists CMake file properties used in Qt6::DBus.
\l{CMake Commands in Qt6 DBus}{CMake Commands} know about the following CMake
source file properties:
\sa{CMake Property Reference}
*/
/*!
\page cmake-source-file-property-classname.html
\ingroup cmake-source-file-properties-qtdbus
\title CLASSNAME
\target cmake-source-file-property-CLASSNAME
\summary {Overrides the default interface class name.}
\cmakepropertysince 5.0
When this property is set, the generated C++ class name is overridden
with the provided property value.
\sa{qt6_add_dbus_interface}{qt_add_dbus_interface}
*/
/*!
\page cmake-source-file-property-include.html
\ingroup cmake-source-file-properties-qtdbus
\title INCLUDE
\target cmake-source-file-property-INCLUDE
\summary {Adds an include path.}
\cmakepropertysince 5.0
When this property is set, an #include "path" is added
to the generated C++ file.
\sa{qt6_add_dbus_interface}{qt_add_dbus_interface}
*/
/*!
\page cmake-source-file-property-no-namespace.html
\ingroup cmake-source-file-properties-qtdbus
\title NO_NAMESPACE
\target cmake-source-file-property-NO_NAMESPACE
\summary {Disables generation of a namespaced name.}
\cmakepropertysince 5.0
When this property is set, the generated C++ class will not contain a namespaced alias.
\sa{qt6_add_dbus_interface}{qt_add_dbus_interface}
*/

View File

@ -0,0 +1,14 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\group examples-dbus
\title Qt D-Bus Examples
\brief Using D-Bus from Qt applications.
\ingroup all-examples
\l{Qt D-Bus} allows applications to send messages to each other using
D-Bus. This page lists examples which specifically use D-Bus for
inter-process communication (IPC).
*/

View File

@ -0,0 +1,96 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtdbus-index.html
\title Qt D-Bus
\brief An introduction to Inter-Process Communication and Remote Procedure Calling with D-Bus.
\keyword QtDBus
D-Bus is an Inter-Process Communication (IPC) and Remote Procedure
Calling (RPC) mechanism originally developed for Linux to replace
existing and competing IPC solutions with one unified protocol. It
was also designed to allow communication between system-level
processes (such as printer and hardware driver services) and
normal user processes.
It uses a fast, binary message-passing protocol, which is suitable
for same-machine communication due to its low latency and low
overhead. Its specification is currently defined by the
\tt{freedesktop.org} project and is available to all parties.
Communication, in general, happens through a central server
application called the "bus" (hence the name), but direct
application-to-application communication is also possible. When
communicating on a bus, applications can query which other
applications and services are available, as well as activate one
on demand.
\section1 Using the Module
\include {module-use.qdocinc} {using the c++ api}
\include {module-use.qdocinc} {building with cmake} {DBus}
\section1 Articles and Guides
The following documents contain information about Qt's D-Bus integration
features and provide details about the mechanisms used to send and receive
type information over the bus:
\list
\li \l {Qt D-Bus Overview}
\li \l {Using Qt D-Bus Adaptors}
\li \l {The Qt D-Bus Type System}
\li \l {Qt D-Bus XML compiler (qdbusxml2cpp)}
\li \l{D-Bus Viewer}
\endlist
\section1 Examples
\list
\li \l{Qt D-Bus Examples}
\endlist
\section1 Reference
\list
\li \l{Qt D-Bus C++ Classes}
\li \l{CMake Commands in Qt6 DBus}
\endlist
\section1 Module Evolution
\l{Changes to Qt D-Bus} lists important changes in the module API
and functionality that were made for the Qt 6 series of Qt.
\section1 Licenses and Attributions
The Qt D-Bus module is available under commercial licenses from \l{The Qt Company}.
In addition, it is available under free software licenses:
The \l{GNU Lesser General Public License, version 3}, or
the \l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
Furthermore, Qt D-Bus in Qt \QtVersion may contain third party
modules under the following permissive licenses:
\generatelist{groupsbymodule attributions-qtdbus}
*/
/*!
\page qdbusviewer.html
\title D-Bus Viewer
\keyword qdbusviewer
The Qt D-Bus Viewer is a tool that lets you introspect D-Bus objects and messages. You can
choose between the system bus and the session bus. Click on any service on the list
on the left side to see all the exported objects.
You can invoke methods by double-clicking on them. If a method takes one or more IN parameters,
a property editor opens.
Right-click on a signal to connect to it. All emitted signals including their parameters
are output in the message view on the lower side of the window.
*/

View File

@ -0,0 +1,23 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtDBus
\title Qt D-Bus C++ Classes
\brief The Qt D-Bus module is a Unix-only library that you can use
to perform Inter-Process Communication using the \l{Qt D-Bus}{D-Bus} protocol.
\ingroup modules
\qtcmakepackage DBus
\qtvariable dbus
\keyword The QDBus compiler
Applications using the Qt D-Bus module can provide services to
other, remote applications by exporting objects, as well as use
services exported by those applications by placing calls and
accessing properties.
The \l{Qt D-Bus} page contains information about how to use the module.
*/

View File

@ -0,0 +1,175 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtdbus-overview.html
\title Qt D-Bus Overview
\brief Provides insight into the Qt Qt D-Bus module.
D-Bus is an Inter-Process Communication (IPC) and Remote Procedure
Calling (RPC) mechanism originally developed for Linux to replace
existing and competing IPC solutions with one unified protocol. It
was also designed to allow communication between system-level
processes (such as printer and hardware driver services) and
normal user processes.
It uses a fast, binary message-passing protocol, which is suitable
for same-machine communication due to its low latency and low
overhead. Its specification is currently defined by the
\tt{freedesktop.org} project and is available to all parties.
Communication, in general, happens through a central server
application called the "bus" (hence the name), but direct
application-to-application communication is also possible. When
communicating on a bus, applications can query which other
applications and services are available, as well as activate one
on demand.
\section1 The Buses
D-Bus buses are used when many-to-many communication is
desired. In order to achieve that, a central server is launched
before any application can connect to the bus. This server is
responsible for keeping track of the applications that are
connected and for properly routing messages from their source to
their destination.
In addition, D-Bus defines two well-known buses, called the
system bus and the session bus. These buses are special in the
sense that they have well-defined semantics: some services are
defined to be found in one or both of these buses.
For example, an application wishing to query the list of hardware
devices attached to the computer will probably communicate to a
service available on the system bus, while the service providing
opening of the user's web browser will probably be found on the
session bus.
On the system bus, you can also expect to find restrictions on
what services each application is allowed to offer. Therefore, you
can be reasonably certain that if a certain service is present,
it's being offered by a trusted application.
\section1 Concepts
\section2 Messages
On the low level, applications communicate over D-Bus by sending
messages to one another. Messages are used to relay the remote
procedure calls as well as the replies and errors associated
with them. When used over a bus, messages have a destination,
which means they are routed only to the interested parties,
avoiding congestion due to "swarming" or broadcasting.
A special kind of message called a "signal message"
(a concept based on Qt's \l {Signals and Slots} mechanism),
however, does not have a pre-defined destination. Since its
purpose is to be used in a one-to-many context, signal messages
are designed to work over an "opt-in" mechanism.
The Qt D-Bus module fully encapsulates the low-level concept of
messages into a simpler, object-oriented approach familiar to Qt
developers. In most cases, the developer need not worry about
sending or receiving messages.
\section2 Service Names
When communicating over a bus, applications obtain what is
called a "service name": it is how that application chooses to be
known by other applications on the same bus. The service names
are brokered by the D-Bus bus daemon and are used to
route messages from one application to another. An analogous
concept to service names are IP addresses and hostnames: a
computer normally has one IP address and may have one or more
hostnames associated with it, according to the services that it
provides to the network.
On the other hand, if a bus is not used, service names are also
not used. If we compare this to a computer network again, this
would equate to a point-to-point network: since the peer is
known, there is no need to use hostnames to find it or its IP
address.
The format of a D-Bus service name is in fact very similar to a
host name: it is a dot-separated sequence of letters and
digits. The common practice is even to name your service name
according to the domain name of the organization that defined
that service.
For example, the D-Bus service is defined by
\tt{freedesktop.org} and can be found on the bus under the
service name:
\snippet code/doc_src_introtodbus.qdoc 0
\section2 Object Paths
Like network hosts, applications provide specific services to
other applications by exporting objects. Those objects are
hierarchically organized, much like the parent-child
relationship that classes derived from QObject possess. One
difference, however, is that there is the concept of "root
object", which all objects have as the ultimate parent.
If we continue our analogy with Web services, object paths
equate to the path part of a URL:
\image qurl-ftppath.png
Like them, object paths in D-Bus are formed resembling path
names on the filesystem: they are slash-separated labels, each
consisting of letters, digits and the underscore character
("\_"). They must always start with a slash and must not end with
one.
\section2 Interfaces
Interfaces are similar to C++ abstract classes and Java's
\c interface keyword and declare the "contract" that is
established between caller and callee. That is, they establish
the names of the methods, signals, and properties that are
available as well as the behavior that is expected from either
side when communication is established.
Qt uses a very similar mechanism in its \l {How to Create Qt
Plugins}{Plugin system}: Base classes in C++ are associated
with a unique identifier by way of the Q_DECLARE_INTERFACE()
macro.
D-Bus interface names are, in fact, named in a manner similar to
what is suggested by the Qt Plugin System: an identifier usually
constructed from the domain name of the entity that defined that
interface.
\section2 Cheat Sheet
To facilitate remembering of the naming formats and their
purposes, the following table can be used:
\table 90%
\header \li D-Bus Concept \li Analogy \li Name format
\row \li Service name \li Network hostnames \li Dot-separated
("looks like a hostname")
\row \li Object path \li URL path component \li Slash-separated
("looks like a path")
\row \li Interface \li Plugin identifier \li Dot-separated
\endtable
\section1 Debugging
When developing applications that use D-Bus, it is sometimes useful to be able
to see information about the messages that are sent and received across the
bus by each application.
This feature can be enabled on a per-application basis by setting the
\c QDBUS_DEBUG environment variable before running each application.
For example, we can enable debugging only for the car in the
\l{D-Bus Remote Controlled Car} example by running the controller and the
car in the following way:
\snippet code/doc_src_introtodbus.qdoc QDBUS_DEBUG
Information about the messages will be written to the console the application
was launched from.
*/

137
src/dbus/qdbus_symbols.cpp Normal file
View File

@ -0,0 +1,137 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qglobal.h>
#if QT_CONFIG(library)
#include <QtCore/qlibrary.h>
#include <QtCore/private/qlocking_p.h>
#endif
#include <QtCore/qmutex.h>
#ifndef QT_NO_DBUS
extern "C" void dbus_shutdown();
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
void (*qdbus_resolve_me(const char *name))();
#if !defined QT_LINKED_LIBDBUS
#if QT_CONFIG(library)
Q_CONSTINIT static QLibrary *qdbus_libdbus = nullptr;
void qdbus_unloadLibDBus()
{
if (qdbus_libdbus) {
if (qEnvironmentVariableIsSet("QDBUS_FORCE_SHUTDOWN"))
qdbus_libdbus->resolve("dbus_shutdown")();
qdbus_libdbus->unload();
}
delete qdbus_libdbus;
qdbus_libdbus = nullptr;
}
#endif
bool qdbus_loadLibDBus()
{
#if QT_CONFIG(library)
#ifdef QT_BUILD_INTERNAL
// this is to simulate a library load failure for our autotest suite.
if (!qEnvironmentVariableIsEmpty("QT_SIMULATE_DBUS_LIBFAIL"))
return false;
#endif
Q_CONSTINIT static bool triedToLoadLibrary = false;
Q_CONSTINIT static QBasicMutex mutex;
const auto locker = qt_scoped_lock(mutex);
QLibrary *&lib = qdbus_libdbus;
if (triedToLoadLibrary)
return lib && lib->isLoaded();
lib = new QLibrary;
lib->setLoadHints(QLibrary::ExportExternalSymbolsHint); // make libdbus symbols available for apps that need more advanced control over the dbus
triedToLoadLibrary = true;
static int majorversions[] = { 3, 2, -1 };
const QString baseNames[] = {
#ifdef Q_OS_WIN
"dbus-1"_L1,
#endif
"libdbus-1"_L1
};
lib->unload();
for (const int majorversion : majorversions) {
for (const QString &baseName : baseNames) {
#ifdef Q_OS_WIN
QString suffix;
if (majorversion != -1)
suffix = QString::number(- majorversion); // negative so it prepends the dash
lib->setFileName(baseName + suffix);
#else
lib->setFileNameAndVersion(baseName, majorversion);
#endif
if (lib->load() && lib->resolve("dbus_connection_open_private"))
return true;
lib->unload();
}
}
delete lib;
lib = nullptr;
return false;
#else
return true;
#endif
}
void (*qdbus_resolve_conditionally(const char *name))()
{
#if QT_CONFIG(library)
if (qdbus_loadLibDBus())
return qdbus_libdbus->resolve(name);
#else
Q_UNUSED(name);
#endif
return nullptr;
}
void (*qdbus_resolve_me(const char *name))()
{
#if QT_CONFIG(library)
if (Q_UNLIKELY(!qdbus_loadLibDBus()))
qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name);
QFunctionPointer ptr = qdbus_libdbus->resolve(name);
if (Q_UNLIKELY(!ptr))
qFatal("Cannot resolve '%s' in your libdbus-1.", name);
return ptr;
#else
Q_UNUSED(name);
return nullptr;
#endif
}
#else
static void qdbus_unloadLibDBus()
{
if (qEnvironmentVariableIsSet("QDBUS_FORCE_SHUTDOWN"))
dbus_shutdown();
}
#endif // !QT_LINKED_LIBDBUS
#if defined(QT_LINKED_LIBDBUS) || QT_CONFIG(library)
Q_DESTRUCTOR_FUNCTION(qdbus_unloadLibDBus)
#endif
QT_END_NAMESPACE
#endif // QT_NO_DBUS

472
src/dbus/qdbus_symbols_p.h Normal file
View File

@ -0,0 +1,472 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUS_SYMBOLS_P_H
#define QDBUS_SYMBOLS_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#ifndef QT_NO_DBUS
#ifdef QT_LINKED_LIBDBUS
# include <dbus/dbus.h>
#else
# include "dbus_minimal_p.h"
#endif
#ifdef interface
# undef interface
#endif
QT_BEGIN_NAMESPACE
#if !defined QT_LINKED_LIBDBUS
void (*qdbus_resolve_conditionally(const char *name))(); // doesn't print a warning
void (*qdbus_resolve_me(const char *name))(); // prints a warning
bool qdbus_loadLibDBus();
//# define TRACE_DBUS_CALLS
# ifdef TRACE_DBUS_CALLS
namespace QtDBusCallTracing {
struct TraceDBusCall
{
struct ThreadData {
TraceDBusCall *ptr;
int level;
bool finishedPrinted;
};
static inline ThreadData &td()
{
Q_CONSTINIT static thread_local ThreadData value;
return value;
}
ThreadData savedData;
QDebug s;
TraceDBusCall(QDebug s, const char *fname)
: savedData(td()), s(s.nospace() << QByteArray(savedData.level * 3, ' ').constData() << fname)
{
if (savedData.ptr && !savedData.finishedPrinted) {
savedData.ptr->s << " ...unfinished";
savedData.ptr->s = qDebug().nospace() << QByteArray(savedData.level * 3 - 3, ' ').constData();
savedData.finishedPrinted = true;
}
ThreadData &data = td();
data.ptr = this;
data.level++;
data.finishedPrinted = false;
}
~TraceDBusCall()
{
td() = savedData;
}
void operator()() { s << ")"; }
template <typename... Args> void operator()(const char *arg1, Args &&... args)
{
s << '"' << arg1 << '"';
if (sizeof...(args))
s << ", ";
operator()(args...);
}
template <typename Arg1, typename... Args> void operator()(Arg1 &&arg1, Args &&... args)
{
s << arg1;
if (sizeof...(args))
s << ", ";
operator()(args...);
}
};
template <typename T> T operator,(TraceDBusCall &&tc, T &&ret)
{
tc.s << " = " << ret;
return ret;
}
inline const char *operator,(TraceDBusCall &&tc, const char *ret)
{
tc.s << " = \"" << ret << '"';
return ret;
}
template <typename T> struct TraceReturn { typedef TraceDBusCall Type; };
template <> struct TraceReturn<void> { typedef void Type; };
}
# define DEBUGCALL(name, argcall) QtDBusCallTracing::TraceDBusCall tc(qDebug(), name "("); tc argcall
# define DEBUGRET(ret) (QtDBusCallTracing::TraceReturn<ret>::Type) tc ,
# else
# define DEBUGCALL(name, argcall)
# define DEBUGRET(ret)
# endif
# define DEFINEFUNC(ret, func, args, argcall, funcret) \
typedef ret (* _q_PTR_##func) args; \
static inline ret q_##func args \
{ \
static _q_PTR_##func ptr; \
DEBUGCALL(#func, argcall); \
if (!ptr) \
ptr = (_q_PTR_##func) qdbus_resolve_me(#func); \
funcret DEBUGRET(ret) ptr argcall; \
}
# define DEFINEFUNC_CONDITIONALLY(ret, func, args, argcall, funcret, failret) \
typedef ret (* _q_PTR_##func) args; \
static inline ret q_##func args \
{ \
static _q_PTR_##func ptr; \
DEBUGCALL(#func, argcall); \
if (!ptr) \
ptr = (_q_PTR_##func) qdbus_resolve_conditionally(#func); \
if (!ptr) \
failret; \
funcret DEBUGRET(ret) ptr argcall; \
}
#else // defined QT_LINKED_LIBDBUS
inline bool qdbus_loadLibDBus() { return true; }
# define DEFINEFUNC(ret, func, args, argcall, funcret) \
static inline ret q_##func args { funcret func argcall; }
#endif // defined QT_LINKED_LIBDBUS
/* dbus-bus.h */
DEFINEFUNC(void, dbus_bus_add_match, (DBusConnection *connection,
const char *rule,
DBusError *error),
(connection, rule, error), )
DEFINEFUNC(void, dbus_bus_remove_match, (DBusConnection *connection,
const char *rule,
DBusError *error),
(connection, rule, error), )
DEFINEFUNC(dbus_bool_t, dbus_bus_register,(DBusConnection *connection,
DBusError *error),
(connection, error), return)
DEFINEFUNC(DBusConnection *, dbus_bus_get_private, (DBusBusType type,
DBusError *error),
(type, error), return)
DEFINEFUNC(const char*, dbus_bus_get_unique_name, (DBusConnection *connection),
(connection), return)
/* dbus-connection.h */
DEFINEFUNC(dbus_bool_t , dbus_connection_add_filter, (DBusConnection *connection,
DBusHandleMessageFunction function,
void *user_data,
DBusFreeFunction free_data_function),
(connection, function, user_data, free_data_function), return)
DEFINEFUNC(void , dbus_connection_close, (DBusConnection *connection),
(connection), return)
DEFINEFUNC(DBusDispatchStatus , dbus_connection_dispatch, (DBusConnection *connection),
(connection), return)
DEFINEFUNC(DBusDispatchStatus , dbus_connection_get_dispatch_status, (DBusConnection *connection),
(connection), return)
DEFINEFUNC(dbus_bool_t, dbus_connection_get_is_authenticated, (DBusConnection * connection),
(connection), return )
DEFINEFUNC(dbus_bool_t , dbus_connection_get_is_connected, (DBusConnection *connection),
(connection), return)
DEFINEFUNC(DBusConnection* , dbus_connection_open_private, (const char *address,
DBusError *error),
(address, error), return)
DEFINEFUNC(DBusConnection* , dbus_connection_ref, (DBusConnection *connection),
(connection), return)
DEFINEFUNC(dbus_bool_t , dbus_connection_send, (DBusConnection *connection,
DBusMessage *message,
dbus_uint32_t *client_serial),
(connection, message, client_serial), return)
DEFINEFUNC(dbus_bool_t , dbus_connection_send_with_reply, (DBusConnection *connection,
DBusMessage *message,
DBusPendingCall **pending_return,
int timeout_milliseconds),
(connection, message, pending_return, timeout_milliseconds), return)
DEFINEFUNC(void , dbus_connection_set_exit_on_disconnect, (DBusConnection *connection,
dbus_bool_t exit_on_disconnect),
(connection, exit_on_disconnect), )
DEFINEFUNC(dbus_bool_t , dbus_connection_set_timeout_functions, (DBusConnection *connection,
DBusAddTimeoutFunction add_function,
DBusRemoveTimeoutFunction remove_function,
DBusTimeoutToggledFunction toggled_function,
void *data,
DBusFreeFunction free_data_function),
(connection, add_function, remove_function, toggled_function, data, free_data_function), return)
DEFINEFUNC(dbus_bool_t , dbus_connection_set_watch_functions, (DBusConnection *connection,
DBusAddWatchFunction add_function,
DBusRemoveWatchFunction remove_function,
DBusWatchToggledFunction toggled_function,
void *data,
DBusFreeFunction free_data_function),
(connection, add_function, remove_function, toggled_function, data, free_data_function), return)
DEFINEFUNC(void , dbus_connection_set_wakeup_main_function, (DBusConnection *connection,
DBusWakeupMainFunction wakeup_main_function,
void *data,
DBusFreeFunction free_data_function),
(connection, wakeup_main_function, data, free_data_function), )
DEFINEFUNC(void , dbus_connection_set_dispatch_status_function, (DBusConnection *connection,
DBusDispatchStatusFunction function,
void *data,
DBusFreeFunction free_data_function),
(connection, function, data, free_data_function), )
DEFINEFUNC(void , dbus_connection_unref, (DBusConnection *connection),
(connection), )
DEFINEFUNC(dbus_bool_t , dbus_timeout_get_enabled, (DBusTimeout *timeout),
(timeout), return)
DEFINEFUNC(int , dbus_timeout_get_interval, (DBusTimeout *timeout),
(timeout), return)
DEFINEFUNC(dbus_bool_t , dbus_timeout_handle, (DBusTimeout *timeout),
(timeout), return)
DEFINEFUNC(dbus_bool_t , dbus_watch_get_enabled, (DBusWatch *watch),
(watch), return)
DEFINEFUNC(int , dbus_watch_get_unix_fd, (DBusWatch *watch),
(watch), return)
DEFINEFUNC(unsigned int , dbus_watch_get_flags, (DBusWatch *watch),
(watch), return)
DEFINEFUNC(dbus_bool_t , dbus_watch_handle, (DBusWatch *watch,
unsigned int flags),
(watch, flags), return)
DEFINEFUNC(void , dbus_connection_set_allow_anonymous, (DBusConnection *connection,
dbus_bool_t value),
(connection, value), return)
/* dbus-errors.h */
DEFINEFUNC(void , dbus_error_free, (DBusError *error),
(error), )
DEFINEFUNC(void , dbus_error_init, (DBusError *error),
(error), )
DEFINEFUNC(dbus_bool_t , dbus_error_is_set, (const DBusError *error),
(error), return)
/* dbus-memory.h */
DEFINEFUNC(void , dbus_free, (void *memory), (memory), )
/* dbus-message.h */
DEFINEFUNC(DBusMessage* , dbus_message_copy, (const DBusMessage *message),
(message), return)
DEFINEFUNC(dbus_bool_t , dbus_message_get_auto_start, (DBusMessage *message),
(message), return)
DEFINEFUNC(const char* , dbus_message_get_error_name, (DBusMessage *message),
(message), return)
DEFINEFUNC(const char* , dbus_message_get_interface, (DBusMessage *message),
(message), return)
DEFINEFUNC(const char* , dbus_message_get_member, (DBusMessage *message),
(message), return)
DEFINEFUNC(dbus_bool_t , dbus_message_get_no_reply, (DBusMessage *message),
(message), return)
DEFINEFUNC(const char* , dbus_message_get_path, (DBusMessage *message),
(message), return)
DEFINEFUNC(const char* , dbus_message_get_sender, (DBusMessage *message),
(message), return)
DEFINEFUNC(dbus_uint32_t , dbus_message_get_serial, (DBusMessage *message),
(message), return)
DEFINEFUNC(const char* , dbus_message_get_signature, (DBusMessage *message),
(message), return)
DEFINEFUNC(int , dbus_message_get_type, (DBusMessage *message),
(message), return)
#if !defined QT_LINKED_LIBDBUS
DEFINEFUNC_CONDITIONALLY(dbus_bool_t , dbus_message_get_allow_interactive_authorization, (DBusMessage *message),
(message), return, return false)
#else // defined QT_LINKED_LIBDBUS
static inline dbus_bool_t q_dbus_message_get_allow_interactive_authorization(DBusMessage *message)
{
#ifdef DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION
return dbus_message_get_allow_interactive_authorization(message);
#else
Q_UNUSED(message);
return false;
#endif
}
#endif // defined QT_LINKED_LIBDBUS
DEFINEFUNC(dbus_bool_t , dbus_message_iter_append_basic, (DBusMessageIter *iter,
int type,
const void *value),
(iter, type, value), return)
DEFINEFUNC(dbus_bool_t , dbus_message_iter_append_fixed_array, (DBusMessageIter *iter,
int element_type,
const void *value,
int n_elements),
(iter, element_type, value, n_elements), return)
DEFINEFUNC(dbus_bool_t , dbus_message_iter_close_container, (DBusMessageIter *iter,
DBusMessageIter *sub),
(iter, sub), return)
DEFINEFUNC(int , dbus_message_iter_get_arg_type, (DBusMessageIter *iter),
(iter), return)
DEFINEFUNC(void , dbus_message_iter_get_basic, (DBusMessageIter *iter,
void *value),
(iter, value), )
DEFINEFUNC(int , dbus_message_iter_get_element_type, (DBusMessageIter *iter),
(iter), return)
DEFINEFUNC(void , dbus_message_iter_get_fixed_array, (DBusMessageIter *iter,
void *value,
int *n_elements),
(iter, value, n_elements), return)
DEFINEFUNC(char* , dbus_message_iter_get_signature, (DBusMessageIter *iter),
(iter), return)
DEFINEFUNC(dbus_bool_t , dbus_message_iter_init, (DBusMessage *message,
DBusMessageIter *iter),
(message, iter), return)
DEFINEFUNC(void , dbus_message_iter_init_append, (DBusMessage *message,
DBusMessageIter *iter),
(message, iter), return)
DEFINEFUNC(dbus_bool_t , dbus_message_iter_next, (DBusMessageIter *iter),
(iter), return)
DEFINEFUNC(dbus_bool_t , dbus_message_iter_open_container, (DBusMessageIter *iter,
int type,
const char *contained_signature,
DBusMessageIter *sub),
(iter, type, contained_signature, sub), return)
DEFINEFUNC(void , dbus_message_iter_recurse, (DBusMessageIter *iter,
DBusMessageIter *sub),
(iter, sub), )
DEFINEFUNC(DBusMessage* , dbus_message_new, (int message_type),
(message_type), return)
DEFINEFUNC(DBusMessage* , dbus_message_new_method_call, (const char *bus_name,
const char *path,
const char *interface,
const char *method),
(bus_name, path, interface, method), return)
DEFINEFUNC(DBusMessage* , dbus_message_new_signal, (const char *path,
const char *interface,
const char *name),
(path, interface, name), return)
DEFINEFUNC(DBusMessage* , dbus_message_ref, (DBusMessage *message),
(message), return)
DEFINEFUNC(void , dbus_message_set_auto_start, (DBusMessage *message,
dbus_bool_t auto_start),
(message, auto_start), return)
DEFINEFUNC(dbus_bool_t , dbus_message_set_destination, (DBusMessage *message,
const char *destination),
(message, destination), return)
DEFINEFUNC(dbus_bool_t , dbus_message_set_error_name, (DBusMessage *message,
const char *name),
(message, name), return)
DEFINEFUNC(void , dbus_message_set_no_reply, (DBusMessage *message,
dbus_bool_t no_reply),
(message, no_reply), return)
DEFINEFUNC(dbus_bool_t , dbus_message_set_path, (DBusMessage *message,
const char *object_path),
(message, object_path), return)
DEFINEFUNC(dbus_bool_t , dbus_message_set_reply_serial, (DBusMessage *message,
dbus_uint32_t reply_serial),
(message, reply_serial), return)
DEFINEFUNC(dbus_bool_t , dbus_message_set_sender, (DBusMessage *message,
const char *sender),
(message, sender), return)
DEFINEFUNC(void , dbus_message_unref, (DBusMessage *message),
(message), )
#if !defined QT_LINKED_LIBDBUS
DEFINEFUNC_CONDITIONALLY(void, dbus_message_set_allow_interactive_authorization,
(DBusMessage *message, dbus_bool_t allow), (message, allow), return, return)
#else // defined QT_LINKED_LIBDBUS
static inline void q_dbus_message_set_allow_interactive_authorization(DBusMessage *message, dbus_bool_t allow)
{
#ifdef DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION
dbus_message_set_allow_interactive_authorization(message, allow);
#else
Q_UNUSED(message);
Q_UNUSED(allow);
#endif
}
#endif // defined QT_LINKED_LIBDBUS
/* dbus-misc.h */
DEFINEFUNC(char* , dbus_get_local_machine_id , (void), (), return)
DEFINEFUNC(void , dbus_get_version , (int *major_version, int *minor_version, int *micro_version)
, (major_version, minor_version, micro_version)
, return)
/* dbus-pending-call.h */
DEFINEFUNC(dbus_bool_t , dbus_pending_call_set_notify, (DBusPendingCall *pending,
DBusPendingCallNotifyFunction function,
void *user_data,
DBusFreeFunction free_user_data),
(pending, function, user_data, free_user_data), return)
DEFINEFUNC(void , dbus_pending_call_block, (DBusPendingCall *pending),
(pending), )
DEFINEFUNC(void , dbus_pending_call_cancel, (DBusPendingCall *pending),
(pending), )
DEFINEFUNC(dbus_bool_t , dbus_pending_call_get_completed, (DBusPendingCall *pending),
(pending), return)
DEFINEFUNC(DBusMessage* , dbus_pending_call_steal_reply, (DBusPendingCall *pending),
(pending), return)
DEFINEFUNC(void , dbus_pending_call_unref, (DBusPendingCall *pending),
(pending), return)
/* dbus-server.h */
DEFINEFUNC(dbus_bool_t , dbus_server_allocate_data_slot, (dbus_int32_t *slot_p),
(slot_p), return)
DEFINEFUNC(void , dbus_server_free_data_slot, (dbus_int32_t *slot_p),
(slot_p), return)
DEFINEFUNC(void , dbus_server_disconnect, (DBusServer *server),
(server), )
DEFINEFUNC(char* , dbus_server_get_address, (DBusServer *server),
(server), return)
DEFINEFUNC(dbus_bool_t , dbus_server_get_is_connected, (DBusServer *server),
(server), return)
DEFINEFUNC(DBusServer* , dbus_server_listen, (const char *address,
DBusError *error),
(address, error), return)
DEFINEFUNC(dbus_bool_t , dbus_server_set_data, (DBusServer *server,
int slot,
void *data,
DBusFreeFunction free_data_func),
(server, slot, data, free_data_func), return)
DEFINEFUNC(void , dbus_server_set_new_connection_function, (DBusServer *server,
DBusNewConnectionFunction function,
void *data,
DBusFreeFunction free_data_function),
(server, function, data, free_data_function), )
DEFINEFUNC(dbus_bool_t , dbus_server_set_timeout_functions, (DBusServer *server,
DBusAddTimeoutFunction add_function,
DBusRemoveTimeoutFunction remove_function,
DBusTimeoutToggledFunction toggled_function,
void *data,
DBusFreeFunction free_data_function),
(server, add_function, remove_function, toggled_function, data, free_data_function), return)
DEFINEFUNC(dbus_bool_t , dbus_server_set_watch_functions, (DBusServer *server,
DBusAddWatchFunction add_function,
DBusRemoveWatchFunction remove_function,
DBusWatchToggledFunction toggled_function,
void *data,
DBusFreeFunction free_data_function),
(server, add_function, remove_function, toggled_function, data, free_data_function), return)
DEFINEFUNC(void , dbus_server_unref, (DBusServer *server),
(server), )
/* dbus-thread.h */
DEFINEFUNC(dbus_bool_t , dbus_threads_init_default, (), (), return)
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif // QDBUS_SYMBOLS_P_H

View File

@ -0,0 +1,305 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusabstractadaptor.h"
#include "qdbusabstractadaptor_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qset.h>
#include <QtCore/qtimer.h>
#include <QtCore/qthread.h>
#include "qdbusconnection.h"
#include "qdbusconnection_p.h" // for qDBusParametersForMethod
#include "qdbusmetatype_p.h"
#include <algorithm>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
static int cachedRelaySlotMethodIndex = 0;
int QDBusAdaptorConnector::relaySlotMethodIndex()
{
if (cachedRelaySlotMethodIndex == 0) {
cachedRelaySlotMethodIndex = staticMetaObject.indexOfMethod("relaySlot()");
Q_ASSERT(cachedRelaySlotMethodIndex != 0); // 0 should be deleteLater() or destroyed()
}
return cachedRelaySlotMethodIndex;
}
QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
{
if (!obj)
return nullptr;
const QObjectList &children = obj->children();
QObjectList::ConstIterator it = children.constBegin();
QObjectList::ConstIterator end = children.constEnd();
for ( ; it != end; ++it) {
QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(*it);
if (connector) {
connector->polish();
return connector;
}
}
return nullptr;
}
QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
{
return qDBusFindAdaptorConnector(adaptor->parent());
}
QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
{
QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
if (connector)
return connector;
return new QDBusAdaptorConnector(obj);
}
QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
{
return adaptor->d_func()->xml;
}
void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
const QString &xml)
{
adaptor->d_func()->xml = xml;
}
/*!
\class QDBusAbstractAdaptor
\inmodule QtDBus
\since 4.2
\brief The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
The QDBusAbstractAdaptor class is the starting point for all objects intending to provide
interfaces to the external world using D-Bus. This is accomplished by attaching a one or more
classes derived from QDBusAbstractAdaptor to a normal QObject and then registering that QObject
with QDBusConnection::registerObject. QDBusAbstractAdaptor objects are intended to be
light-weight wrappers, mostly just relaying calls into the real object (its parent) and the
signals from it.
Each QDBusAbstractAdaptor-derived class should define the D-Bus interface it is implementing
using the Q_CLASSINFO macro in the class definition. Note that only one interface can be
exposed in this way.
QDBusAbstractAdaptor uses the standard QObject mechanism of signals, slots and properties to
determine what signals, methods and properties to export to the bus. Any signal emitted by
QDBusAbstractAdaptor-derived classes will be automatically be relayed through any D-Bus
connections the object is registered on.
Classes derived from QDBusAbstractAdaptor must be created on the heap using the \a new operator
and must not be deleted by the user (they will be deleted automatically when the object they are
connected to is also deleted).
\sa {usingadaptors.html}{Using adaptors}, QDBusConnection
*/
/*!
Constructs a QDBusAbstractAdaptor with \a obj as the parent object.
*/
QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
: QObject(*new QDBusAbstractAdaptorPrivate, obj)
{
QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
connector->waitingForPolish = true;
QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
}
/*!
Destroys the adaptor.
\warning Adaptors are destroyed automatically when the real object they refer to is
destroyed. Do not delete the adaptors yourself.
*/
QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
{
}
/*!
Toggles automatic signal relaying from the real object (see object()).
Automatic signal relaying consists of signal-to-signal connection of the signals on the parent
that have the exact same method signature in both classes.
If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
*/
void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
{
const QMetaObject *us = metaObject();
const QMetaObject *them = parent()->metaObject();
bool connected = false;
for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) {
QMetaMethod mm = us->method(idx);
if (mm.methodType() != QMetaMethod::Signal)
continue;
// try to connect/disconnect to a signal on the parent that has the same method signature
QByteArray sig = QMetaObject::normalizedSignature(mm.methodSignature().constData());
if (them->indexOfSignal(sig) == -1)
continue;
sig.prepend(QSIGNAL_CODE + '0');
parent()->disconnect(sig, this, sig);
if (enable)
connected = connect(parent(), sig, sig) || connected;
}
d_func()->autoRelaySignals = connected;
}
/*!
Returns \c true if automatic signal relaying from the real object (see object()) is enabled,
otherwiser returns \c false.
\sa setAutoRelaySignals()
*/
bool QDBusAbstractAdaptor::autoRelaySignals() const
{
return d_func()->autoRelaySignals;
}
QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *obj)
: QObject(obj), waitingForPolish(false)
{
}
QDBusAdaptorConnector::~QDBusAdaptorConnector()
{
}
void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
{
// find the interface name
const QMetaObject *mo = adaptor->metaObject();
int ciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
if (ciid != -1) {
QMetaClassInfo mci = mo->classInfo(ciid);
if (*mci.value()) {
// find out if this interface exists first
const char *interface = mci.value();
AdaptorMap::Iterator it = std::lower_bound(adaptors.begin(), adaptors.end(),
QByteArray(interface));
if (it != adaptors.end() && qstrcmp(interface, it->interface) == 0) {
// exists. Replace it (though it's probably the same)
if (it->adaptor != adaptor) {
// reconnect the signals
disconnectAllSignals(it->adaptor);
connectAllSignals(adaptor);
}
it->adaptor = adaptor;
} else {
// create a new one
AdaptorData entry;
entry.interface = interface;
entry.adaptor = adaptor;
adaptors << entry;
// connect the adaptor's signals to our relaySlot slot
connectAllSignals(adaptor);
}
}
}
}
void QDBusAdaptorConnector::disconnectAllSignals(QObject *obj)
{
QMetaObject::disconnect(obj, -1, this, relaySlotMethodIndex());
}
void QDBusAdaptorConnector::connectAllSignals(QObject *obj)
{
QMetaObject::connect(obj, -1, this, relaySlotMethodIndex(), Qt::DirectConnection);
}
void QDBusAdaptorConnector::polish()
{
if (!waitingForPolish)
return; // avoid working multiple times if multiple adaptors were added
waitingForPolish = false;
const QObjectList &objs = parent()->children();
QObjectList::ConstIterator it = objs.constBegin();
QObjectList::ConstIterator end = objs.constEnd();
for ( ; it != end; ++it) {
QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(*it);
if (adaptor)
addAdaptor(adaptor);
}
// sort the adaptor list
std::sort(adaptors.begin(), adaptors.end());
}
void QDBusAdaptorConnector::relaySlot(QMethodRawArguments argv)
{
QObject *sndr = sender();
if (Q_LIKELY(sndr)) {
relay(sndr, senderSignalIndex(), argv.arguments);
} else {
qWarning("QtDBus: cannot relay signals from parent %s(%p \"%s\") unless they are emitted in the object's thread %s(%p \"%s\"). "
"Current thread is %s(%p \"%s\").",
parent()->metaObject()->className(), parent(), qPrintable(parent()->objectName()),
parent()->thread()->metaObject()->className(), parent()->thread(), qPrintable(parent()->thread()->objectName()),
QThread::currentThread()->metaObject()->className(), QThread::currentThread(), qPrintable(QThread::currentThread()->objectName()));
}
}
void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **argv)
{
if (lastSignalIdx < QObject::staticMetaObject.methodCount())
// QObject signal (destroyed(QObject *)) -- ignore
return;
const QMetaObject *senderMetaObject = senderObj->metaObject();
QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
QObject *realObject = senderObj;
if (qobject_cast<QDBusAbstractAdaptor *>(senderObj))
// it's an adaptor, so the real object is in fact its parent
realObject = realObject->parent();
// break down the parameter list
QList<QMetaType> types;
QString errorMsg;
int inputCount = qDBusParametersForMethod(mm, types, errorMsg);
if (inputCount == -1) {
// invalid signal signature
qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s: %s",
senderMetaObject->className(), mm.methodSignature().constData(),
qPrintable(errorMsg));
return;
}
if (inputCount + 1 != types.size() ||
types.at(inputCount) == QDBusMetaTypeId::message()) {
// invalid signal signature
qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s",
senderMetaObject->className(), mm.methodSignature().constData());
return;
}
QVariantList args;
const int numTypes = types.size();
args.reserve(numTypes - 1);
for (int i = 1; i < numTypes; ++i)
args << QVariant(QMetaType(types.at(i)), argv[i]);
// now emit the signal with all the information
emit relaySignal(realObject, senderMetaObject, lastSignalIdx, args);
}
QT_END_NAMESPACE
#include "moc_qdbusabstractadaptor_p.cpp"
#include "moc_qdbusabstractadaptor.cpp"
#endif // QT_NO_DBUS

View File

@ -0,0 +1,37 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSABSTRACTADAPTOR_H
#define QDBUSABSTRACTADAPTOR_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qobject.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusAbstractAdaptorPrivate;
class Q_DBUS_EXPORT QDBusAbstractAdaptor: public QObject
{
Q_OBJECT
protected:
explicit QDBusAbstractAdaptor(QObject *parent);
public:
~QDBusAbstractAdaptor();
protected:
void setAutoRelaySignals(bool enable);
bool autoRelaySignals() const;
private:
Q_DECLARE_PRIVATE(QDBusAbstractAdaptor)
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,106 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSABSTRACTADAPTOR_P_H
#define QDBUSABSTRACTADAPTOR_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qdbusabstractadaptor.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qobject.h>
#include <QtCore/qvariant.h>
#include "private/qobject_p.h"
#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface"
#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection"
#ifndef QT_NO_DBUS
#ifdef interface
# undef interface
#endif
QT_BEGIN_NAMESPACE
class QDBusAbstractAdaptor;
class QDBusAdaptorConnector;
class QDBusAdaptorManager;
class QDBusConnectionPrivate;
class QDBusAbstractAdaptorPrivate: public QObjectPrivate
{
Q_DECLARE_PUBLIC(QDBusAbstractAdaptor)
public:
QDBusAbstractAdaptorPrivate() : autoRelaySignals(false) {}
QString xml;
bool autoRelaySignals;
static QString retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor);
static void saveIntrospectionXml(QDBusAbstractAdaptor *adaptor, const QString &xml);
};
class QDBusAdaptorConnector: public QObject
{
Q_OBJECT
public: // typedefs
struct AdaptorData
{
const char *interface;
QDBusAbstractAdaptor *adaptor;
inline bool operator<(const AdaptorData &other) const
{ return QByteArray(interface) < other.interface; }
inline bool operator<(const QString &other) const
{ return QLatin1StringView(interface) < other; }
inline bool operator<(const QByteArray &other) const
{ return interface < other; }
};
typedef QList<AdaptorData> AdaptorMap;
public: // methods
explicit QDBusAdaptorConnector(QObject *parent);
~QDBusAdaptorConnector();
void addAdaptor(QDBusAbstractAdaptor *adaptor);
void connectAllSignals(QObject *object);
void disconnectAllSignals(QObject *object);
void relay(QObject *sender, int id, void **);
public Q_SLOTS:
void relaySlot(QMethodRawArguments a);
void polish();
Q_SIGNALS:
void relaySignal(QObject *obj, const QMetaObject *metaObject, int sid, const QVariantList &args);
public: // member variables
AdaptorMap adaptors;
bool waitingForPolish : 1;
private:
static int relaySlotMethodIndex();
};
Q_DECLARE_TYPEINFO(QDBusAdaptorConnector::AdaptorData, Q_PRIMITIVE_TYPE);
extern QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *object);
extern QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *object);
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif // QDBUSABSTRACTADAPTOR_P_H

View File

@ -0,0 +1,777 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusabstractinterface.h"
#include "qdbusabstractinterface_p.h"
#include <qcoreapplication.h>
#include <qthread.h>
#include "qdbusargument.h"
#include "qdbuspendingcall.h"
#include "qdbusmessage_p.h"
#include "qdbusmetaobject_p.h"
#include "qdbusmetatype_p.h"
#include "qdbusservicewatcher.h"
#include "qdbusutil_p.h"
#include <qdebug.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
namespace {
// ### Qt6: change to a regular QEvent (customEvent)
// We need to use a QMetaCallEvent here because we can't override customEvent() in
// Qt 5. Since QDBusAbstractInterface is meant to be derived from, the vtables of
// classes in generated code will have a pointer to QObject::customEvent instead
// of to QDBusAbstractInterface::customEvent.
// See solution in Patch Set 1 of this change in the Qt Gerrit servers.
// (https://codereview.qt-project.org/#/c/126384/1)
class DisconnectRelayEvent : public QAbstractMetaCallEvent
{
public:
DisconnectRelayEvent(QObject *sender, const QMetaMethod &m)
: QAbstractMetaCallEvent(sender, m.methodIndex())
{}
void placeMetaCall(QObject *object) override
{
QDBusAbstractInterface *iface = static_cast<QDBusAbstractInterface *>(object);
QDBusAbstractInterfacePrivate::finishDisconnectNotify(iface, signalId());
}
};
}
static QDBusError checkIfValid(const QString &service, const QString &path,
const QString &interface, bool isDynamic, bool isPeer)
{
// We should be throwing exceptions here... oh well
QDBusError error;
// dynamic interfaces (QDBusInterface) can have empty interfaces, but not service and object paths
// non-dynamic is the opposite: service and object paths can be empty, but not the interface
if (!isDynamic) {
// use assertion here because this should never happen, at all
Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty");
}
if (!QDBusUtil::checkBusName(service, (isDynamic && !isPeer) ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
return error;
if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
return error;
if (!QDBusUtil::checkInterfaceName(interface, QDBusUtil::EmptyAllowed, &error))
return error;
// no error
return QDBusError();
}
QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv,
const QString &p,
const QString &iface,
const QDBusConnection& con,
bool isDynamic)
: connection(con), service(serv), path(p), interface(iface),
lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() &&
connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))),
timeout(-1),
isValid(!lastError.isValid())
{
if (!isValid)
return;
if (!connection.isConnected()) {
lastError = QDBusError(QDBusError::Disconnected,
QDBusUtil::disconnectedErrorMessage());
}
}
void QDBusAbstractInterfacePrivate::initOwnerTracking()
{
if (!isValid || !connection.isConnected() || !connectionPrivate()->shouldWatchService(service))
return;
QObject::connect(new QDBusServiceWatcher(service, connection, QDBusServiceWatcher::WatchForOwnerChange, q_func()),
SIGNAL(serviceOwnerChanged(QString,QString,QString)),
q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
currentOwner = connectionPrivate()->getNameOwner(service);
if (currentOwner.isEmpty())
lastError = connectionPrivate()->lastError;
}
bool QDBusAbstractInterfacePrivate::canMakeCalls() const
{
// recheck only if we have a wildcard (i.e. empty) service or path
// if any are empty, set the error message according to QDBusUtil
if (service.isEmpty() && connectionPrivate()->mode != QDBusConnectionPrivate::PeerMode)
return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError);
if (path.isEmpty())
return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError);
return true;
}
bool QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp, void *returnValuePtr) const
{
if (!isValid || !canMakeCalls()) // can't make calls
return false;
QMetaType type = mp.metaType();
// is this metatype registered?
const char *expectedSignature = "";
if (type.id() != QMetaType::QVariant) {
expectedSignature = QDBusMetaType::typeToSignature(type);
if (expectedSignature == nullptr) {
qWarning("QDBusAbstractInterface: type %s must be registered with Qt D-Bus before it can be "
"used to read property %s.%s",
mp.typeName(), qPrintable(interface), mp.name());
lastError = QDBusError(QDBusError::Failed, "Unregistered type %1 cannot be handled"_L1
.arg(QLatin1StringView(mp.typeName())));
return false;
}
}
// try to read this property
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QDBusUtil::dbusInterfaceProperties(),
QStringLiteral("Get"));
QDBusMessagePrivate::setParametersValidated(msg, true);
msg << interface << QString::fromUtf8(mp.name());
QDBusMessage reply = connection.call(msg, QDBus::Block, timeout);
if (reply.type() != QDBusMessage::ReplyMessage) {
lastError = QDBusError(reply);
return false;
}
if (reply.signature() != "v"_L1) {
QString errmsg =
"Invalid signature '%1' in return from call to " DBUS_INTERFACE_PROPERTIES ""_L1;
lastError = QDBusError(QDBusError::InvalidSignature, std::move(errmsg).arg(reply.signature()));
return false;
}
QByteArray foundSignature;
const char *foundType = nullptr;
QVariant value = qvariant_cast<QDBusVariant>(reply.arguments().at(0)).variant();
if (value.metaType() == type || type.id() == QMetaType::QVariant
|| (expectedSignature[0] == 'v' && expectedSignature[1] == '\0')) {
// simple match
if (type.id() == QMetaType::QVariant) {
*reinterpret_cast<QVariant*>(returnValuePtr) = value;
} else {
QMetaType(type).destruct(returnValuePtr);
QMetaType(type).construct(returnValuePtr, value.constData());
}
return true;
}
if (value.metaType() == QMetaType::fromType<QDBusArgument>()) {
QDBusArgument arg = qvariant_cast<QDBusArgument>(value);
foundType = "user type";
foundSignature = arg.currentSignature().toLatin1();
if (foundSignature == expectedSignature) {
// signatures match, we can demarshall
return QDBusMetaType::demarshall(arg, QMetaType(type), returnValuePtr);
}
} else {
foundType = value.typeName();
foundSignature = QDBusMetaType::typeToSignature(value.metaType());
}
// there was an error...
const auto errmsg = "Unexpected '%1' (%2) when retrieving property '%3.%4' "
"(expected type '%5' (%6))"_L1;
lastError = QDBusError(QDBusError::InvalidSignature,
errmsg.arg(QLatin1StringView(foundType),
QLatin1StringView(foundSignature),
interface,
QLatin1StringView(mp.name()),
QLatin1StringView(mp.typeName()),
QLatin1StringView(expectedSignature)));
return false;
}
bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
{
if (!isValid || !canMakeCalls()) // can't make calls
return false;
// send the value
QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
QDBusUtil::dbusInterfaceProperties(),
QStringLiteral("Set"));
QDBusMessagePrivate::setParametersValidated(msg, true);
msg << interface << QString::fromUtf8(mp.name()) << QVariant::fromValue(QDBusVariant(value));
QDBusMessage reply = connection.call(msg, QDBus::Block, timeout);
if (reply.type() != QDBusMessage::ReplyMessage) {
lastError = QDBusError(reply);
return false;
}
return true;
}
void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
const QString &oldOwner,
const QString &newOwner)
{
Q_UNUSED(oldOwner);
Q_UNUSED(name);
//qDebug() << "QDBusAbstractInterfacePrivate serviceOwnerChanged" << name << oldOwner << newOwner;
Q_ASSERT(name == service);
currentOwner = newOwner;
}
QDBusAbstractInterfaceBase::QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &d, QObject *parent)
: QObject(d, parent)
{
}
int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
int saved_id = _id;
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty) {
QMetaProperty mp = metaObject()->property(saved_id);
int &status = *reinterpret_cast<int *>(_a[2]);
if (_c == QMetaObject::WriteProperty) {
QVariant value;
if (mp.metaType() == QMetaType::fromType<QDBusVariant>())
value = reinterpret_cast<const QDBusVariant*>(_a[0])->variant();
else
value = QVariant(mp.metaType(), _a[0]);
status = d_func()->setProperty(mp, value) ? 1 : 0;
} else {
bool readStatus = d_func()->property(mp, _a[0]);
// Caller supports QVariant returns? Then we can also report errors
// by storing an invalid variant.
if (!readStatus && _a[1]) {
status = 0;
reinterpret_cast<QVariant*>(_a[1])->clear();
}
}
_id = -1;
}
return _id;
}
/*!
\class QDBusAbstractInterface
\inmodule QtDBus
\since 4.2
\brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces.
Generated-code classes also derive from QDBusAbstractInterface,
all methods described here are also valid for generated-code
classes. In addition to those described here, generated-code
classes provide member functions for the remote methods, which
allow for compile-time checking of the correct parameters and
return values, as well as property type-matching and signal
parameter-matching.
\sa {qdbusxml2cpp.html}{The QDBus compiler}, QDBusInterface
*/
/*!
\internal
This is the constructor called from QDBusInterface::QDBusInterface.
*/
QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d, QObject *parent)
: QDBusAbstractInterfaceBase(d, parent)
{
d.initOwnerTracking();
}
/*!
\internal
This is the constructor called from static classes derived from
QDBusAbstractInterface (i.e., those generated by dbusxml2cpp).
*/
QDBusAbstractInterface::QDBusAbstractInterface(const QString &service, const QString &path,
const char *interface, const QDBusConnection &con,
QObject *parent)
: QDBusAbstractInterfaceBase(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
con, false), parent)
{
// keep track of the service owner
d_func()->initOwnerTracking();
}
/*!
Releases this object's resources.
*/
QDBusAbstractInterface::~QDBusAbstractInterface()
{
}
/*!
Returns \c true if this is a valid reference to a remote object. It returns \c false if
there was an error during the creation of this interface (for instance, if the remote
application does not exist).
Note: when dealing with remote objects, it is not always possible to determine if it
exists when creating a QDBusInterface.
*/
bool QDBusAbstractInterface::isValid() const
{
Q_D(const QDBusAbstractInterface);
/* We don't retrieve the owner name for peer connections */
if (d->connectionPrivate() && d->connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode) {
return d->isValid;
} else {
return !d->currentOwner.isEmpty();
}
}
/*!
Returns the connection this interface is associated with.
*/
QDBusConnection QDBusAbstractInterface::connection() const
{
return d_func()->connection;
}
/*!
Returns the name of the service this interface is associated with.
*/
QString QDBusAbstractInterface::service() const
{
return d_func()->service;
}
/*!
Returns the object path that this interface is associated with.
*/
QString QDBusAbstractInterface::path() const
{
return d_func()->path;
}
/*!
Returns the name of this interface.
*/
QString QDBusAbstractInterface::interface() const
{
return d_func()->interface;
}
/*!
Returns the error the last operation produced, or an invalid error if the last operation did not
produce an error.
*/
QDBusError QDBusAbstractInterface::lastError() const
{
return d_func()->lastError;
}
/*!
Sets the timeout in milliseconds for all future DBus calls to \a timeout.
-1 means the default DBus timeout (usually 25 seconds).
\since 4.8
*/
void QDBusAbstractInterface::setTimeout(int timeout)
{
d_func()->timeout = timeout;
}
/*!
Returns the current value of the timeout in milliseconds.
-1 means the default DBus timeout (usually 25 seconds).
\since 4.8
*/
int QDBusAbstractInterface::timeout() const
{
return d_func()->timeout;
}
/*!
Places a call to the remote method specified by \a method on this interface, using \a args as
arguments. This function returns the message that was received as a reply, which can be a normal
QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
failed). The \a mode parameter specifies how this call should be placed.
If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this
call produced.
Normally, you should place calls using call().
\warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy:
other method calls and signals may be delivered before this function returns, as well
as other Qt queued signals and events.
\threadsafe
*/
QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
const QString& method,
const QList<QVariant>& args)
{
Q_D(QDBusAbstractInterface);
if (!d->isValid || !d->canMakeCalls())
return QDBusMessage::createError(d->lastError);
QString m = method;
// split out the signature from the method
int pos = method.indexOf(u'.');
if (pos != -1)
m.truncate(pos);
if (mode == QDBus::AutoDetect) {
// determine if this a sync or async call
mode = QDBus::Block;
const QMetaObject *mo = metaObject();
QByteArray match = m.toLatin1();
for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) {
QMetaMethod mm = mo->method(i);
if (mm.name() == match) {
// found a method with the same name as what we're looking for
// hopefully, nobody is overloading asynchronous and synchronous methods with
// the same name
QList<QByteArray> tags = QByteArray(mm.tag()).split(' ');
if (tags.contains("Q_NOREPLY"))
mode = QDBus::NoBlock;
break;
}
}
}
// qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path();
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m);
QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
QDBusMessage reply = d->connection.call(msg, mode, d->timeout);
if (thread() == QThread::currentThread())
d->lastError = QDBusError(reply); // will clear if reply isn't an error
// ensure that there is at least one element
if (reply.arguments().isEmpty())
reply << QVariant();
return reply;
}
/*!
\since 4.5
Places a call to the remote method specified by \a method on this
interface, using \a args as arguments. This function returns a
QDBusPendingCall object that can be used to track the status of the
reply and access its contents once it has arrived.
Normally, you should place calls using asyncCall().
\threadsafe
*/
QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString& method,
const QList<QVariant>& args)
{
Q_D(QDBusAbstractInterface);
if (!d->isValid || !d->canMakeCalls())
return QDBusPendingCall::fromError(d->lastError);
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
return d->connection.asyncCall(msg, d->timeout);
}
/*!
Places a call to the remote method specified by \a method
on this interface, using \a args as arguments. This function
returns immediately after queueing the call. The reply from
the remote function is delivered to the \a returnMethod on
object \a receiver. If an error occurs, the \a errorMethod
on object \a receiver is called instead.
This function returns \c true if the queueing succeeds. It does
not indicate that the executed call succeeded. If it fails,
the \a errorMethod is called. If the queueing failed, this
function returns \c false and no slot will be called.
The \a returnMethod must have as its parameters the types returned
by the function call. Optionally, it may have a QDBusMessage
parameter as its last or only parameter. The \a errorMethod must
have a QDBusError as its only parameter.
\since 4.3
\sa QDBusError, QDBusMessage
*/
bool QDBusAbstractInterface::callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver,
const char *returnMethod,
const char *errorMethod)
{
Q_D(QDBusAbstractInterface);
if (!d->isValid || !d->canMakeCalls())
return false;
QDBusMessage msg = QDBusMessage::createMethodCall(service(),
path(),
interface(),
method);
QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
d->lastError = QDBusError();
return d->connection.callWithCallback(msg,
receiver,
returnMethod,
errorMethod,
d->timeout);
}
/*!
\overload
This function is deprecated. Please use the overloaded version.
Places a call to the remote method specified by \a method
on this interface, using \a args as arguments. This function
returns immediately after queueing the call. The reply from
the remote function or any errors emitted by it are delivered
to the \a slot slot on object \a receiver.
This function returns \c true if the queueing succeeded: it does
not indicate that the call succeeded. If it failed, the slot
will be called with an error message. lastError() will not be
set under those circumstances.
\sa QDBusError, QDBusMessage
*/
bool QDBusAbstractInterface::callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver,
const char *slot)
{
return callWithCallback(method, args, receiver, slot, nullptr);
}
/*!
\internal
Catch signal connections.
*/
void QDBusAbstractInterface::connectNotify(const QMetaMethod &signal)
{
// someone connecting to one of our signals
Q_D(QDBusAbstractInterface);
if (!d->isValid)
return;
// we end up recursing here, so optimize away
static const QMetaMethod destroyedSignal = QMetaMethod::fromSignal(&QDBusAbstractInterface::destroyed);
if (signal == destroyedSignal)
return;
QDBusConnectionPrivate *conn = d->connectionPrivate();
if (conn) {
conn->connectRelay(d->service, d->path, d->interface,
this, signal);
}
}
/*!
\internal
Catch signal disconnections.
*/
void QDBusAbstractInterface::disconnectNotify(const QMetaMethod &signal)
{
// someone disconnecting from one of our signals
Q_D(QDBusAbstractInterface);
if (!d->isValid)
return;
// disconnection is just resource freeing, so it can be delayed;
// let's do that later, after all the QObject mutexes have been unlocked.
QCoreApplication::postEvent(this, new DisconnectRelayEvent(this, signal));
}
/*!
\internal
Continues the disconnect notification from above.
*/
void QDBusAbstractInterfacePrivate::finishDisconnectNotify(QDBusAbstractInterface *ptr, int signalId)
{
QDBusAbstractInterfacePrivate *d = ptr->d_func();
QDBusConnectionPrivate *conn = d->connectionPrivate();
if (!conn)
return;
const QMetaObject *mo = ptr->metaObject();
QMetaMethod signal = signalId >= 0 ? mo->method(signalId) : QMetaMethod();
if (signal.isValid()) {
if (!ptr->isSignalConnected(signal))
return conn->disconnectRelay(d->service, d->path, d->interface,
ptr, signal);
} else {
// wildcard disconnecting, we need to figure out which of our signals are
// no longer connected to anything
int midx = QObject::staticMetaObject.methodCount();
const int end = mo->methodCount();
for ( ; midx < end; ++midx) {
QMetaMethod mm = mo->method(midx);
if (mm.methodType() == QMetaMethod::Signal && !ptr->isSignalConnected(mm))
conn->disconnectRelay(d->service, d->path, d->interface, ptr, mm);
}
}
}
/*!
\internal
Get the value of the property \a propname.
*/
QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
{
// assume this property exists and is readable
// we're only called from generated code anyways
return property(propname);
}
/*!
\internal
Set the value of the property \a propname to \a value.
*/
void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
{
setProperty(propname, value);
}
/*!
\fn QDBusAbstractInterface::call(const QString &message)
\internal
*/
/*!
\fn template <typename...Args> QDBusMessage QDBusAbstractInterface::call(const QString &method, Args&&...args)
Calls the method \a method on this interface and passes \a args to the method.
All \a args must be convertible to QVariant.
The parameters to \c call are passed on to the remote function via D-Bus as input
arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error
reply, lastError() will also be set to the contents of the error message.
It can be used the following way:
\snippet code/src_qdbus_qdbusabstractinterface.cpp 0
This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
\note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
\sa callWithArgumentList()
*/
/*!
\fn QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &message)
\internal
*/
/*!
\fn template <typename...Args> QDBusMessage QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &method, Args&&...args)
\overload
Calls the method \a method on this interface and passes \a args to the method.
All \a args must be convertible to QVariant.
If \a mode is \c NoWaitForReply, then this function will return immediately after
placing the call, without waiting for a reply from the remote
method. Otherwise, \a mode indicates whether this function should
activate the Qt Event Loop while waiting for the reply to arrive.
If this function reenters the Qt event loop in order to wait for the
reply, it will exclude user input. During the wait, it may deliver
signals and other method calls to your application. Therefore, it
must be prepared to handle a reentrancy whenever a call is placed
with call().
\note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
\sa callWithArgumentList()
*/
/*!
\fn QDBusAbstractInterface::asyncCall(const QString &message)
\internal
*/
/*!
\fn template <typename...Args> QDBusPendingCall QDBusAbstractInterface::asyncCall(const QString &method, Args&&...args)
Calls the method \a method on this interface and passes \a args to the method.
All \a args must be convertible to QVariant.
The parameters to \c call are passed on to the remote function via D-Bus as input
arguments. The returned QDBusPendingCall object can be used to find out information about
the reply.
It can be used the following way:
\snippet code/src_qdbus_qdbusabstractinterface.cpp 1
This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
\note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
\sa asyncCallWithArgumentList()
*/
/*!
\internal
*/
QDBusMessage QDBusAbstractInterface::internalConstCall(QDBus::CallMode mode,
const QString &method,
const QList<QVariant> &args) const
{
// ### move the code here, and make the other functions call this
return const_cast<QDBusAbstractInterface*>(this)->callWithArgumentList(mode, method, args);
}
QDBusMessage QDBusAbstractInterface::doCall(QDBus::CallMode mode, const QString &method, const QVariant *args, size_t numArgs)
{
QList<QVariant> list;
list.reserve(int(numArgs));
for (size_t i = 0; i < numArgs; ++i)
list.append(args[i]);
return callWithArgumentList(mode, method, list);
}
QDBusPendingCall QDBusAbstractInterface::doAsyncCall(const QString &method, const QVariant *args, size_t numArgs)
{
QList<QVariant> list;
list.reserve(int(numArgs));
for (size_t i = 0; i < numArgs; ++i)
list.append(args[i]);
return asyncCallWithArgumentList(method, list);
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#include "moc_qdbusabstractinterface.cpp"

View File

@ -0,0 +1,141 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSABSTRACTINTERFACE_H
#define QDBUSABSTRACTINTERFACE_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
#include <QtDBus/qdbusmessage.h>
#include <QtDBus/qdbusextratypes.h>
#include <QtDBus/qdbusconnection.h>
#include <QtDBus/qdbuspendingcall.h>
#ifdef interface
#undef interface
#endif
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusError;
class QDBusPendingCall;
class QDBusAbstractInterfacePrivate;
class Q_DBUS_EXPORT QDBusAbstractInterfaceBase: public QObject
{
public:
int qt_metacall(QMetaObject::Call, int, void**) override;
protected:
QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &dd, QObject *parent);
private:
Q_DECLARE_PRIVATE(QDBusAbstractInterface)
};
class Q_DBUS_EXPORT QDBusAbstractInterface:
#ifdef Q_QDOC
public QObject
#else
public QDBusAbstractInterfaceBase
#endif
{
Q_OBJECT
public:
virtual ~QDBusAbstractInterface();
bool isValid() const;
QDBusConnection connection() const;
QString service() const;
QString path() const;
QString interface() const;
QDBusError lastError() const;
void setTimeout(int timeout);
int timeout() const;
QDBusMessage call(const QString &method)
{
return doCall(QDBus::AutoDetect, method, nullptr, 0);
}
template <typename...Args>
QDBusMessage call(const QString &method, Args &&...args)
{
const QVariant variants[] = { QVariant(std::forward<Args>(args))... };
return doCall(QDBus::AutoDetect, method, variants, sizeof...(args));
}
QDBusMessage call(QDBus::CallMode mode, const QString &method)
{
return doCall(mode, method, nullptr, 0);
}
template <typename...Args>
QDBusMessage call(QDBus::CallMode mode, const QString &method, Args &&...args)
{
const QVariant variants[] = { QVariant(std::forward<Args>(args))... };
return doCall(mode, method, variants, sizeof...(args));
}
QDBusMessage callWithArgumentList(QDBus::CallMode mode,
const QString &method,
const QList<QVariant> &args);
bool callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver, const char *member, const char *errorSlot);
bool callWithCallback(const QString &method,
const QList<QVariant> &args,
QObject *receiver, const char *member);
QDBusPendingCall asyncCall(const QString &method)
{
return doAsyncCall(method, nullptr, 0);
}
template <typename...Args>
QDBusPendingCall asyncCall(const QString &method, Args&&...args)
{
const QVariant variants[] = { QVariant(std::forward<Args>(args))... };
return doAsyncCall(method, variants, sizeof...(args));
}
QDBusPendingCall asyncCallWithArgumentList(const QString &method,
const QList<QVariant> &args);
protected:
QDBusAbstractInterface(const QString &service, const QString &path, const char *interface,
const QDBusConnection &connection, QObject *parent);
QDBusAbstractInterface(QDBusAbstractInterfacePrivate &, QObject *parent);
void connectNotify(const QMetaMethod &signal) override;
void disconnectNotify(const QMetaMethod &signal) override;
QVariant internalPropGet(const char *propname) const;
void internalPropSet(const char *propname, const QVariant &value);
QDBusMessage internalConstCall(QDBus::CallMode mode,
const QString &method,
const QList<QVariant> &args = QList<QVariant>()) const;
private:
QDBusMessage doCall(QDBus::CallMode mode, const QString &method, const QVariant *args, size_t numArgs);
QDBusPendingCall doAsyncCall(const QString &method, const QVariant *args, size_t numArgs);
private:
Q_DECLARE_PRIVATE(QDBusAbstractInterface)
Q_PRIVATE_SLOT(d_func(), void _q_serviceOwnerChanged(QString,QString,QString))
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,72 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSABSTRACTINTERFACE_P_H
#define QDBUSABSTRACTINTERFACE_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qdbusabstractinterface.h>
#include <qdbusconnection.h>
#include <qdbuserror.h>
#include "qdbusconnection_p.h"
#include "private/qobject_p.h"
#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusAbstractInterfacePrivate : public QObjectPrivate
{
public:
Q_DECLARE_PUBLIC(QDBusAbstractInterface)
mutable QDBusConnection connection; // mutable because we want to make calls from const functions
QString service;
QString currentOwner;
QString path;
QString interface;
mutable QDBusError lastError;
int timeout;
// this is set during creation and never changed
// it can't be const because QDBusInterfacePrivate has one more check
bool isValid;
QDBusAbstractInterfacePrivate(const QString &serv, const QString &p,
const QString &iface, const QDBusConnection& con, bool dynamic);
virtual ~QDBusAbstractInterfacePrivate() { }
void initOwnerTracking();
bool canMakeCalls() const;
// these functions do not check if the property is valid
bool property(const QMetaProperty &mp, void *returnValuePtr) const;
bool setProperty(const QMetaProperty &mp, const QVariant &value);
// return conn's d pointer
inline QDBusConnectionPrivate *connectionPrivate() const
{ return QDBusConnectionPrivate::d(connection); }
void _q_serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
static void finishDisconnectNotify(QDBusAbstractInterface *iface, int signalId);
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

1373
src/dbus/qdbusargument.cpp Normal file

File diff suppressed because it is too large Load Diff

333
src/dbus/qdbusargument.h Normal file
View File

@ -0,0 +1,333 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSARGUMENT_H
#define QDBUSARGUMENT_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qhash.h>
#include <QtCore/qglobal.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvariant.h>
#include <QtDBus/qdbusextratypes.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusUnixFileDescriptor;
class QDBusArgumentPrivate;
class QDBusDemarshaller;
class QDBusMarshaller;
class Q_DBUS_EXPORT QDBusArgument
{
public:
enum ElementType {
BasicType,
VariantType,
ArrayType,
StructureType,
MapType,
MapEntryType,
UnknownType = -1
};
QDBusArgument();
QDBusArgument(const QDBusArgument &other);
QDBusArgument(QDBusArgument &&other) noexcept : d(other.d) { other.d = nullptr; }
QDBusArgument &operator=(QDBusArgument &&other) noexcept { swap(other); return *this; }
QDBusArgument &operator=(const QDBusArgument &other);
~QDBusArgument();
void swap(QDBusArgument &other) noexcept { qt_ptr_swap(d, other.d); }
// used for marshalling (Qt -> D-BUS)
QDBusArgument &operator<<(uchar arg);
QDBusArgument &operator<<(bool arg);
QDBusArgument &operator<<(short arg);
QDBusArgument &operator<<(ushort arg);
QDBusArgument &operator<<(int arg);
QDBusArgument &operator<<(uint arg);
QDBusArgument &operator<<(qlonglong arg);
QDBusArgument &operator<<(qulonglong arg);
QDBusArgument &operator<<(double arg);
QDBusArgument &operator<<(const QString &arg);
QDBusArgument &operator<<(const QDBusVariant &arg);
QDBusArgument &operator<<(const QDBusObjectPath &arg);
QDBusArgument &operator<<(const QDBusSignature &arg);
QDBusArgument &operator<<(const QDBusUnixFileDescriptor &arg);
QDBusArgument &operator<<(const QStringList &arg);
QDBusArgument &operator<<(const QByteArray &arg);
void beginStructure();
void endStructure();
void beginArray(int elementMetaTypeId)
{ beginArray(QMetaType(elementMetaTypeId)); }
void beginArray(QMetaType elementMetaType);
void endArray();
void beginMap(int keyMetaTypeId, int valueMetaTypeId)
{ beginMap(QMetaType(keyMetaTypeId), QMetaType(valueMetaTypeId)); }
void beginMap(QMetaType keyMetaType, QMetaType valueMetaType);
void endMap();
void beginMapEntry();
void endMapEntry();
void appendVariant(const QVariant &v);
// used for de-marshalling (D-BUS -> Qt)
QString currentSignature() const;
ElementType currentType() const;
const QDBusArgument &operator>>(uchar &arg) const;
const QDBusArgument &operator>>(bool &arg) const;
const QDBusArgument &operator>>(short &arg) const;
const QDBusArgument &operator>>(ushort &arg) const;
const QDBusArgument &operator>>(int &arg) const;
const QDBusArgument &operator>>(uint &arg) const;
const QDBusArgument &operator>>(qlonglong &arg) const;
const QDBusArgument &operator>>(qulonglong &arg) const;
const QDBusArgument &operator>>(double &arg) const;
const QDBusArgument &operator>>(QString &arg) const;
const QDBusArgument &operator>>(QDBusVariant &arg) const;
const QDBusArgument &operator>>(QDBusObjectPath &arg) const;
const QDBusArgument &operator>>(QDBusSignature &arg) const;
const QDBusArgument &operator>>(QDBusUnixFileDescriptor &arg) const;
const QDBusArgument &operator>>(QStringList &arg) const;
const QDBusArgument &operator>>(QByteArray &arg) const;
void beginStructure() const;
void endStructure() const;
void beginArray() const;
void endArray() const;
void beginMap() const;
void endMap() const;
void beginMapEntry() const;
void endMapEntry() const;
bool atEnd() const;
QVariant asVariant() const;
protected:
QDBusArgument(QDBusArgumentPrivate *d);
friend class QDBusArgumentPrivate;
mutable QDBusArgumentPrivate *d;
};
Q_DECLARE_SHARED(QDBusArgument)
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QDBusArgument, Q_DBUS_EXPORT)
QT_BEGIN_NAMESPACE
template<typename T> inline T qdbus_cast(const QDBusArgument &arg)
{
T item;
arg >> item;
return item;
}
template<typename T> inline T qdbus_cast(const QVariant &v)
{
if (v.metaType() == QMetaType::fromType<QDBusArgument>())
return qdbus_cast<T>(qvariant_cast<QDBusArgument>(v));
else
return qvariant_cast<T>(v);
}
// specialize for QVariant, allowing it to be used in place of QDBusVariant
template<> inline QVariant qdbus_cast<QVariant>(const QDBusArgument &arg)
{
QDBusVariant item;
arg >> item;
return item.variant();
}
template<> inline QVariant qdbus_cast<QVariant>(const QVariant &v)
{
return qdbus_cast<QDBusVariant>(v).variant();
}
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QVariant &v);
// QVariant types
#ifndef QDBUS_NO_SPECIALTYPES
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QDate &date);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QDate &date);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QTime &time);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QTime &time);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QDateTime &dt);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QDateTime &dt);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QRect &rect);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QRect &rect);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QRectF &rect);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QRectF &rect);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QSize &size);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QSize &size);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QSizeF &size);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QSizeF &size);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QPoint &pt);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QPoint &pt);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QPointF &pt);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QPointF &pt);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QLine &line);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QLine &line);
Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QLineF &line);
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QLineF &line);
#endif
template<template <typename> class Container, typename T,
typename = typename Container<T>::iterator>
inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<T> &list)
{
arg.beginArray(QMetaType::fromType<T>());
typename Container<T>::const_iterator it = list.begin();
typename Container<T>::const_iterator end = list.end();
for ( ; it != end; ++it)
arg << *it;
arg.endArray();
return arg;
}
template<template <typename> class Container, typename T,
typename = typename Container<T>::iterator>
inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<T> &list)
{
arg.beginArray();
list.clear();
while (!arg.atEnd()) {
T item;
arg >> item;
list.push_back(item);
}
arg.endArray();
return arg;
}
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantList &list)
{
arg.beginArray(QMetaType::fromType<QDBusVariant>());
QVariantList::ConstIterator it = list.constBegin();
QVariantList::ConstIterator end = list.constEnd();
for ( ; it != end; ++it)
arg << QDBusVariant(*it);
arg.endArray();
return arg;
}
// Specializations for associative containers
template <template <typename, typename> class Container, typename Key, typename T,
QtPrivate::IfAssociativeIteratorHasKeyAndValue<typename Container<Key, T>::iterator> = true>
inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<Key, T> &map)
{
arg.beginMap(QMetaType::fromType<Key>(), QMetaType::fromType<T>());
auto it = map.begin();
auto end = map.end();
for ( ; it != end; ++it) {
arg.beginMapEntry();
arg << it.key() << it.value();
arg.endMapEntry();
}
arg.endMap();
return arg;
}
template <template <typename, typename> class Container, typename Key, typename T,
QtPrivate::IfAssociativeIteratorHasFirstAndSecond<typename Container<Key, T>::iterator> = true>
inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<Key, T> &map)
{
arg.beginMap(QMetaType::fromType<Key>(), QMetaType::fromType<T>());
auto it = map.begin();
auto end = map.end();
for ( ; it != end; ++it) {
arg.beginMapEntry();
arg << it->first << it->second;
arg.endMapEntry();
}
arg.endMap();
return arg;
}
template <template <typename, typename> class Container, typename Key, typename T,
QtPrivate::IfAssociativeIteratorHasKeyAndValue<typename Container<Key, T>::iterator> = true>
inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<Key, T> &map)
{
arg.beginMap();
map.clear();
while (!arg.atEnd()) {
Key key;
T value;
arg.beginMapEntry();
arg >> key >> value;
map.insert(key, value);
arg.endMapEntry();
}
arg.endMap();
return arg;
}
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantMap &map)
{
arg.beginMap(QMetaType::fromType<QString>(), QMetaType::fromType<QDBusVariant>());
QVariantMap::ConstIterator it = map.constBegin();
QVariantMap::ConstIterator end = map.constEnd();
for ( ; it != end; ++it) {
arg.beginMapEntry();
arg << it.key() << QDBusVariant(it.value());
arg.endMapEntry();
}
arg.endMap();
return arg;
}
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantHash &map)
{
arg.beginMap(QMetaType::fromType<QString>(), QMetaType::fromType<QDBusVariant>());
QVariantHash::ConstIterator it = map.constBegin();
QVariantHash::ConstIterator end = map.constEnd();
for ( ; it != end; ++it) {
arg.beginMapEntry();
arg << it.key() << QDBusVariant(it.value());
arg.endMapEntry();
}
arg.endMap();
return arg;
}
template <typename T1, typename T2>
inline QDBusArgument &operator<<(QDBusArgument &arg, const QPair<T1, T2> &pair)
{
arg.beginStructure();
arg << pair.first << pair.second;
arg.endStructure();
return arg;
}
template <typename T1, typename T2>
inline const QDBusArgument &operator>>(const QDBusArgument &arg, QPair<T1, T2> &pair)
{
arg.beginStructure();
arg >> pair.first >> pair.second;
arg.endStructure();
return arg;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

193
src/dbus/qdbusargument_p.h Normal file
View File

@ -0,0 +1,193 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSARGUMENT_P_H
#define QDBUSARGUMENT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qdbusargument.h>
#include "qdbusunixfiledescriptor.h"
#include "qdbus_symbols_p.h"
#ifndef QT_NO_DBUS
#ifndef DBUS_TYPE_UNIX_FD
# define DBUS_TYPE_UNIX_FD int('h')
# define DBUS_TYPE_UNIX_FD_AS_STRING "h"
#endif
QT_BEGIN_NAMESPACE
class QDBusMarshaller;
class QDBusDemarshaller;
class QDBusArgumentPrivate
{
public:
inline QDBusArgumentPrivate(int flags = 0)
: message(nullptr), ref(1), capabilities(flags)
{ }
virtual ~QDBusArgumentPrivate();
static bool checkRead(QDBusArgumentPrivate *d);
static bool checkReadAndDetach(QDBusArgumentPrivate *&d);
static bool checkWrite(QDBusArgumentPrivate *&d);
QDBusMarshaller *marshaller();
QDBusDemarshaller *demarshaller();
static QByteArray createSignature(int id);
static inline QDBusArgument create(QDBusArgumentPrivate *d)
{
QDBusArgument q(d);
return q;
}
static inline QDBusArgumentPrivate *d(QDBusArgument &q)
{ return q.d; }
public:
DBusMessage *message;
QAtomicInt ref;
int capabilities;
enum Direction {
Marshalling,
Demarshalling
} direction;
};
class QDBusMarshaller: public QDBusArgumentPrivate
{
public:
QDBusMarshaller(int flags) : QDBusArgumentPrivate(flags), parent(nullptr), ba(nullptr), closeCode(0), ok(true), skipSignature(false)
{ direction = Marshalling; }
~QDBusMarshaller();
QString currentSignature();
void append(uchar arg);
void append(bool arg);
void append(short arg);
void append(ushort arg);
void append(int arg);
void append(uint arg);
void append(qlonglong arg);
void append(qulonglong arg);
void append(double arg);
void append(const QString &arg);
void append(const QDBusObjectPath &arg);
void append(const QDBusSignature &arg);
void append(const QDBusUnixFileDescriptor &arg);
void append(const QStringList &arg);
void append(const QByteArray &arg);
bool append(const QDBusVariant &arg); // this one can fail
QDBusMarshaller *beginStructure();
QDBusMarshaller *endStructure();
QDBusMarshaller *beginArray(QMetaType id);
QDBusMarshaller *endArray();
QDBusMarshaller *beginMap(QMetaType kid, QMetaType vid);
QDBusMarshaller *endMap();
QDBusMarshaller *beginMapEntry();
QDBusMarshaller *endMapEntry();
QDBusMarshaller *beginCommon(int code, const char *signature);
QDBusMarshaller *endCommon();
void open(QDBusMarshaller &sub, int code, const char *signature);
void close();
void error(const QString &message);
bool appendVariantInternal(const QVariant &arg);
bool appendRegisteredType(const QVariant &arg);
bool appendCrossMarshalling(QDBusDemarshaller *arg);
public:
DBusMessageIter iterator;
QDBusMarshaller *parent;
QByteArray *ba;
QString errorString;
char closeCode;
bool ok;
bool skipSignature;
private:
Q_DECL_COLD_FUNCTION void unregisteredTypeError(QMetaType t);
Q_DISABLE_COPY_MOVE(QDBusMarshaller)
};
class QDBusDemarshaller: public QDBusArgumentPrivate
{
public:
inline QDBusDemarshaller(int flags) : QDBusArgumentPrivate(flags), parent(nullptr)
{ direction = Demarshalling; }
~QDBusDemarshaller();
QString currentSignature();
uchar toByte();
bool toBool();
ushort toUShort();
short toShort();
int toInt();
uint toUInt();
qlonglong toLongLong();
qulonglong toULongLong();
double toDouble();
QString toString();
QDBusObjectPath toObjectPath();
QDBusSignature toSignature();
QDBusUnixFileDescriptor toUnixFileDescriptor();
QDBusVariant toVariant();
QStringList toStringList();
QByteArray toByteArray();
QDBusDemarshaller *beginStructure();
QDBusDemarshaller *endStructure();
QDBusDemarshaller *beginArray();
QDBusDemarshaller *endArray();
QDBusDemarshaller *beginMap();
QDBusDemarshaller *endMap();
QDBusDemarshaller *beginMapEntry();
QDBusDemarshaller *endMapEntry();
QDBusDemarshaller *beginCommon();
QDBusDemarshaller *endCommon();
QDBusArgument duplicate();
inline void close() { }
bool atEnd();
QVariant toVariantInternal();
QDBusArgument::ElementType currentType();
bool isCurrentTypeStringLike();
public:
DBusMessageIter iterator;
QDBusDemarshaller *parent;
private:
Q_DISABLE_COPY_MOVE(QDBusDemarshaller)
QString toStringUnchecked();
QDBusObjectPath toObjectPathUnchecked();
QDBusSignature toSignatureUnchecked();
QStringList toStringListUnchecked();
QByteArray toByteArrayUnchecked();
};
inline QDBusMarshaller *QDBusArgumentPrivate::marshaller()
{ return static_cast<QDBusMarshaller *>(this); }
inline QDBusDemarshaller *QDBusArgumentPrivate::demarshaller()
{ return static_cast<QDBusDemarshaller *>(this); }
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

1253
src/dbus/qdbusconnection.cpp Normal file

File diff suppressed because it is too large Load Diff

185
src/dbus/qdbusconnection.h Normal file
View File

@ -0,0 +1,185 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSCONNECTION_H
#define QDBUSCONNECTION_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
#ifndef QT_NO_DBUS
#ifdef interface
# undef interface
#endif
QT_BEGIN_NAMESPACE
namespace QDBus
{
enum CallMode {
NoBlock,
Block,
BlockWithGui,
AutoDetect
};
}
class QDBusAbstractInterfacePrivate;
class QDBusInterface;
class QDBusError;
class QDBusMessage;
class QDBusPendingCall;
class QDBusConnectionInterface;
class QDBusVirtualObject;
class QObject;
class QDBusConnectionPrivate;
class Q_DBUS_EXPORT QDBusConnection
{
Q_GADGET
Q_MOC_INCLUDE(<QtDBus/qdbuspendingcall.h>)
public:
enum BusType { SessionBus, SystemBus, ActivationBus };
Q_ENUM(BusType)
enum RegisterOption {
ExportAdaptors = 0x01,
ExportScriptableSlots = 0x10,
ExportScriptableSignals = 0x20,
ExportScriptableProperties = 0x40,
ExportScriptableInvokables = 0x80,
ExportScriptableContents = 0xf0,
ExportNonScriptableSlots = 0x100,
ExportNonScriptableSignals = 0x200,
ExportNonScriptableProperties = 0x400,
ExportNonScriptableInvokables = 0x800,
ExportNonScriptableContents = 0xf00,
ExportAllSlots = ExportScriptableSlots|ExportNonScriptableSlots,
ExportAllSignals = ExportScriptableSignals|ExportNonScriptableSignals,
ExportAllProperties = ExportScriptableProperties|ExportNonScriptableProperties,
ExportAllInvokables = ExportScriptableInvokables|ExportNonScriptableInvokables,
ExportAllContents = ExportScriptableContents|ExportNonScriptableContents,
#ifndef Q_QDOC
// Qt 4.2 had a misspelling here
ExportAllSignal = ExportAllSignals,
#endif
ExportChildObjects = 0x1000
// Reserved = 0xff000000
};
Q_DECLARE_FLAGS(RegisterOptions, RegisterOption)
Q_FLAG(RegisterOptions)
enum UnregisterMode {
UnregisterNode,
UnregisterTree
};
Q_ENUM(UnregisterMode)
enum VirtualObjectRegisterOption {
SingleNode = 0x0,
SubPath = 0x1
// Reserved = 0xff000000
};
Q_DECLARE_FLAGS(VirtualObjectRegisterOptions, VirtualObjectRegisterOption)
enum ConnectionCapability {
UnixFileDescriptorPassing = 0x0001
};
Q_DECLARE_FLAGS(ConnectionCapabilities, ConnectionCapability)
explicit QDBusConnection(const QString &name);
QDBusConnection(const QDBusConnection &other);
QDBusConnection(QDBusConnection &&other) noexcept : d(other.d) { other.d = nullptr; }
QDBusConnection &operator=(QDBusConnection &&other) noexcept { swap(other); return *this; }
QDBusConnection &operator=(const QDBusConnection &other);
~QDBusConnection();
void swap(QDBusConnection &other) noexcept { qt_ptr_swap(d, other.d); }
bool isConnected() const;
QString baseService() const;
QDBusError lastError() const;
QString name() const;
ConnectionCapabilities connectionCapabilities() const;
bool send(const QDBusMessage &message) const;
bool callWithCallback(const QDBusMessage &message, QObject *receiver,
const char *returnMethod, const char *errorMethod,
int timeout = -1) const;
bool callWithCallback(const QDBusMessage &message, QObject *receiver,
const char *slot, int timeout = -1) const;
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode = QDBus::Block,
int timeout = -1) const;
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout = -1) const;
bool connect(const QString &service, const QString &path, const QString &interface,
const QString &name, QObject *receiver, const char *slot);
bool connect(const QString &service, const QString &path, const QString &interface,
const QString &name, const QString& signature,
QObject *receiver, const char *slot);
bool connect(const QString &service, const QString &path, const QString &interface,
const QString &name, const QStringList &argumentMatch, const QString& signature,
QObject *receiver, const char *slot);
bool disconnect(const QString &service, const QString &path, const QString &interface,
const QString &name, QObject *receiver, const char *slot);
bool disconnect(const QString &service, const QString &path, const QString &interface,
const QString &name, const QString& signature,
QObject *receiver, const char *slot);
bool disconnect(const QString &service, const QString &path, const QString &interface,
const QString &name, const QStringList &argumentMatch, const QString& signature,
QObject *receiver, const char *slot);
bool registerObject(const QString &path, QObject *object,
RegisterOptions options = ExportAdaptors);
bool registerObject(const QString &path, const QString &interface, QObject *object,
RegisterOptions options = ExportAdaptors);
void unregisterObject(const QString &path, UnregisterMode mode = UnregisterNode);
QObject *objectRegisteredAt(const QString &path) const;
bool registerVirtualObject(const QString &path, QDBusVirtualObject *object,
VirtualObjectRegisterOption options = SingleNode);
bool registerService(const QString &serviceName);
bool unregisterService(const QString &serviceName);
QDBusConnectionInterface *interface() const;
void *internalPointer() const;
static QDBusConnection connectToBus(BusType type, const QString &name);
static QDBusConnection connectToBus(const QString &address, const QString &name);
static QDBusConnection connectToPeer(const QString &address, const QString &name);
static void disconnectFromBus(const QString &name);
static void disconnectFromPeer(const QString &name);
static QByteArray localMachineId();
static QDBusConnection sessionBus();
static QDBusConnection systemBus();
protected:
explicit QDBusConnection(QDBusConnectionPrivate *dd);
private:
friend class QDBusConnectionPrivate;
QDBusConnectionPrivate *d;
};
Q_DECLARE_SHARED(QDBusConnection)
Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::RegisterOptions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::VirtualObjectRegisterOptions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::ConnectionCapabilities)
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,385 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSCONNECTION_P_H
#define QDBUSCONNECTION_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qdbuserror.h>
#include <qdbusconnection.h>
#include <QtCore/qatomic.h>
#include <QtCore/qhash.h>
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtCore/qreadwritelock.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvarlengtharray.h>
#include "qdbus_symbols_p.h"
#include <qdbusmessage.h>
#include <qdbusservicewatcher.h> // for the WatchMode enum
Q_MOC_INCLUDE(<QtDBus/private/qdbuspendingcall_p.h>)
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusMessage;
class QSocketNotifier;
class QTimerEvent;
class QDBusObjectPrivate;
class QDBusCallDeliveryEvent;
class QDBusActivateObjectEvent;
class QMetaMethod;
class QDBusInterfacePrivate;
struct QDBusMetaObject;
class QDBusAbstractInterface;
class QDBusConnectionInterface;
class QDBusPendingCallPrivate;
class QDBusServer;
#ifndef QT_BOOTSTRAPPED
class QDBusErrorInternal
{
mutable DBusError error;
Q_DISABLE_COPY_MOVE(QDBusErrorInternal)
public:
inline QDBusErrorInternal() { q_dbus_error_init(&error); }
inline ~QDBusErrorInternal() { q_dbus_error_free(&error); }
inline bool operator !() const { return !q_dbus_error_is_set(&error); }
inline operator DBusError *() { q_dbus_error_free(&error); return &error; }
inline operator QDBusError() const { QDBusError err(&error); q_dbus_error_free(&error); return err; }
};
// QDBusConnectionPrivate holds the DBusConnection and
// can have many QDBusConnection objects referring to it
class Q_AUTOTEST_EXPORT QDBusConnectionPrivate: public QObject
{
Q_OBJECT
public:
// structs and enums
enum ConnectionMode { InvalidMode, ServerMode, ClientMode, PeerMode }; // LocalMode
struct Watcher
{
Watcher(): watch(nullptr), read(nullptr), write(nullptr) {}
DBusWatch *watch;
QSocketNotifier *read;
QSocketNotifier *write;
};
struct ArgMatchRules {
QStringList args;
QString arg0namespace;
bool operator==(const ArgMatchRules &other) const {
return args == other.args &&
arg0namespace == other.arg0namespace;
}
};
struct SignalHook
{
inline SignalHook() : obj(nullptr), midx(-1) { }
QString service, path, signature;
QObject* obj;
int midx;
QList<QMetaType> params;
ArgMatchRules argumentMatch;
QByteArray matchRule;
};
enum TreeNodeType {
Object = 0x0,
VirtualObject = 0x01000000
};
struct ObjectTreeNode
{
typedef QList<ObjectTreeNode> DataList;
inline ObjectTreeNode() : obj(nullptr), flags(0) { }
inline ObjectTreeNode(const QString &n) // intentionally implicit
: name(n), obj(nullptr), flags(0) { }
inline bool operator<(const QString &other) const
{ return name < other; }
inline bool operator<(QStringView other) const
{ return name < other; }
inline bool isActive() const
{ return obj || !children.isEmpty(); }
QString name;
QString interfaceName;
union {
QObject *obj;
QDBusVirtualObject *treeNode;
};
int flags;
DataList children;
};
public:
// typedefs
typedef QMultiHash<qintptr, Watcher> WatcherHash;
typedef QHash<int, DBusTimeout *> TimeoutHash;
typedef QList<QDBusMessage> PendingMessageList;
typedef QMultiHash<QString, SignalHook> SignalHookHash;
typedef QHash<QString, QDBusMetaObject* > MetaObjectHash;
typedef QHash<QByteArray, int> MatchRefCountHash;
typedef QList<QDBusPendingCallPrivate *> PendingCallList;
struct WatchedServiceData {
WatchedServiceData() : refcount(0) {}
WatchedServiceData(const QString &owner, int refcount = 0)
: owner(owner), refcount(refcount)
{}
QString owner;
int refcount;
};
typedef QHash<QString, WatchedServiceData> WatchedServicesHash;
public:
// public methods are entry points from other objects
explicit QDBusConnectionPrivate(QObject *parent = nullptr);
~QDBusConnectionPrivate();
void createBusService();
void setPeer(DBusConnection *connection, const QDBusErrorInternal &error);
void setConnection(DBusConnection *connection, const QDBusErrorInternal &error);
void setServer(QDBusServer *object, DBusServer *server, const QDBusErrorInternal &error);
void closeConnection();
QString getNameOwner(const QString &service);
bool shouldWatchService(const QString &service);
void watchService(const QString &service, QDBusServiceWatcher::WatchMode mode,
QObject *obj, const char *member);
void unwatchService(const QString &service, QDBusServiceWatcher::WatchMode mode,
QObject *obj, const char *member);
bool send(const QDBusMessage &message);
QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1);
QDBusMessage sendWithReplyLocal(const QDBusMessage &message);
QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *returnMethod, const char *errorMethod,int timeout = -1);
bool connectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
bool disconnectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
bool connectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const ArgMatchRules &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
bool disconnectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const ArgMatchRules &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
void registerObject(const ObjectTreeNode *node);
void unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode);
void connectRelay(const QString &service,
const QString &path, const QString &interface,
QDBusAbstractInterface *receiver, const QMetaMethod &signal);
void disconnectRelay(const QString &service,
const QString &path, const QString &interface,
QDBusAbstractInterface *receiver, const QMetaMethod &signal);
void registerService(const QString &serviceName);
void unregisterService(const QString &serviceName);
bool handleMessage(const QDBusMessage &msg);
QDBusMetaObject *findMetaObject(const QString &service, const QString &path,
const QString &interface, QDBusError &error);
void postEventToThread(int action, QObject *target, QEvent *event);
private:
void checkThread();
bool handleError(const QDBusErrorInternal &error);
void handleSignal(const QString &key, const QDBusMessage &msg);
void handleSignal(const QDBusMessage &msg);
void handleObjectCall(const QDBusMessage &message);
void activateSignal(const SignalHook& hook, const QDBusMessage &msg);
void activateObject(ObjectTreeNode &node, const QDBusMessage &msg, int pathStartPos);
bool activateInternalFilters(const ObjectTreeNode &node, const QDBusMessage &msg);
bool activateCall(QObject *object, int flags, const QDBusMessage &msg);
void sendInternal(QDBusPendingCallPrivate *pcall, void *msg, int timeout);
void sendError(const QDBusMessage &msg, QDBusError::ErrorType code);
void deliverCall(QObject *object, int flags, const QDBusMessage &msg,
const QList<QMetaType> &metaTypes, int slotIdx);
SignalHookHash::Iterator removeSignalHookNoLock(SignalHookHash::Iterator it);
void collectAllObjects(ObjectTreeNode &node, QSet<QObject *> &set);
bool isServiceRegisteredByThread(const QString &serviceName);
QString getNameOwnerNoCache(const QString &service);
void watchForDBusDisconnection();
void _q_newConnection(QDBusConnectionPrivate *newConnection);
void handleAuthentication();
protected:
void timerEvent(QTimerEvent *e) override;
public slots:
// public slots
void setDispatchEnabled(bool enable);
void doDispatch();
void socketRead(qintptr);
void socketWrite(qintptr);
void objectDestroyed(QObject *o);
void relaySignal(QObject *obj, const QMetaObject *, int signalId, const QVariantList &args);
bool addSignalHook(const QString &key, const SignalHook &hook);
bool removeSignalHook(const QString &key, const SignalHook &hook);
private slots:
void serviceOwnerChangedNoLock(const QString &name, const QString &oldOwner, const QString &newOwner);
void registerServiceNoLock(const QString &serviceName);
void unregisterServiceNoLock(const QString &serviceName);
void handleDBusDisconnection();
signals:
void dispatchStatusChanged();
void spyHooksFinished(const QDBusMessage &msg);
void messageNeedsSending(QDBusPendingCallPrivate *pcall, void *msg, int timeout = -1);
bool signalNeedsConnecting(const QString &key, const QDBusConnectionPrivate::SignalHook &hook);
bool signalNeedsDisconnecting(const QString &key, const QDBusConnectionPrivate::SignalHook &hook);
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
void callWithCallbackFailed(const QDBusError &error, const QDBusMessage &message);
void newServerConnection(QDBusConnectionPrivate *newConnection);
public:
QAtomicInt ref;
QAtomicInt capabilities;
QDBusConnection::ConnectionCapabilities connectionCapabilities() const
{
return (QDBusConnection::ConnectionCapabilities)capabilities.loadRelaxed();
}
QString name; // this connection's name
QString baseService; // this connection's base service
QStringList serverConnectionNames;
ConnectionMode mode;
union {
QDBusConnectionInterface *busService;
QDBusServer *serverObject;
};
union {
DBusConnection *connection;
DBusServer *server;
};
WatcherHash watchers;
TimeoutHash timeouts;
PendingMessageList pendingMessages;
// the master lock protects our own internal state
QReadWriteLock lock;
QDBusError lastError;
QStringList serviceNames;
WatchedServicesHash watchedServices;
SignalHookHash signalHooks;
MatchRefCountHash matchRefCounts;
ObjectTreeNode rootNode;
MetaObjectHash cachedMetaObjects;
PendingCallList pendingCalls;
bool anonymousAuthenticationAllowed;
bool dispatchEnabled; // protected by the dispatch lock, not the main lock
bool isAuthenticated;
public:
// static methods
static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<QMetaType> &params,
QString &errorMsg);
static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
const QString &service,
const QString &path, const QString &interface, const QString &name,
const ArgMatchRules &argMatch,
QObject *receiver, const char *signal, int minMIdx,
bool buildSignature);
static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
static QDBusCallDeliveryEvent *prepareReply(QDBusConnectionPrivate *target, QObject *object,
int idx, const QList<QMetaType> &metaTypes,
const QDBusMessage &msg);
static void processFinishedCall(QDBusPendingCallPrivate *call);
static QDBusConnectionPrivate *d(const QDBusConnection& q) { return q.d; }
static QDBusConnection q(QDBusConnectionPrivate *connection) { return QDBusConnection(connection); }
friend class QDBusActivateObjectEvent;
friend class QDBusCallDeliveryEvent;
friend class QDBusServer;
};
// in qdbusmisc.cpp
extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg);
# endif // QT_BOOTSTRAPPED
extern Q_DBUS_EXPORT int qDBusParametersForMethod(const QList<QByteArray> &parameters,
QList<QMetaType> &metaTypes, QString &errorMsg);
extern Q_DBUS_EXPORT bool qDBusCheckAsyncTag(const char *tag);
#ifndef QT_BOOTSTRAPPED
extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name);
extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
// in qdbusinternalfilters.cpp
extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node, const QString &path);
extern QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg);
extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg);
extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg);
// can be replaced with a lambda in Qt 5.7
class QDBusConnectionDispatchEnabler : public QObject
{
Q_OBJECT
QDBusConnectionPrivate *con;
public:
QDBusConnectionDispatchEnabler(QDBusConnectionPrivate *con) : con(con) {}
public slots:
void execute()
{
// This call cannot race with something disabling dispatch only because dispatch is
// never re-disabled from Qt code on an in-use connection once it has been enabled.
QMetaObject::invokeMethod(con, "setDispatchEnabled", Qt::QueuedConnection, Q_ARG(bool, true));
if (!con->ref.deref())
con->deleteLater();
deleteLater();
}
};
#endif // QT_BOOTSTRAPPED
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,413 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusconnectioninterface.h"
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QMetaMethod>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include "qdbusutil_p.h" // for the DBUS_* constants
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
/*
* Implementation of interface class QDBusConnectionInterface
*/
/*!
\class QDBusConnectionInterface
\inmodule QtDBus
\since 4.2
\brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
The D-Bus bus server daemon provides one special interface \c
org.freedesktop.DBus that allows clients to access certain
properties of the bus, such as the current list of clients
connected. The QDBusConnectionInterface class provides access to that
interface.
The most common uses of this class are to register and unregister
service names on the bus using the registerService() and
unregisterService() functions, query about existing names using
the isServiceRegistered(), registeredServiceNames() and
serviceOwner() functions, and to receive notification that a
client has registered or de-registered through the
serviceRegistered(), serviceUnregistered() and serviceOwnerChanged()
signals.
*/
/*!
\enum QDBusConnectionInterface::ServiceQueueOptions
Flags for determining how a service registration should behave, in
case the service name is already registered.
\value DontQueueService If an application requests a name that
is already owned, no queueing will be
performed. The registeredService()
call will simply fail.
This is the default.
\value QueueService Attempts to register the requested
service, but do not try to replace it
if another application already has it
registered. Instead, simply put this
application in queue, until it is
given up. The serviceRegistered()
signal will be emitted when that
happens.
\value ReplaceExistingService If another application already has
the service name registered, attempt
to replace it.
\sa ServiceReplacementOptions
*/
/*!
\enum QDBusConnectionInterface::ServiceReplacementOptions
Flags for determining if the D-Bus server should allow another
application to replace a name that this application has registered
with the ReplaceExistingService option.
The possible values are:
\value DontAllowReplacement Do not allow another application to
replace us. The service must be
explicitly unregistered with
unregisterService() for another
application to acquire it.
This is the default.
\value AllowReplacement Allow other applications to replace us
with the ReplaceExistingService option
to registerService() without
intervention. If that happens, the
serviceUnregistered() signal will be
emitted.
\sa ServiceQueueOptions
*/
/*!
\enum QDBusConnectionInterface::RegisterServiceReply
The possible return values from registerService():
\value ServiceNotRegistered The call failed and the service name was not registered.
\value ServiceRegistered The caller is now the owner of the service name.
\value ServiceQueued The caller specified the QueueService flag and the
service was already registered, so we are in queue.
The serviceRegistered() signal will be emitted when the service is
acquired by this application.
*/
/*!
\internal
*/
const char *QDBusConnectionInterface::staticInterfaceName()
{ return "org.freedesktop.DBus"; }
/*!
\internal
*/
QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
QObject *parent)
: QDBusAbstractInterface(QDBusUtil::dbusService(),
QDBusUtil::dbusPath(),
DBUS_INTERFACE_DBUS, connection, parent)
{
connect(this, &QDBusConnectionInterface::NameAcquired, this, emit &QDBusConnectionInterface::serviceRegistered);
connect(this, &QDBusConnectionInterface::NameLost, this, emit &QDBusConnectionInterface::serviceUnregistered);
connect(this, &QDBusConnectionInterface::NameOwnerChanged,
this, emit &QDBusConnectionInterface::serviceOwnerChanged);
}
/*!
\internal
*/
QDBusConnectionInterface::~QDBusConnectionInterface()
{
}
/*!
Returns the unique connection name of the primary owner of the
name \a name. If the requested name doesn't have an owner, returns
a \c org.freedesktop.DBus.Error.NameHasNoOwner error.
*/
QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
{
return internalConstCall(QDBus::AutoDetect, "GetNameOwner"_L1, QList<QVariant>() << name);
}
/*!
\property QDBusConnectionInterface::registeredServiceNames
\brief holds the registered service names
Lists all names currently registered on the bus.
*/
QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
{
return internalConstCall(QDBus::AutoDetect, "ListNames"_L1);
}
/*!
\property QDBusConnectionInterface::activatableServiceNames
\brief holds the activatable service names
\since 5.14
Lists all names that can be activated on the bus.
*/
QDBusReply<QStringList> QDBusConnectionInterface::activatableServiceNames() const
{
return internalConstCall(QDBus::AutoDetect, "ListActivatableNames"_L1);
}
/*!
Returns \c true if the service name \a serviceName has is currently
registered.
*/
QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
{
return internalConstCall(QDBus::AutoDetect, "NameHasOwner"_L1,
QList<QVariant>() << serviceName);
}
/*!
Returns the Unix Process ID (PID) for the process currently
holding the bus service \a serviceName.
*/
QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
{
return internalConstCall(QDBus::AutoDetect, "GetConnectionUnixProcessID"_L1,
QList<QVariant>() << serviceName);
}
/*!
Returns the Unix User ID (UID) for the process currently holding
the bus service \a serviceName.
*/
QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
{
return internalConstCall(QDBus::AutoDetect, "GetConnectionUnixUser"_L1,
QList<QVariant>() << serviceName);
}
/*!
Requests that the bus start the service given by the name \a name.
*/
QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
{
return call("StartServiceByName"_L1, name, uint(0));
}
/*!
Requests to register the service name \a serviceName on the
bus. The \a qoption flag specifies how the D-Bus server should behave
if \a serviceName is already registered. The \a roption flag
specifies if the server should allow another application to
replace our registered name.
If the service registration succeeds, the serviceRegistered()
signal will be emitted. If we are placed in queue, the signal will
be emitted when we obtain the name. If \a roption is
AllowReplacement, the serviceUnregistered() signal will be emitted
if another application replaces this one.
\sa unregisterService()
*/
QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
QDBusConnectionInterface::registerService(const QString &serviceName,
ServiceQueueOptions qoption,
ServiceReplacementOptions roption)
{
// reconstruct the low-level flags
uint flags = 0;
switch (qoption) {
case DontQueueService:
flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
break;
case QueueService:
flags = 0;
break;
case ReplaceExistingService:
flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
break;
}
switch (roption) {
case DontAllowReplacement:
break;
case AllowReplacement:
flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
break;
}
QDBusMessage reply = call("RequestName"_L1, serviceName, flags);
// qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
// convert the low-level flags to something that we can use
if (reply.type() == QDBusMessage::ReplyMessage) {
uint code = 0;
switch (reply.arguments().at(0).toUInt()) {
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
code = uint(ServiceRegistered);
break;
case DBUS_REQUEST_NAME_REPLY_EXISTS:
code = uint(ServiceNotRegistered);
break;
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
code = uint(ServiceQueued);
break;
}
reply.setArguments(QVariantList() << code);
}
return reply;
}
/*!
Releases the claim on the bus service name \a serviceName, that
had been previously registered with registerService(). If this
application had ownership of the name, it will be released for
other applications to claim. If it only had the name queued, it
gives up its position in the queue.
*/
QDBusReply<bool>
QDBusConnectionInterface::unregisterService(const QString &serviceName)
{
QDBusMessage reply = call("ReleaseName"_L1, serviceName);
if (reply.type() == QDBusMessage::ReplyMessage) {
bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
reply.setArguments(QVariantList() << success);
}
return reply;
}
/*!
\internal
*/
void QDBusConnectionInterface::connectNotify(const QMetaMethod &signal)
{
// translate the signal names to what we really want
// this avoids setting hooks for signals that don't exist on the bus
static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
if (signal == serviceRegisteredSignal)
QDBusAbstractInterface::connectNotify(NameAcquiredSignal);
else if (signal == serviceUnregisteredSignal)
QDBusAbstractInterface::connectNotify(NameLostSignal);
else if (signal == serviceOwnerChangedSignal) {
static bool warningPrinted = false;
if (!warningPrinted) {
qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
warningPrinted = true;
}
QDBusAbstractInterface::connectNotify(NameOwnerChangedSignal);
}
}
/*!
\internal
*/
void QDBusConnectionInterface::disconnectNotify(const QMetaMethod &signal)
{
// translate the signal names to what we really want
// this avoids setting hooks for signals that don't exist on the bus
static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
if (signal == serviceRegisteredSignal)
QDBusAbstractInterface::disconnectNotify(NameAcquiredSignal);
else if (signal == serviceUnregisteredSignal)
QDBusAbstractInterface::disconnectNotify(NameLostSignal);
else if (signal == serviceOwnerChangedSignal)
QDBusAbstractInterface::disconnectNotify(NameOwnerChangedSignal);
}
// signals
/*!
\fn QDBusConnectionInterface::serviceRegistered(const QString &service)
This signal is emitted by the D-Bus server when the bus service
name (unique connection name or well-known service name) given by
\a service is acquired by this application.
Acquisition happens after this application has requested a name using
registerService().
*/
/*!
\fn QDBusConnectionInterface::serviceUnregistered(const QString &service)
This signal is emitted by the D-Bus server when this application
loses ownership of the bus service name given by \a service.
*/
/*!
\fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
\deprecated
Use QDBusServiceWatcher instead.
This signal is emitted by the D-Bus server whenever a service
ownership change happens in the bus, including apparition and
disparition of names.
This signal means the application \a oldOwner lost ownership of
bus name \a name to application \a newOwner. If \a oldOwner is an
empty string, it means the name \a name has just been created; if
\a newOwner is empty, the name \a name has no current owner and is
no longer available.
\note connecting to this signal will make the application listen for and
receive every single service ownership change on the bus. Depending on
how many services are running, this make the application be activated to
receive more signals than it needs. To avoid this problem, use the
QDBusServiceWatcher class, which can listen for specific changes.
*/
/*!
\fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
This signal is emitted when there is an error during a
QDBusConnection::callWithCallback(). \a error specifies the error.
\a call is the message that couldn't be delivered.
\sa QDBusConnection::callWithCallback()
*/
QT_END_NAMESPACE
#include "moc_qdbusconnectioninterface.cpp"
#endif // QT_NO_DBUS

View File

@ -0,0 +1,94 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSCONNECTIONINTERFACE_H
#define QDBUSCONNECTIONINTERFACE_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qstringlist.h>
#include <QtDBus/qdbusabstractinterface.h>
#include <QtDBus/qdbusreply.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnection;
class QString;
class QByteArray;
/*
* Proxy class for interface org.freedesktop.DBus
*/
class Q_DBUS_EXPORT QDBusConnectionInterface: public QDBusAbstractInterface
{
Q_OBJECT
friend class QDBusConnectionPrivate;
static inline const char *staticInterfaceName();
explicit QDBusConnectionInterface(const QDBusConnection &connection, QObject *parent);
~QDBusConnectionInterface();
Q_PROPERTY(QDBusReply<QStringList> registeredServiceNames READ registeredServiceNames)
Q_PROPERTY(QDBusReply<QStringList> activatableServiceNames READ activatableServiceNames)
public:
enum ServiceQueueOptions {
DontQueueService,
QueueService,
ReplaceExistingService
};
Q_ENUM(ServiceQueueOptions)
enum ServiceReplacementOptions {
DontAllowReplacement,
AllowReplacement
};
Q_ENUM(ServiceReplacementOptions)
enum RegisterServiceReply {
ServiceNotRegistered = 0,
ServiceRegistered,
ServiceQueued
};
Q_ENUM(RegisterServiceReply)
public Q_SLOTS:
QDBusReply<QStringList> registeredServiceNames() const;
QDBusReply<QStringList> activatableServiceNames() const;
QDBusReply<bool> isServiceRegistered(const QString &serviceName) const;
QDBusReply<QString> serviceOwner(const QString &name) const;
QDBusReply<bool> unregisterService(const QString &serviceName);
QDBusReply<QDBusConnectionInterface::RegisterServiceReply> registerService(const QString &serviceName,
ServiceQueueOptions qoption = DontQueueService,
ServiceReplacementOptions roption = DontAllowReplacement);
QDBusReply<uint> servicePid(const QString &serviceName) const;
QDBusReply<uint> serviceUid(const QString &serviceName) const;
QDBusReply<void> startService(const QString &name);
Q_SIGNALS:
void serviceRegistered(const QString &service);
void serviceUnregistered(const QString &service);
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
void callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call);
#ifndef Q_QDOC
// internal signals
// do not use
void NameAcquired(const QString &);
void NameLost(const QString &);
void NameOwnerChanged(const QString &, const QString &, const QString &);
protected:
void connectNotify(const QMetaMethod &) override;
void disconnectNotify(const QMetaMethod &) override;
#endif
};
QT_END_NAMESPACE
Q_DECLARE_BUILTIN_METATYPE(UInt, QMetaType::UInt, QDBusConnectionInterface::RegisterServiceReply)
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,90 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSCONNECTIONMANAGER_P_H
#define QDBUSCONNECTIONMANAGER_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include "qdbusconnection_p.h"
#include "private/qthread_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnectionManager : public QDaemonThread
{
Q_OBJECT
struct ConnectionRequestData;
public:
QDBusConnectionManager();
~QDBusConnectionManager();
static QDBusConnectionManager* instance();
QDBusConnectionPrivate *busConnection(QDBusConnection::BusType type);
QDBusConnectionPrivate *connection(const QString &name) const;
void removeConnection(const QString &name);
void setConnection(const QString &name, QDBusConnectionPrivate *c);
QDBusConnectionPrivate *connectToBus(QDBusConnection::BusType type, const QString &name, bool suspendedDelivery);
QDBusConnectionPrivate *connectToBus(const QString &address, const QString &name);
QDBusConnectionPrivate *connectToPeer(const QString &address, const QString &name);
mutable QMutex mutex;
signals:
void connectionRequested(ConnectionRequestData *);
void serverRequested(const QString &address, void *server);
protected:
void run() override;
private:
void executeConnectionRequest(ConnectionRequestData *data);
void createServer(const QString &address, void *server);
QHash<QString, QDBusConnectionPrivate *> connectionHash;
QMutex defaultBusMutex;
QDBusConnectionPrivate *defaultBuses[2];
mutable QMutex senderMutex;
QString senderName; // internal; will probably change
};
// TODO: move into own header and use Q_MOC_INCLUDE
struct QDBusConnectionManager::ConnectionRequestData
{
enum RequestType {
ConnectToStandardBus,
ConnectToBusByAddress,
ConnectToPeerByAddress
} type;
union {
QDBusConnection::BusType busType;
const QString *busAddress;
};
const QString *name;
QDBusConnectionPrivate *result;
bool suspendedDelivery;
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

170
src/dbus/qdbuscontext.cpp Normal file
View File

@ -0,0 +1,170 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusmessage.h"
#include "qdbusconnection.h"
#include "qdbusabstractadaptor.h"
#include "qdbuscontext.h"
#include "qdbuscontext_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
QDBusContextPrivate *QDBusContextPrivate::set(QObject *obj, QDBusContextPrivate *newContext)
{
// determine if this is an adaptor or not
if (qobject_cast<QDBusAbstractAdaptor *>(obj))
obj = obj->parent();
Q_ASSERT(obj);
void *ptr = obj->qt_metacast("QDBusContext");
QDBusContext *q_ptr = reinterpret_cast<QDBusContext *>(ptr);
if (q_ptr) {
QDBusContextPrivate *old = q_ptr->d_ptr;
q_ptr->d_ptr = newContext;
return old;
}
return nullptr;
}
/*!
\since 4.3
\class QDBusContext
\inmodule QtDBus
\brief The QDBusContext class allows slots to determine the D-Bus context of the calls.
When a slot is called in an object due to a signal delivery or due
to a remote method call, it is sometimes necessary to know the
context in which that happened. In particular, if the slot
determines that it wants to send the reply at a later opportunity
or if it wants to reply with an error, the context is needed.
The QDBusContext class is an alternative to accessing the context
that doesn't involve modifying the code generated by the \l
{Qt D-Bus XML compiler (qdbusxml2cpp)}.
QDBusContext is used by subclassing it from the objects being
exported using QDBusConnection::registerObject(). The following
example illustrates the usage:
\snippet code/src_qdbus_qdbuscontext.cpp 0
The example illustrates the two typical uses, that of sending
error replies and that of delayed replies.
Note: do not subclass QDBusContext and QDBusAbstractAdaptor at the
same time. QDBusContext should appear in the real object, not the
adaptor. If it's necessary from the adaptor code to determine the
context, use a public inheritance and access the functions via
QObject::parent().
*/
/*!
Constructs an empty QDBusContext.
*/
QDBusContext::QDBusContext()
: d_ptr(nullptr)
{
}
/*!
An empty destructor.
*/
QDBusContext::~QDBusContext()
{
}
/*!
Returns \c true if we are processing a D-Bus call. If this function
returns \c true, the rest of the functions in this class are
available.
Accessing those functions when this function returns \c false is
undefined and may lead to crashes.
*/
bool QDBusContext::calledFromDBus() const
{
return d_ptr;
}
/*!
Returns the connection from which this call was received.
*/
QDBusConnection QDBusContext::connection() const
{
return d_ptr->connection;
}
/*!
Returns the message that generated this call.
*/
const QDBusMessage &QDBusContext::message() const
{
return d_ptr->message;
}
/*!
Returns \c true if this call will have a delayed reply.
\sa setDelayedReply()
*/
bool QDBusContext::isDelayedReply() const
{
return message().isDelayedReply();
}
/*!
Sets whether this call will have a delayed reply or not.
If \a enable is false, Qt D-Bus will automatically generate a reply
back to the caller, if needed, as soon as the called slot returns.
If \a enable is true, Qt D-Bus will not generate automatic
replies. It will also ignore the return value from the slot and
any output parameters. Instead, the called object is responsible
for storing the incoming message and send a reply or error at a
later time.
Failing to send a reply will result in an automatic timeout error
being generated by D-Bus.
*/
void QDBusContext::setDelayedReply(bool enable) const
{
message().setDelayedReply(enable);
}
/*!
Sends an error \a name as a reply to the caller. The optional \a
msg parameter is a human-readable text explaining the failure.
If an error is sent, the return value and any output parameters
from the called slot will be ignored by Qt D-Bus.
*/
void QDBusContext::sendErrorReply(const QString &name, const QString &msg) const
{
setDelayedReply(true);
connection().send(message().createErrorReply(name, msg));
}
/*!
\overload
Sends an error \a type as a reply to the caller. The optional \a
msg parameter is a human-readable text explaining the failure.
If an error is sent, the return value and any output parameters
from the called slot will be ignored by Qt D-Bus.
*/
void QDBusContext::sendErrorReply(QDBusError::ErrorType type, const QString &msg) const
{
setDelayedReply(true);
connection().send(message().createErrorReply(type, msg));
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

45
src/dbus/qdbuscontext.h Normal file
View File

@ -0,0 +1,45 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSCONTEXT_H
#define QDBUSCONTEXT_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qstring.h>
#include <QtDBus/qdbuserror.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnection;
class QDBusMessage;
class QDBusContextPrivate;
class Q_DBUS_EXPORT QDBusContext
{
public:
QDBusContext();
~QDBusContext();
bool calledFromDBus() const;
QDBusConnection connection() const;
const QDBusMessage &message() const;
// convenience methods
bool isDelayedReply() const;
// yes, they are const, so that you can use them even from const methods
void setDelayedReply(bool enable) const;
void sendErrorReply(const QString &name, const QString &msg = QString()) const;
void sendErrorReply(QDBusError::ErrorType type, const QString &msg = QString()) const;
private:
QDBusContextPrivate *d_ptr;
friend class QDBusContextPrivate;
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

45
src/dbus/qdbuscontext_p.h Normal file
View File

@ -0,0 +1,45 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSCONTEXT_P_H
#define QDBUSCONTEXT_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusMessage;
class QDBusConnection;
class QDBusContext;
class QDBusContextPrivate
{
public:
inline QDBusContextPrivate(const QDBusConnection &conn, const QDBusMessage &msg)
: connection(conn), message(msg) {}
QDBusConnection connection;
const QDBusMessage &message;
static QDBusContextPrivate *set(QObject *obj, QDBusContextPrivate *newContext);
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,401 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusargument_p.h"
#include "qdbusconnection.h"
#include <memory>
#include <stdlib.h>
QT_BEGIN_NAMESPACE
template <typename T>
static inline T qIterGet(DBusMessageIter *it)
{
// Use a union of expected and largest type q_dbus_message_iter_get_basic
// will return to ensure reading the wrong basic type does not result in
// stack overwrite
union {
// The value to be extracted
T t;
// Largest type that q_dbus_message_iter_get_basic will return
// according to dbus_message_iter_get_basic API documentation
dbus_uint64_t maxValue;
// A pointer to ensure no stack overwrite in case there is a platform
// where sizeof(void*) > sizeof(dbus_uint64_t)
void* ptr;
} value;
// Initialize the value in case a narrower type is extracted to it.
// Note that the result of extracting a narrower type in place of a wider
// one and vice-versa will be platform-dependent.
value.t = T();
q_dbus_message_iter_get_basic(it, &value);
q_dbus_message_iter_next(it);
return value.t;
}
QDBusDemarshaller::~QDBusDemarshaller()
{
}
inline QString QDBusDemarshaller::currentSignature()
{
char *sig = q_dbus_message_iter_get_signature(&iterator);
QString retval = QString::fromUtf8(sig);
q_dbus_free(sig);
return retval;
}
inline uchar QDBusDemarshaller::toByte()
{
return qIterGet<uchar>(&iterator);
}
inline bool QDBusDemarshaller::toBool()
{
return bool(qIterGet<dbus_bool_t>(&iterator));
}
inline ushort QDBusDemarshaller::toUShort()
{
return qIterGet<dbus_uint16_t>(&iterator);
}
inline short QDBusDemarshaller::toShort()
{
return qIterGet<dbus_int16_t>(&iterator);
}
inline int QDBusDemarshaller::toInt()
{
return qIterGet<dbus_int32_t>(&iterator);
}
inline uint QDBusDemarshaller::toUInt()
{
return qIterGet<dbus_uint32_t>(&iterator);
}
inline qlonglong QDBusDemarshaller::toLongLong()
{
return qIterGet<qlonglong>(&iterator);
}
inline qulonglong QDBusDemarshaller::toULongLong()
{
return qIterGet<qulonglong>(&iterator);
}
inline double QDBusDemarshaller::toDouble()
{
return qIterGet<double>(&iterator);
}
inline QString QDBusDemarshaller::toStringUnchecked()
{
return QString::fromUtf8(qIterGet<char *>(&iterator));
}
inline QString QDBusDemarshaller::toString()
{
if (isCurrentTypeStringLike())
return toStringUnchecked();
else
return QString();
}
inline QDBusObjectPath QDBusDemarshaller::toObjectPathUnchecked()
{
return QDBusObjectPath(QString::fromUtf8(qIterGet<char *>(&iterator)));
}
inline QDBusObjectPath QDBusDemarshaller::toObjectPath()
{
if (isCurrentTypeStringLike())
return toObjectPathUnchecked();
else
return QDBusObjectPath();
}
inline QDBusSignature QDBusDemarshaller::toSignatureUnchecked()
{
return QDBusSignature(QString::fromUtf8(qIterGet<char *>(&iterator)));
}
inline QDBusSignature QDBusDemarshaller::toSignature()
{
if (isCurrentTypeStringLike())
return toSignatureUnchecked();
else
return QDBusSignature();
}
inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor()
{
QDBusUnixFileDescriptor fd;
fd.giveFileDescriptor(qIterGet<dbus_int32_t>(&iterator));
return fd;
}
inline QDBusVariant QDBusDemarshaller::toVariant()
{
QDBusDemarshaller sub(capabilities);
sub.message = q_dbus_message_ref(message);
q_dbus_message_iter_recurse(&iterator, &sub.iterator);
q_dbus_message_iter_next(&iterator);
return QDBusVariant( sub.toVariantInternal() );
}
QDBusArgument::ElementType QDBusDemarshaller::currentType()
{
switch (q_dbus_message_iter_get_arg_type(&iterator)) {
case DBUS_TYPE_BYTE:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_DOUBLE:
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_SIGNATURE:
return QDBusArgument::BasicType;
case DBUS_TYPE_VARIANT:
return QDBusArgument::VariantType;
case DBUS_TYPE_ARRAY:
switch (q_dbus_message_iter_get_element_type(&iterator)) {
case DBUS_TYPE_BYTE:
case DBUS_TYPE_STRING:
// QByteArray and QStringList
return QDBusArgument::BasicType;
case DBUS_TYPE_DICT_ENTRY:
return QDBusArgument::MapType;
default:
return QDBusArgument::ArrayType;
}
case DBUS_TYPE_STRUCT:
return QDBusArgument::StructureType;
case DBUS_TYPE_DICT_ENTRY:
return QDBusArgument::MapEntryType;
case DBUS_TYPE_UNIX_FD:
return capabilities & QDBusConnection::UnixFileDescriptorPassing ?
QDBusArgument::BasicType : QDBusArgument::UnknownType;
case DBUS_TYPE_INVALID:
return QDBusArgument::UnknownType;
// default:
// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
// q_dbus_message_iter_get_arg_type(&iterator),
// q_dbus_message_iter_get_arg_type(&iterator));
}
return QDBusArgument::UnknownType;
}
QVariant QDBusDemarshaller::toVariantInternal()
{
switch (q_dbus_message_iter_get_arg_type(&iterator)) {
case DBUS_TYPE_BYTE:
return QVariant::fromValue(toByte());
case DBUS_TYPE_INT16:
return QVariant::fromValue(toShort());
case DBUS_TYPE_UINT16:
return QVariant::fromValue(toUShort());
case DBUS_TYPE_INT32:
return toInt();
case DBUS_TYPE_UINT32:
return toUInt();
case DBUS_TYPE_DOUBLE:
return toDouble();
case DBUS_TYPE_BOOLEAN:
return toBool();
case DBUS_TYPE_INT64:
return toLongLong();
case DBUS_TYPE_UINT64:
return toULongLong();
case DBUS_TYPE_STRING:
return toStringUnchecked();
case DBUS_TYPE_OBJECT_PATH:
return QVariant::fromValue(toObjectPathUnchecked());
case DBUS_TYPE_SIGNATURE:
return QVariant::fromValue(toSignatureUnchecked());
case DBUS_TYPE_VARIANT:
return QVariant::fromValue(toVariant());
case DBUS_TYPE_ARRAY:
switch (q_dbus_message_iter_get_element_type(&iterator)) {
case DBUS_TYPE_BYTE:
// QByteArray
return toByteArrayUnchecked();
case DBUS_TYPE_STRING:
return toStringListUnchecked();
case DBUS_TYPE_DICT_ENTRY:
return QVariant::fromValue(duplicate());
default:
return QVariant::fromValue(duplicate());
}
case DBUS_TYPE_STRUCT:
return QVariant::fromValue(duplicate());
case DBUS_TYPE_UNIX_FD:
if (capabilities & QDBusConnection::UnixFileDescriptorPassing)
return QVariant::fromValue(toUnixFileDescriptor());
Q_FALLTHROUGH();
default:
// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
// q_dbus_message_iter_get_arg_type(&iterator),
// q_dbus_message_iter_get_arg_type(&iterator));
char *ptr = nullptr;
ptr += q_dbus_message_iter_get_arg_type(&iterator);
q_dbus_message_iter_next(&iterator);
// I hope you never dereference this pointer!
return QVariant::fromValue<void *>(ptr);
};
}
bool QDBusDemarshaller::isCurrentTypeStringLike()
{
const int type = q_dbus_message_iter_get_arg_type(&iterator);
switch (type) {
case DBUS_TYPE_STRING: //FALLTHROUGH
case DBUS_TYPE_OBJECT_PATH: //FALLTHROUGH
case DBUS_TYPE_SIGNATURE:
return true;
default:
return false;
}
}
QStringList QDBusDemarshaller::toStringListUnchecked()
{
QStringList list;
QDBusDemarshaller sub(capabilities);
q_dbus_message_iter_recurse(&iterator, &sub.iterator);
q_dbus_message_iter_next(&iterator);
while (!sub.atEnd())
list.append(sub.toStringUnchecked());
return list;
}
QStringList QDBusDemarshaller::toStringList()
{
if (q_dbus_message_iter_get_arg_type(&iterator) == DBUS_TYPE_ARRAY
&& q_dbus_message_iter_get_element_type(&iterator) == DBUS_TYPE_STRING)
return toStringListUnchecked();
else
return QStringList();
}
QByteArray QDBusDemarshaller::toByteArrayUnchecked()
{
DBusMessageIter sub;
q_dbus_message_iter_recurse(&iterator, &sub);
q_dbus_message_iter_next(&iterator);
int len;
char* data;
q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
return QByteArray(data,len);
}
QByteArray QDBusDemarshaller::toByteArray()
{
if (q_dbus_message_iter_get_arg_type(&iterator) == DBUS_TYPE_ARRAY
&& q_dbus_message_iter_get_element_type(&iterator) == DBUS_TYPE_BYTE) {
return toByteArrayUnchecked();
}
return QByteArray();
}
bool QDBusDemarshaller::atEnd()
{
// dbus_message_iter_has_next is broken if the list has one single element
return q_dbus_message_iter_get_arg_type(&iterator) == DBUS_TYPE_INVALID;
}
inline QDBusDemarshaller *QDBusDemarshaller::beginStructure()
{
return beginCommon();
}
inline QDBusDemarshaller *QDBusDemarshaller::beginArray()
{
return beginCommon();
}
inline QDBusDemarshaller *QDBusDemarshaller::beginMap()
{
return beginCommon();
}
inline QDBusDemarshaller *QDBusDemarshaller::beginMapEntry()
{
return beginCommon();
}
QDBusDemarshaller *QDBusDemarshaller::beginCommon()
{
QDBusDemarshaller *d = new QDBusDemarshaller(capabilities);
d->parent = this;
d->message = q_dbus_message_ref(message);
// recurse
q_dbus_message_iter_recurse(&iterator, &d->iterator);
q_dbus_message_iter_next(&iterator);
return d;
}
inline QDBusDemarshaller *QDBusDemarshaller::endStructure()
{
return endCommon();
}
inline QDBusDemarshaller *QDBusDemarshaller::endArray()
{
return endCommon();
}
inline QDBusDemarshaller *QDBusDemarshaller::endMap()
{
return endCommon();
}
inline QDBusDemarshaller *QDBusDemarshaller::endMapEntry()
{
return endCommon();
}
QDBusDemarshaller *QDBusDemarshaller::endCommon()
{
QDBusDemarshaller *retval = parent;
delete this;
return retval;
}
QDBusArgument QDBusDemarshaller::duplicate()
{
std::unique_ptr<QDBusDemarshaller> d(new QDBusDemarshaller(capabilities));
d->iterator = iterator;
d->message = q_dbus_message_ref(message);
q_dbus_message_iter_next(&iterator);
return QDBusArgumentPrivate::create(d.release());
}
QT_END_NAMESPACE

333
src/dbus/qdbuserror.cpp Normal file
View File

@ -0,0 +1,333 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbuserror.h"
#include <qdebug.h>
#include <qvarlengtharray.h>
#include <private/qoffsetstringarray_p.h>
#ifndef QT_BOOTSTRAPPED
#include "qdbus_symbols_p.h"
#include "qdbusmessage.h"
#include "qdbusmessage_p.h"
#endif
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN(QDBusError)
static constexpr const auto errorMessages = qOffsetStringArray(
"NoError",
"other",
"org.freedesktop.DBus.Error.Failed",
"org.freedesktop.DBus.Error.NoMemory",
"org.freedesktop.DBus.Error.ServiceUnknown",
"org.freedesktop.DBus.Error.NoReply",
"org.freedesktop.DBus.Error.BadAddress",
"org.freedesktop.DBus.Error.NotSupported",
"org.freedesktop.DBus.Error.LimitsExceeded",
"org.freedesktop.DBus.Error.AccessDenied",
"org.freedesktop.DBus.Error.NoServer",
"org.freedesktop.DBus.Error.Timeout",
"org.freedesktop.DBus.Error.NoNetwork",
"org.freedesktop.DBus.Error.AddressInUse",
"org.freedesktop.DBus.Error.Disconnected",
"org.freedesktop.DBus.Error.InvalidArgs",
"org.freedesktop.DBus.Error.UnknownMethod",
"org.freedesktop.DBus.Error.TimedOut",
"org.freedesktop.DBus.Error.InvalidSignature",
"org.freedesktop.DBus.Error.UnknownInterface",
"org.freedesktop.DBus.Error.UnknownObject",
"org.freedesktop.DBus.Error.UnknownProperty",
"org.freedesktop.DBus.Error.PropertyReadOnly",
"org.qtproject.QtDBus.Error.InternalError",
"org.qtproject.QtDBus.Error.InvalidService",
"org.qtproject.QtDBus.Error.InvalidObjectPath",
"org.qtproject.QtDBus.Error.InvalidInterface",
"org.qtproject.QtDBus.Error.InvalidMember",
""
);
#ifndef QT_BOOTSTRAPPED
static inline QDBusError::ErrorType get(const char *name)
{
if (!name || !*name)
return QDBusError::NoError;
for (int i = 0; i < errorMessages.count(); ++i)
if (strcmp(name, errorMessages.at(i)) == 0)
return QDBusError::ErrorType(i);
return QDBusError::Other;
}
#endif
/*!
\class QDBusError
\inmodule QtDBus
\since 4.2
\brief The QDBusError class represents an error received from the
D-Bus bus or from remote applications found in the bus.
When dealing with the D-Bus bus service or with remote
applications over D-Bus, a number of error conditions can
happen. This error conditions are sometimes signalled by a
returned error value or by a QDBusError.
C++ and Java exceptions are a valid analogy for D-Bus errors:
instead of returning normally with a return value, remote
applications and the bus may decide to throw an error
condition. However, the Qt D-Bus implementation does not use the C++
exception-throwing mechanism, so you will receive QDBusErrors in
the return reply (see QDBusReply::error()).
QDBusError objects are used to inspect the error name and message
as received from the bus and remote applications. You should not
create such objects yourself to signal error conditions when
called from D-Bus: instead, use QDBusMessage::createError() and
QDBusConnection::send().
\sa QDBusConnection::send(), QDBusMessage, QDBusReply
*/
/*!
\enum QDBusError::ErrorType
In order to facilitate verification of the most common D-Bus errors generated by the D-Bus
implementation and by the bus daemon itself, QDBusError can be compared to a set of pre-defined
values:
\value NoError QDBusError is invalid (i.e., the call succeeded)
\value Other QDBusError contains an error that is not one of the well-known ones
\value Failed The call failed (\c org.freedesktop.DBus.Error.Failed)
\value NoMemory Out of memory (\c org.freedesktop.DBus.Error.NoMemory)
\value ServiceUnknown The called service is not known
(\c org.freedesktop.DBus.Error.ServiceUnknown)
\value NoReply The called method did not reply within the specified timeout
(\c org.freedesktop.DBus.Error.NoReply)
\value BadAddress The address given is not valid
(\c org.freedesktop.DBus.Error.BadAddress)
\value NotSupported The call/operation is not supported
(\c org.freedesktop.DBus.Error.NotSupported)
\value LimitsExceeded The limits allocated to this process/call/connection exceeded the
pre-defined values (\c org.freedesktop.DBus.Error.LimitsExceeded)
\value AccessDenied The call/operation tried to access a resource it isn't allowed to
(\c org.freedesktop.DBus.Error.AccessDenied)
\value NoServer \e {Documentation doesn't say what this is for}
(\c org.freedesktop.DBus.Error.NoServer)
\value Timeout \e {Documentation doesn't say what this is for or how it's used}
(\c org.freedesktop.DBus.Error.Timeout)
\value NoNetwork \e {Documentation doesn't say what this is for}
(\c org.freedesktop.DBus.Error.NoNetwork)
\value AddressInUse QDBusServer tried to bind to an address that is already in use
(\c org.freedesktop.DBus.Error.AddressInUse)
\value Disconnected The call/process/message was sent after QDBusConnection disconnected
(\c org.freedesktop.DBus.Error.Disconnected)
\value InvalidArgs The arguments passed to this call/operation are not valid
(\c org.freedesktop.DBus.Error.InvalidArgs)
\value UnknownMethod The method called was not found in this object/interface with the
given parameters (\c org.freedesktop.DBus.Error.UnknownMethod)
\value TimedOut \e {Documentation doesn't say...}
(\c org.freedesktop.DBus.Error.TimedOut)
\value InvalidSignature The type signature is not valid or compatible
(\c org.freedesktop.DBus.Error.InvalidSignature)
\value UnknownInterface The interface is not known in this object
(\c org.freedesktop.DBus.Error.UnknownInterface)
\value UnknownObject The object path points to an object that does not exist
(\c org.freedesktop.DBus.Error.UnknownObject)
\value UnknownProperty The property does not exist in this interface
(\c org.freedesktop.DBus.Error.UnknownProperty)
\value PropertyReadOnly The property set failed because the property is read-only
(\c org.freedesktop.DBus.Error.PropertyReadOnly)
\value InternalError An internal error occurred
\value InvalidObjectPath The object path provided is invalid.
\value InvalidService The service requested is invalid.
\value InvalidMember The member is invalid.
\value InvalidInterface The interface is invalid.
*/
/*!
\internal
Constructs a QDBusError that represents no error.
*/
QDBusError::QDBusError()
: code(NoError)
{
// ### This class has an implicit (therefore inline) destructor
// so the following field cannot be used.
Q_UNUSED(unused);
}
#ifndef QT_BOOTSTRAPPED
/*!
\internal
Constructs a QDBusError from a DBusError structure.
*/
QDBusError::QDBusError(const DBusError *error)
: code(NoError)
{
if (!error || !q_dbus_error_is_set(error))
return;
code = get(error->name);
msg = QString::fromUtf8(error->message);
nm = QString::fromUtf8(error->name);
}
/*!
\internal
Constructs a QDBusError from a QDBusMessage.
*/
QDBusError::QDBusError(const QDBusMessage &qdmsg)
: code(NoError)
{
if (qdmsg.type() != QDBusMessage::ErrorMessage)
return;
code = get(qdmsg.errorName().toUtf8().constData());
nm = qdmsg.errorName();
msg = qdmsg.errorMessage();
}
#endif
/*!
\internal
Constructs a QDBusError from a well-known error code
*/
QDBusError::QDBusError(ErrorType error, const QString &mess)
: code(error)
{
nm = QLatin1StringView(errorMessages[error]);
msg = mess;
}
/*!
\internal
Constructs a QDBusError from another QDBusError object
*/
QDBusError::QDBusError(const QDBusError &other)
: code(other.code), msg(other.msg), nm(other.nm)
{
}
/*!
\internal
Assignment operator
*/
QDBusError &QDBusError::operator=(const QDBusError &other)
{
code = other.code;
msg = other.msg;
nm = other.nm;
return *this;
}
#ifndef QT_BOOTSTRAPPED
/*!
\internal
Assignment operator from a QDBusMessage
*/
QDBusError &QDBusError::operator=(const QDBusMessage &qdmsg)
{
if (qdmsg.type() == QDBusMessage::ErrorMessage) {
code = get(qdmsg.errorName().toUtf8().constData());
nm = qdmsg.errorName();
msg = qdmsg.errorMessage();
} else {
code =NoError;
nm.clear();
msg.clear();
}
return *this;
}
#endif
/*!
Returns this error's ErrorType.
\sa ErrorType
*/
QDBusError::ErrorType QDBusError::type() const
{
return code;
}
/*!
Returns this error's name. Error names are similar to D-Bus Interface names, like
\c org.freedesktop.DBus.InvalidArgs.
\sa type()
*/
QString QDBusError::name() const
{
return nm;
}
/*!
Returns the message that the callee associated with this error. Error messages are
implementation defined and usually contain a human-readable error code, though this does not
mean it is suitable for your end-users.
*/
QString QDBusError::message() const
{
return msg;
}
/*!
Returns \c true if this is a valid error condition (i.e., if there was an error),
otherwise false.
*/
bool QDBusError::isValid() const
{
return (code != NoError);
}
/*!
\since 4.3
Returns the error name associated with error condition \a error.
*/
QString QDBusError::errorString(ErrorType error)
{
return QLatin1StringView(errorMessages[error]);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QDBusError &msg)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QDBusError(" << msg.name() << ", " << msg.message() << ')';
return dbg;
}
#endif
/*!
\fn void QDBusError::swap(QDBusError &other)
Swaps this QDBusError instance with \a other.
*/
QT_END_NAMESPACE
#include "moc_qdbuserror.cpp"
#endif // QT_NO_DBUS
/*
MSVC2015 has the warning C4503 at the end of the file:
QtPrivate::StaticStringBuilder<QtPrivate::IndexesList<...> - decorated name length exceeded, name was truncated
It is used by qOffsetStringArray in a constexpr evaluation and this code does not exist in the object file,
but we still have the warning or even error with -WX flag
*/
QT_WARNING_DISABLE_MSVC(4503)

113
src/dbus/qdbuserror.h Normal file
View File

@ -0,0 +1,113 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSERROR_H
#define QDBUSERROR_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
#ifndef QT_NO_DBUS
struct DBusError;
QT_BEGIN_NAMESPACE
class QDBusMessage;
class Q_DBUS_EXPORT QDBusError
{
Q_GADGET
public:
enum ErrorType {
NoError = 0,
Other = 1,
Failed,
NoMemory,
ServiceUnknown,
NoReply,
BadAddress,
NotSupported,
LimitsExceeded,
AccessDenied,
NoServer,
Timeout,
NoNetwork,
AddressInUse,
Disconnected,
InvalidArgs,
UnknownMethod,
TimedOut,
InvalidSignature,
UnknownInterface,
UnknownObject,
UnknownProperty,
PropertyReadOnly,
InternalError,
InvalidService,
InvalidObjectPath,
InvalidInterface,
InvalidMember,
#ifndef Q_QDOC
// don't use this one!
LastErrorType = InvalidMember
#endif
};
Q_ENUM(ErrorType)
QDBusError();
#ifndef QT_BOOTSTRAPPED
explicit QDBusError(const DBusError *error);
Q_IMPLICIT QDBusError(const QDBusMessage& msg);
#endif
QDBusError(ErrorType error, const QString &message);
QDBusError(const QDBusError &other);
QDBusError(QDBusError &&other) noexcept
: code(other.code), msg(std::move(other.msg)), nm(std::move(other.nm))
{}
QDBusError &operator=(QDBusError &&other) noexcept { swap(other); return *this; }
QDBusError &operator=(const QDBusError &other);
#ifndef QT_BOOTSTRAPPED
QDBusError &operator=(const QDBusMessage &msg);
#endif
void swap(QDBusError &other) noexcept
{
std::swap(code, other.code);
msg.swap(other.msg);
nm.swap(other.nm);
}
ErrorType type() const;
QString name() const;
QString message() const;
bool isValid() const;
static QString errorString(ErrorType error);
private:
ErrorType code;
QString msg;
QString nm;
// ### This class has an implicit (therefore inline) destructor
// so the following field cannot be used:
void *unused;
};
Q_DECLARE_SHARED(QDBusError)
#ifndef QT_NO_DEBUG_STREAM
Q_DBUS_EXPORT QDebug operator<<(QDebug, const QDBusError &);
#endif
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QDBusError, Q_DBUS_EXPORT)
#else
QT_BEGIN_NAMESPACE
class Q_DBUS_EXPORT QDBusError {}; // dummy class for moc
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,217 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusextratypes.h"
#include "qdbusutil_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN(QDBusVariant)
QT_IMPL_METATYPE_EXTERN(QDBusObjectPath)
QT_IMPL_METATYPE_EXTERN(QDBusSignature)
void QDBusObjectPath::doCheck()
{
if (!QDBusUtil::isValidObjectPath(m_path)) {
qWarning("QDBusObjectPath: invalid path \"%s\"", qPrintable(m_path));
m_path.clear();
}
}
void QDBusSignature::doCheck()
{
if (!QDBusUtil::isValidSignature(m_signature)) {
qWarning("QDBusSignature: invalid signature \"%s\"", qPrintable(m_signature));
m_signature.clear();
}
}
/*!
\class QDBusVariant
\inmodule QtDBus
\since 4.2
\brief The QDBusVariant class enables the programmer to identify
the variant type provided by the D-Bus typesystem.
A D-Bus function that takes an integer, a D-Bus variant and a string as parameters
can be called with the following argument list (see QDBusMessage::setArguments()):
\snippet qdbusextratypes/qdbusextratypes.cpp 0
When a D-Bus function returns a D-Bus variant, it can be retrieved as follows:
\snippet qdbusextratypes/qdbusextratypes.cpp 1
The QVariant within a QDBusVariant is required to distinguish between a normal
D-Bus value and a value within a D-Bus variant.
\sa {The Qt D-Bus Type System}
*/
/*!
\fn QDBusVariant::QDBusVariant()
Constructs a new D-Bus variant.
*/
/*!
\fn QDBusVariant::QDBusVariant(const QVariant &variant)
Constructs a new D-Bus variant from the given Qt \a variant.
\sa setVariant()
*/
/*!
\fn QVariant QDBusVariant::variant() const
Returns this D-Bus variant as a QVariant object.
\sa setVariant()
*/
/*!
\fn void QDBusVariant::setVariant(const QVariant &variant)
Assigns the value of the given Qt \a variant to this D-Bus variant.
\sa variant()
*/
/*!
\class QDBusObjectPath
\inmodule QtDBus
\since 4.2
\brief The QDBusObjectPath class enables the programmer to
identify the OBJECT_PATH type provided by the D-Bus typesystem.
\sa {The Qt D-Bus Type System}
*/
/*!
\fn QDBusObjectPath::QDBusObjectPath()
Constructs a new object path.
*/
/*!
\fn QDBusObjectPath::QDBusObjectPath(const char *path)
Constructs a new object path from the given \a path.
\sa setPath()
*/
/*!
\fn QDBusObjectPath::QDBusObjectPath(QLatin1StringView path)
Constructs a new object path from the Latin-1 string viewed by \a path.
*/
/*!
\fn QDBusObjectPath::QDBusObjectPath(const QString &path)
Constructs a new object path from the given \a path.
*/
/*!
\fn QString QDBusObjectPath::path() const
Returns this object path.
\sa setPath()
*/
/*!
\fn void QDBusObjectPath::setPath(const QString &path)
Assigns the value of the given \a path to this object path.
\sa path()
*/
/*!
\since 5.14
Implicit cast to QVariant. Equivalent to calling
QVariant::fromValue() with this object as argument.
*/
QDBusObjectPath::operator QVariant() const { return QVariant::fromValue(*this); }
/*!
\class QDBusSignature
\inmodule QtDBus
\since 4.2
\brief The QDBusSignature class enables the programmer to
identify the SIGNATURE type provided by the D-Bus typesystem.
\sa {The Qt D-Bus Type System}
*/
/*!
\fn QDBusSignature::QDBusSignature()
Constructs a new signature.
\sa setSignature()
*/
/*!
\fn QDBusSignature::QDBusSignature(const char *signature)
Constructs a new signature from the given \a signature.
*/
/*!
\fn QDBusSignature::QDBusSignature(QLatin1StringView signature)
Constructs a new signature from the Latin-1 string viewed by \a signature.
*/
/*!
\fn QDBusSignature::QDBusSignature(const QString &signature)
Constructs a new signature from the given \a signature.
*/
/*!
\fn QString QDBusSignature::signature() const
Returns this signature.
\sa setSignature()
*/
/*!
\fn void QDBusSignature::setSignature(const QString &signature)
Assigns the value of the given \a signature to this signature.
\sa signature()
*/
/*!
\fn void QDBusObjectPath::swap(QDBusObjectPath &other)
Swaps this QDBusObjectPath instance with \a other.
*/
/*!
\fn void QDBusSignature::swap(QDBusSignature &other)
Swaps this QDBusSignature instance with \a other.
*/
/*!
\fn void QDBusVariant::swap(QDBusVariant &other)
Swaps this QDBusVariant instance with \a other.
*/
QT_END_NAMESPACE
#endif // QT_NO_DBUS

161
src/dbus/qdbusextratypes.h Normal file
View File

@ -0,0 +1,161 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSEXTRATYPES_H
#define QDBUSEXTRATYPES_H
// define some useful types for D-BUS
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstring.h>
#include <QtCore/qhashfunctions.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class Q_DBUS_EXPORT QDBusObjectPath
{
QString m_path;
public:
QDBusObjectPath() noexcept : m_path() {}
// compiler-generated copy/move constructor/assignment operators are ok!
// compiler-generated destructor is ok!
inline explicit QDBusObjectPath(const char *path);
inline explicit QDBusObjectPath(QLatin1StringView path);
inline explicit QDBusObjectPath(const QString &path);
explicit QDBusObjectPath(QString &&p) : m_path(std::move(p)) { doCheck(); }
void swap(QDBusObjectPath &other) noexcept { m_path.swap(other.m_path); }
inline void setPath(const QString &path);
inline QString path() const
{ return m_path; }
operator QVariant() const;
private:
void doCheck();
};
Q_DECLARE_SHARED(QDBusObjectPath)
inline QDBusObjectPath::QDBusObjectPath(const char *objectPath)
: m_path(QString::fromLatin1(objectPath))
{ doCheck(); }
inline QDBusObjectPath::QDBusObjectPath(QLatin1StringView objectPath)
: m_path(objectPath)
{ doCheck(); }
inline QDBusObjectPath::QDBusObjectPath(const QString &objectPath)
: m_path(objectPath)
{ doCheck(); }
inline void QDBusObjectPath::setPath(const QString &objectPath)
{ m_path = objectPath; doCheck(); }
inline bool operator==(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
{ return lhs.path() == rhs.path(); }
inline bool operator!=(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
{ return lhs.path() != rhs.path(); }
inline bool operator<(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
{ return lhs.path() < rhs.path(); }
inline size_t qHash(const QDBusObjectPath &objectPath, size_t seed = 0)
{ return qHash(objectPath.path(), seed); }
class Q_DBUS_EXPORT QDBusSignature
{
QString m_signature;
public:
QDBusSignature() noexcept : m_signature() {}
// compiler-generated copy/move constructor/assignment operators are ok!
// compiler-generated destructor is ok!
inline explicit QDBusSignature(const char *signature);
inline explicit QDBusSignature(QLatin1StringView signature);
inline explicit QDBusSignature(const QString &signature);
explicit QDBusSignature(QString &&sig) : m_signature(std::move(sig)) { doCheck(); }
void swap(QDBusSignature &other) noexcept { m_signature.swap(other.m_signature); }
inline void setSignature(const QString &signature);
inline QString signature() const
{ return m_signature; }
private:
void doCheck();
};
Q_DECLARE_SHARED(QDBusSignature)
inline QDBusSignature::QDBusSignature(const char *dBusSignature)
: m_signature(QString::fromLatin1(dBusSignature))
{ doCheck(); }
inline QDBusSignature::QDBusSignature(QLatin1StringView dBusSignature)
: m_signature(dBusSignature)
{ doCheck(); }
inline QDBusSignature::QDBusSignature(const QString &dBusSignature)
: m_signature(dBusSignature)
{ doCheck(); }
inline void QDBusSignature::setSignature(const QString &dBusSignature)
{ m_signature = dBusSignature; doCheck(); }
inline bool operator==(const QDBusSignature &lhs, const QDBusSignature &rhs)
{ return lhs.signature() == rhs.signature(); }
inline bool operator!=(const QDBusSignature &lhs, const QDBusSignature &rhs)
{ return lhs.signature() != rhs.signature(); }
inline bool operator<(const QDBusSignature &lhs, const QDBusSignature &rhs)
{ return lhs.signature() < rhs.signature(); }
inline size_t qHash(const QDBusSignature &signature, size_t seed = 0)
{ return qHash(signature.signature(), seed); }
class QDBusVariant
{
QVariant m_variant;
public:
QDBusVariant() noexcept : m_variant() {}
// compiler-generated copy/move constructor/assignment operators are ok!
// compiler-generated destructor is ok!
inline explicit QDBusVariant(const QVariant &variant);
explicit QDBusVariant(QVariant &&v) noexcept : m_variant(std::move(v)) {}
void swap(QDBusVariant &other) noexcept { m_variant.swap(other.m_variant); }
inline void setVariant(const QVariant &variant);
inline QVariant variant() const
{ return m_variant; }
};
Q_DECLARE_SHARED(QDBusVariant)
inline QDBusVariant::QDBusVariant(const QVariant &dBusVariant)
: m_variant(dBusVariant) { }
inline void QDBusVariant::setVariant(const QVariant &dBusVariant)
{ m_variant = dBusVariant; }
inline bool operator==(const QDBusVariant &v1, const QDBusVariant &v2)
{ return v1.variant() == v2.variant(); }
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QDBusVariant, Q_DBUS_EXPORT)
QT_DECL_METATYPE_EXTERN(QDBusObjectPath, Q_DBUS_EXPORT)
QT_DECL_METATYPE_EXTERN(QDBusSignature, Q_DBUS_EXPORT)
#endif // QT_NO_DBUS
#endif

2683
src/dbus/qdbusintegrator.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSINTEGRATOR_P_H
#define QDBUSINTEGRATOR_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include "qdbus_symbols_p.h"
#include "qcoreevent.h"
#include "qeventloop.h"
#include "qobject.h"
#include "private/qobject_p.h"
#include "qlist.h"
#include "qpointer.h"
#include "qsemaphore.h"
#include "qdbusconnection.h"
#include "qdbusmessage.h"
#include "qdbusconnection_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnectionPrivate;
class QDBusMessage;
// Really private structs used by qdbusintegrator.cpp
// Things that aren't used by any other file
struct QDBusSlotCache
{
struct Data
{
int flags;
int slotIdx;
QList<QMetaType> metaTypes;
void swap(Data &other) noexcept
{
qSwap(flags, other.flags);
qSwap(slotIdx, other.slotIdx);
qSwap(metaTypes, other.metaTypes);
}
};
typedef QMultiHash<QString, Data> Hash;
Hash hash;
void swap(QDBusSlotCache &other) noexcept { qSwap(hash, other.hash); }
};
Q_DECLARE_SHARED(QDBusSlotCache::Data)
Q_DECLARE_SHARED(QDBusSlotCache)
class QDBusCallDeliveryEvent: public QAbstractMetaCallEvent
{
public:
QDBusCallDeliveryEvent(const QDBusConnection &c, int id, QObject *sender,
const QDBusMessage &msg, const QList<QMetaType> &types, int f = 0)
: QAbstractMetaCallEvent(sender, -1),
connection(c),
message(msg),
metaTypes(types),
id(id),
flags(f)
{
}
void placeMetaCall(QObject *object) override
{
QDBusConnectionPrivate::d(connection)->deliverCall(object, flags, message, metaTypes, id);
}
private:
QDBusConnection connection; // just for refcounting
QDBusMessage message;
QList<QMetaType> metaTypes;
int id;
int flags;
};
class QDBusActivateObjectEvent: public QAbstractMetaCallEvent
{
public:
QDBusActivateObjectEvent(const QDBusConnection &c, QObject *sender,
const QDBusConnectionPrivate::ObjectTreeNode &n,
int p, const QDBusMessage &m, QSemaphore *s = nullptr)
: QAbstractMetaCallEvent(sender, -1, s), connection(c), node(n),
pathStartPos(p), message(m), handled(false)
{ }
~QDBusActivateObjectEvent() override;
void placeMetaCall(QObject *) override;
private:
QDBusConnection connection; // just for refcounting
QDBusConnectionPrivate::ObjectTreeNode node;
int pathStartPos;
QDBusMessage message;
bool handled;
};
class QDBusSpyCallEvent : public QAbstractMetaCallEvent
{
public:
typedef void (*Hook)(const QDBusMessage&);
QDBusSpyCallEvent(QDBusConnectionPrivate *cp, const QDBusConnection &c, const QDBusMessage &msg,
const Hook *hooks, int count)
: QAbstractMetaCallEvent(cp, 0), conn(c), msg(msg), hooks(hooks), hookCount(count)
{}
~QDBusSpyCallEvent() override;
void placeMetaCall(QObject *) override;
static inline void invokeSpyHooks(const QDBusMessage &msg, const Hook *hooks, int hookCount);
QDBusConnection conn; // keeps the refcount in QDBusConnectionPrivate up
QDBusMessage msg;
const Hook *hooks;
int hookCount;
};
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QDBusSlotCache, Q_DBUS_EXPORT)
#endif // QT_NO_DBUS
#endif

295
src/dbus/qdbusinterface.cpp Normal file
View File

@ -0,0 +1,295 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusinterface.h"
#include "qdbusinterface_p.h"
#include "qdbus_symbols_p.h"
#include <QtCore/qpointer.h>
#include <QtCore/qstringlist.h>
#include "qdbusmetatype_p.h"
#include "qdbusconnection_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
static void copyArgument(void *to, int id, const QVariant &arg)
{
if (id == arg.metaType().id()) {
switch (id) {
case QMetaType::Bool:
*reinterpret_cast<bool *>(to) = arg.toBool();
return;
case QMetaType::UChar:
*reinterpret_cast<uchar *>(to) = qvariant_cast<uchar>(arg);
return;
case QMetaType::Short:
*reinterpret_cast<short *>(to) = qvariant_cast<short>(arg);
return;
case QMetaType::UShort:
*reinterpret_cast<ushort *>(to) = qvariant_cast<ushort>(arg);
return;
case QMetaType::Int:
*reinterpret_cast<int *>(to) = arg.toInt();
return;
case QMetaType::UInt:
*reinterpret_cast<uint *>(to) = arg.toUInt();
return;
case QMetaType::LongLong:
*reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
return;
case QMetaType::ULongLong:
*reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
return;
case QMetaType::Double:
*reinterpret_cast<double *>(to) = arg.toDouble();
return;
case QMetaType::QString:
*reinterpret_cast<QString *>(to) = arg.toString();
return;
case QMetaType::QByteArray:
*reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
return;
case QMetaType::QStringList:
*reinterpret_cast<QStringList *>(to) = arg.toStringList();
return;
}
if (id == QDBusMetaTypeId::variant().id()) {
*reinterpret_cast<QDBusVariant *>(to) = qvariant_cast<QDBusVariant>(arg);
return;
} else if (id == QDBusMetaTypeId::objectpath().id()) {
*reinterpret_cast<QDBusObjectPath *>(to) = qvariant_cast<QDBusObjectPath>(arg);
return;
} else if (id == QDBusMetaTypeId::signature().id()) {
*reinterpret_cast<QDBusSignature *>(to) = qvariant_cast<QDBusSignature>(arg);
return;
}
// those above are the only types possible
// the demarshaller code doesn't demarshall anything else
qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
}
// if we got here, it's either an un-dermarshalled type or a mismatch
if (arg.metaType() != QDBusMetaTypeId::argument()) {
// it's a mismatch
//qWarning?
return;
}
// is this type registered?
const char *userSignature = QDBusMetaType::typeToSignature(QMetaType(id));
if (!userSignature || !*userSignature) {
// type not registered
//qWarning?
return;
}
// is it the same signature?
QDBusArgument dbarg = qvariant_cast<QDBusArgument>(arg);
if (dbarg.currentSignature() != QLatin1StringView(userSignature)) {
// not the same signature, another mismatch
//qWarning?
return;
}
// we can demarshall
QDBusMetaType::demarshall(dbarg, QMetaType(id), to);
}
QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
const QString &iface, const QDBusConnection &con)
: QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(nullptr)
{
// QDBusAbstractInterfacePrivate's constructor checked the parameters for us
if (connection.isConnected()) {
metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
if (!metaObject) {
// creation failed, somehow
// most common causes are that the service doesn't exist or doesn't support introspection
// those are not fatal errors, so we continue working
if (!lastError.isValid())
lastError = QDBusError(QDBusError::InternalError, "Unknown error"_L1);
}
}
}
QDBusInterfacePrivate::~QDBusInterfacePrivate()
{
if (metaObject && !metaObject->cached)
delete metaObject;
}
/*!
\class QDBusInterface
\inmodule QtDBus
\since 4.2
\brief The QDBusInterface class is a proxy for interfaces on remote objects.
QDBusInterface is a generic accessor class that is used to place calls to remote objects,
connect to signals exported by remote objects and get/set the value of remote properties. This
class is useful for dynamic access to remote objects: that is, when you do not have a generated
code that represents the remote interface.
Calls are usually placed by using the call() function, which constructs the message, sends it
over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
normal QObject::connect() function. Finally, properties are accessed using the
QObject::property() and QObject::setProperty() functions.
The following code snippet demonstrates how to perform a
mathematical operation of \tt{"2 + 2"} in a remote application
called \c com.example.Calculator, accessed via the session bus.
\snippet code/src_qdbus_qdbusinterface.cpp 0
\sa {Qt D-Bus XML compiler (qdbusxml2cpp)}
*/
/*!
Creates a dynamic QDBusInterface object associated with the
interface \a interface on object at path \a path on service \a
service, using the given \a connection. If \a interface is an
empty string, the object created will refer to the merging of all
interfaces found by introspecting that object. Otherwise if
\a interface is not empty, the QDBusInterface object will be cached
to speedup further creations of the same interface.
\a parent is passed to the base class constructor.
If the remote service \a service is not present or if an error
occurs trying to obtain the description of the remote interface
\a interface, the object created will not be valid (see
isValid()).
*/
QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface,
const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection),
parent)
{
}
/*!
Destroy the object interface and frees up any resource used.
*/
QDBusInterface::~QDBusInterface()
{
// resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
}
/*!
\internal
Overrides QObject::metaObject to return our own copy.
*/
const QMetaObject *QDBusInterface::metaObject() const
{
return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
}
/*!
\internal
Override QObject::qt_metacast to catch the interface name too.
*/
void *QDBusInterface::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, "QDBusInterface"))
return static_cast<void*>(const_cast<QDBusInterface*>(this));
if (d_func()->interface.toLatin1() == _clname)
return static_cast<void*>(const_cast<QDBusInterface*>(this));
return QDBusAbstractInterface::qt_metacast(_clname);
}
/*!
\internal
Dispatch the call through the private.
*/
int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
if (_id < 0 || !d_func()->isValid || !d_func()->metaObject)
return _id;
return d_func()->metacall(_c, _id, _a);
}
int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
{
Q_Q(QDBusInterface);
if (c == QMetaObject::InvokeMetaMethod) {
int offset = metaObject->methodOffset();
QMetaMethod mm = metaObject->method(id + offset);
if (mm.methodType() == QMetaMethod::Signal) {
// signal relay from D-Bus world to Qt world
QMetaObject::activate(q, metaObject, id, argv);
} else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) {
// method call relay from Qt world to D-Bus world
// get D-Bus equivalent signature
QString methodName = QString::fromLatin1(mm.name());
const int *inputTypes = metaObject->inputTypesForMethod(id);
int inputTypesCount = *inputTypes;
// we will assume that the input arguments were passed correctly
QVariantList args;
args.reserve(inputTypesCount);
int i = 1;
for ( ; i <= inputTypesCount; ++i)
args << QVariant(QMetaType(inputTypes[i]), argv[i]);
// make the call
QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
if (reply.type() == QDBusMessage::ReplyMessage) {
// attempt to demarshall the return values
args = reply.arguments();
QVariantList::ConstIterator it = args.constBegin();
const int *outputTypes = metaObject->outputTypesForMethod(id);
int outputTypesCount = *outputTypes++;
if (mm.returnType() != QMetaType::UnknownType && mm.returnType() != QMetaType::Void) {
// this method has a return type
if (argv[0] && it != args.constEnd())
copyArgument(argv[0], *outputTypes++, *it);
// skip this argument even if we didn't copy it
--outputTypesCount;
++it;
}
for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
copyArgument(argv[i], outputTypes[j], *it);
}
}
// done
lastError = QDBusError(reply);
return -1;
}
}
return id;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

40
src/dbus/qdbusinterface.h Normal file
View File

@ -0,0 +1,40 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSINTERFACE_H
#define QDBUSINTERFACE_H
#include <QtDBus/qtdbusglobal.h>
#include <QtDBus/qdbusabstractinterface.h>
#include <QtDBus/qdbusconnection.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusInterfacePrivate;
class Q_DBUS_EXPORT QDBusInterface: public QDBusAbstractInterface
{
friend class QDBusConnection;
private:
QDBusInterface(QDBusInterfacePrivate *p);
public:
QDBusInterface(const QString &service, const QString &path, const QString &interface = QString(),
const QDBusConnection &connection = QDBusConnection::sessionBus(),
QObject *parent = nullptr);
~QDBusInterface();
virtual const QMetaObject *metaObject() const override;
virtual void *qt_metacast(const char *) override;
virtual int qt_metacall(QMetaObject::Call, int, void **) override;
private:
Q_DECLARE_PRIVATE(QDBusInterface)
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,45 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSINTERFACE_P_H
#define QDBUSINTERFACE_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include "qdbusabstractinterface_p.h"
#include "qdbusmetaobject_p.h"
#include <qdbusinterface.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusInterfacePrivate: public QDBusAbstractInterfacePrivate
{
public:
Q_DECLARE_PUBLIC(QDBusInterface)
QDBusMetaObject *metaObject;
QDBusInterfacePrivate(const QString &serv, const QString &p, const QString &iface,
const QDBusConnection &con);
~QDBusInterfacePrivate();
int metacall(QMetaObject::Call c, int id, void **argv);
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,497 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusconnection_p.h"
#include "qdbus_symbols_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qthread.h>
#include "qdbusabstractadaptor.h"
#include "qdbusabstractadaptor_p.h"
#include "qdbusconnection.h"
#include "qdbusextratypes.h"
#include "qdbusmessage.h"
#include "qdbusmetatype.h"
#include "qdbusmetatype_p.h"
#include "qdbusmessage_p.h"
#include "qdbusutil_p.h"
#include "qdbusvirtualobject.h"
#include <algorithm>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
// defined in qdbusxmlgenerator.cpp
extern Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
const QMetaObject *base, int flags);
static const char introspectableInterfaceXml[] =
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
" <method name=\"Introspect\">\n"
" <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" </interface>\n";
static const char propertiesInterfaceXml[] =
" <interface name=\"org.freedesktop.DBus.Properties\">\n"
" <method name=\"Get\">\n"
" <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"Set\">\n"
" <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
" </method>\n"
" <method name=\"GetAll\">\n"
" <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"values\" type=\"a{sv}\" direction=\"out\"/>\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"/>\n"
" </method>\n"
" <signal name=\"PropertiesChanged\">\n"
" <arg name=\"interface_name\" type=\"s\" direction=\"out\"/>\n"
" <arg name=\"changed_properties\" type=\"a{sv}\" direction=\"out\"/>\n"
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out1\" value=\"QVariantMap\"/>\n"
" <arg name=\"invalidated_properties\" type=\"as\" direction=\"out\"/>\n"
" </signal>\n"
" </interface>\n";
static const char peerInterfaceXml[] =
" <interface name=\"org.freedesktop.DBus.Peer\">\n"
" <method name=\"Ping\"/>\n"
" <method name=\"GetMachineId\">\n"
" <arg name=\"machine_uuid\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" </interface>\n";
static QString generateSubObjectXml(QObject *object)
{
QString retval;
const QObjectList &objs = object->children();
QObjectList::ConstIterator it = objs.constBegin();
QObjectList::ConstIterator end = objs.constEnd();
for ( ; it != end; ++it) {
QString name = (*it)->objectName();
if (!name.isEmpty() && QDBusUtil::isValidPartOfObjectPath(name))
retval += " <node name=\""_L1 + name + "\"/>\n"_L1;
}
return retval;
}
// declared as extern in qdbusconnection_p.h
QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node, const QString &path)
{
// object may be null
QString xml_data(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE ""_L1);
xml_data += "<node>\n"_L1;
if (node.obj) {
Q_ASSERT_X(QThread::currentThread() == node.obj->thread(),
"QDBusConnection: internal threading error",
"function called for an object that is in another thread!!");
if (node.flags & (QDBusConnection::ExportScriptableContents
| QDBusConnection::ExportNonScriptableContents)) {
// create XML for the object itself
const QMetaObject *mo = node.obj->metaObject();
for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
xml_data += qDBusGenerateMetaObjectXml(node.interfaceName, mo, mo->superClass(),
node.flags);
}
// does this object have adaptors?
QDBusAdaptorConnector *connector;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
// trasverse every adaptor in this object
QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin();
QDBusAdaptorConnector::AdaptorMap::ConstIterator end = connector->adaptors.constEnd();
for ( ; it != end; ++it) {
// add the interface:
QString ifaceXml = QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(it->adaptor);
if (ifaceXml.isEmpty()) {
// add the interface's contents:
ifaceXml += qDBusGenerateMetaObjectXml(QString::fromLatin1(it->interface),
it->adaptor->metaObject(),
&QDBusAbstractAdaptor::staticMetaObject,
QDBusConnection::ExportScriptableContents
| QDBusConnection::ExportNonScriptableContents);
QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
}
xml_data += ifaceXml;
}
}
// is it a virtual node that handles introspection itself?
if (node.flags & QDBusConnectionPrivate::VirtualObject) {
xml_data += node.treeNode->introspect(path);
}
xml_data += QLatin1StringView(propertiesInterfaceXml);
}
xml_data += QLatin1StringView(introspectableInterfaceXml);
xml_data += QLatin1StringView(peerInterfaceXml);
if (node.flags & QDBusConnection::ExportChildObjects) {
xml_data += generateSubObjectXml(node.obj);
} else {
// generate from the object tree
QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
node.children.constBegin();
QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end =
node.children.constEnd();
for ( ; it != end; ++it)
if (it->obj || !it->children.isEmpty())
xml_data += " <node name=\""_L1 + it->name + "\"/>\n"_L1;
}
xml_data += "</node>\n"_L1;
return xml_data;
}
// implement the D-Bus interface org.freedesktop.DBus.Properties
static inline QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const QString &interface_name)
{
return msg.createErrorReply(QDBusError::UnknownInterface,
"Interface %1 was not found in object %2"_L1
.arg(interface_name, msg.path()));
}
static inline QDBusMessage
propertyNotFoundError(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name)
{
return msg.createErrorReply(QDBusError::UnknownProperty,
"Property %1%2%3 was not found in object %4"_L1
.arg(interface_name,
interface_name.isEmpty() ? ""_L1 : "."_L1,
QLatin1StringView(property_name),
msg.path()));
}
QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
Q_ASSERT(msg.arguments().size() == 2);
Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
"QDBusConnection: internal threading error",
"function called for an object that is in another thread!!");
QString interface_name = msg.arguments().at(0).toString();
QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
QDBusAdaptorConnector *connector;
QVariant value;
bool interfaceFound = false;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
// find the class that implements interface_name or try until we've found the property
// in case of an empty interface
if (interface_name.isEmpty()) {
for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
end = connector->adaptors.constEnd(); it != end; ++it) {
const QMetaObject *mo = it->adaptor->metaObject();
int pidx = mo->indexOfProperty(property_name);
if (pidx != -1) {
value = mo->property(pidx).read(it->adaptor);
break;
}
}
} else {
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
if (it != connector->adaptors.constEnd() && interface_name == QLatin1StringView(it->interface)) {
interfaceFound = true;
value = it->adaptor->property(property_name);
}
}
}
if (!interfaceFound && !value.isValid()
&& node.flags & (QDBusConnection::ExportAllProperties |
QDBusConnection::ExportNonScriptableProperties)) {
// try the object itself
if (!interface_name.isEmpty())
interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
if (interfaceFound) {
int pidx = node.obj->metaObject()->indexOfProperty(property_name);
if (pidx != -1) {
QMetaProperty mp = node.obj->metaObject()->property(pidx);
if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
(!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
value = mp.read(node.obj);
}
}
}
if (!value.isValid()) {
// the property was not found
if (!interfaceFound)
return interfaceNotFoundError(msg, interface_name);
return propertyNotFoundError(msg, interface_name, property_name);
}
return msg.createReply(QVariant::fromValue(QDBusVariant(value)));
}
enum PropertyWriteResult {
PropertyWriteSuccess = 0,
PropertyNotFound,
PropertyTypeMismatch,
PropertyReadOnly,
PropertyWriteFailed
};
static QDBusMessage propertyWriteReply(const QDBusMessage &msg, const QString &interface_name,
const QByteArray &property_name, int status)
{
switch (status) {
case PropertyNotFound:
return propertyNotFoundError(msg, interface_name, property_name);
case PropertyTypeMismatch:
return msg.createErrorReply(QDBusError::InvalidArgs,
"Invalid arguments for writing to property %1%2%3"_L1
.arg(interface_name,
interface_name.isEmpty() ? ""_L1 : "."_L1,
QLatin1StringView(property_name)));
case PropertyReadOnly:
return msg.createErrorReply(QDBusError::PropertyReadOnly,
"Property %1%2%3 is read-only"_L1
.arg(interface_name,
interface_name.isEmpty() ? ""_L1 : "."_L1,
QLatin1StringView(property_name)));
case PropertyWriteFailed:
return msg.createErrorReply(QDBusError::InternalError,
QString::fromLatin1("Internal error"));
case PropertyWriteSuccess:
return msg.createReply();
}
Q_ASSERT_X(false, "", "Should not be reached");
return QDBusMessage();
}
static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value,
int propFlags = QDBusConnection::ExportAllProperties)
{
const QMetaObject *mo = obj->metaObject();
int pidx = mo->indexOfProperty(property_name);
if (pidx == -1) {
// this object has no property by that name
return PropertyNotFound;
}
QMetaProperty mp = mo->property(pidx);
// check if this property is writable
if (!mp.isWritable())
return PropertyReadOnly;
// check if this property is exported
bool isScriptable = mp.isScriptable();
if (!(propFlags & QDBusConnection::ExportScriptableProperties) && isScriptable)
return PropertyNotFound;
if (!(propFlags & QDBusConnection::ExportNonScriptableProperties) && !isScriptable)
return PropertyNotFound;
// we found our property
// do we have the right type?
QMetaType id = mp.metaType();
if (!id.isValid()){
// type not registered or invalid / void?
qWarning("QDBusConnection: Unable to handle unregistered datatype '%s' for property '%s::%s'",
mp.typeName(), mo->className(), property_name.constData());
return PropertyWriteFailed;
}
if (id.id() != QMetaType::QVariant && value.metaType() == QDBusMetaTypeId::argument()) {
// we have to demarshall before writing
QVariant other{QMetaType(id)};
if (!QDBusMetaType::demarshall(qvariant_cast<QDBusArgument>(value), other.metaType(), other.data())) {
qWarning("QDBusConnection: type '%s' (%d) is not registered with QtDBus. "
"Use qDBusRegisterMetaType to register it",
mp.typeName(), id.id());
return PropertyWriteFailed;
}
value = other;
}
if (mp.metaType() == QMetaType::fromType<QDBusVariant>())
value = QVariant::fromValue(QDBusVariant(value));
// the property type here should match
return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed;
}
QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
Q_ASSERT(msg.arguments().size() == 3);
Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
"QDBusConnection: internal threading error",
"function called for an object that is in another thread!!");
QString interface_name = msg.arguments().at(0).toString();
QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
QVariant value = qvariant_cast<QDBusVariant>(msg.arguments().at(2)).variant();
QDBusAdaptorConnector *connector;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
// find the class that implements interface_name or try until we've found the property
// in case of an empty interface
if (interface_name.isEmpty()) {
for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
end = connector->adaptors.constEnd(); it != end; ++it) {
int status = writeProperty(it->adaptor, property_name, value);
if (status == PropertyNotFound)
continue;
return propertyWriteReply(msg, interface_name, property_name, status);
}
} else {
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
if (it != connector->adaptors.cend() && interface_name == QLatin1StringView(it->interface)) {
return propertyWriteReply(msg, interface_name, property_name,
writeProperty(it->adaptor, property_name, value));
}
}
}
if (node.flags & (QDBusConnection::ExportScriptableProperties |
QDBusConnection::ExportNonScriptableProperties)) {
// try the object itself
bool interfaceFound = true;
if (!interface_name.isEmpty())
interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
if (interfaceFound) {
return propertyWriteReply(msg, interface_name, property_name,
writeProperty(node.obj, property_name, value, node.flags));
}
}
// the property was not found
if (!interface_name.isEmpty())
return interfaceNotFoundError(msg, interface_name);
return propertyWriteReply(msg, interface_name, property_name, PropertyNotFound);
}
// unite two QVariantMaps, but don't generate duplicate keys
static QVariantMap &operator+=(QVariantMap &lhs, const QVariantMap &rhs)
{
QVariantMap::ConstIterator it = rhs.constBegin(),
end = rhs.constEnd();
for ( ; it != end; ++it)
lhs.insert(it.key(), it.value());
return lhs;
}
static QVariantMap readAllProperties(QObject *object, int flags)
{
QVariantMap result;
const QMetaObject *mo = object->metaObject();
// QObject has properties, so don't start from 0
for (int i = QObject::staticMetaObject.propertyCount(); i < mo->propertyCount(); ++i) {
QMetaProperty mp = mo->property(i);
// is it readable?
if (!mp.isReadable())
continue;
// is it a registered property?
QMetaType type = mp.metaType();
if (!type.isValid())
continue;
const char *signature = QDBusMetaType::typeToSignature(type);
if (!signature)
continue;
// is this property visible from the outside?
if ((mp.isScriptable() && flags & QDBusConnection::ExportScriptableProperties) ||
(!mp.isScriptable() && flags & QDBusConnection::ExportNonScriptableProperties)) {
// yes, it's visible
QVariant value = mp.read(object);
if (value.isValid())
result.insert(QString::fromLatin1(mp.name()), value);
}
}
return result;
}
QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg)
{
Q_ASSERT(msg.arguments().size() == 1);
Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
"QDBusConnection: internal threading error",
"function called for an object that is in another thread!!");
QString interface_name = msg.arguments().at(0).toString();
bool interfaceFound = false;
QVariantMap result;
QDBusAdaptorConnector *connector;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
if (interface_name.isEmpty()) {
// iterate over all interfaces
for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
end = connector->adaptors.constEnd(); it != end; ++it) {
result += readAllProperties(it->adaptor, QDBusConnection::ExportAllProperties);
}
} else {
// find the class that implements interface_name
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
interface_name);
if (it != connector->adaptors.constEnd() && interface_name == QLatin1StringView(it->interface)) {
interfaceFound = true;
result = readAllProperties(it->adaptor, QDBusConnection::ExportAllProperties);
}
}
}
if (node.flags & QDBusConnection::ExportAllProperties &&
(!interfaceFound || interface_name.isEmpty())) {
// try the object itself
result += readAllProperties(node.obj, node.flags);
interfaceFound = true;
}
if (!interfaceFound && !interface_name.isEmpty()) {
// the interface was not found
return interfaceNotFoundError(msg, interface_name);
}
return msg.createReply(QVariant::fromValue(result));
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

View File

@ -0,0 +1,349 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusintrospection_p.h"
#include "qdbusxmlparser_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
/*!
\class QDBusIntrospection
\inmodule QtDBus
\brief Information about introspected objects and interfaces on D-Bus.
\internal
This class provides structures and methods for parsing the XML introspection data for D-Bus.
Normally, you don't have to use the methods provided here: QDBusInterface and QDBusObject will
do that for you.
But they may prove useful if the XML data was obtained through other means (like parsing a file).
*/
/*!
\class QDBusIntrospection::Argument
\inmodule QtDBus
\brief One argument to a D-Bus method or signal.
This struct represents one argument passed to a method or received from a method or signal in
D-Bus. The struct does not contain information on the direction (input or output).
*/
/*!
\variable QDBusIntrospection::Argument::type
The argument type.
*/
/*!
\variable QDBusIntrospection::Argument::name
The argument name. The argument name is optional, so this may be a null QString.
*/
/*!
\fn QDBusIntrospection::Argument::operator==(const Argument &other) const
Compares this object against \a other and return true if they are the same.
*/
/*!
\class QDBusIntrospection::Method
\inmodule QtDBus
\brief Information about one method.
This struct represents one method discovered through introspection. A method is composed of
its \a name, its input arguments, its output arguments, and, optionally, annotations. There are no
"in-out" arguments.
*/
/*!
\variable QDBusIntrospection::Method::name
The method's name.
*/
/*!
\variable QDBusIntrospection::Method::inputArgs
A list of the method's input arguments.
*/
/*!
\variable QDBusIntrospection::Method::outputArgs
A list of the method's output arguments (i.e., return values).
*/
/*!
\variable QDBusIntrospection::Method::annotations
The annotations associated with the method. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\fn QDBusIntrospection::Method::operator==(const Method &other) const
Compares this object against \a other and return true if they are the same.
*/
/*!
\class QDBusIntrospection::Signal
\inmodule QtDBus
\brief Information about one signal.
This struct represents one signal discovered through introspection. A signal is composed of
its \a name, its output arguments, and, optionally, annotations.
*/
/*!
\variable QDBusIntrospection::Signal::name
The signal's name.
*/
/*!
\variable QDBusIntrospection::Signal::outputArgs
A list of the signal's arguments.
*/
/*!
\variable QDBusIntrospection::Signal::annotations
The annotations associated with the signal. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\fn QDBusIntrospection::Signal::operator==(const Signal& other) const
Compares this object against \a other and return true if they are the same.
*/
/*!
\class QDBusIntrospection::Property
\inmodule QtDBus
\brief Information about one property.
This struct represents one property discovered through introspection. A property is composed of
its \a name, its \a type, its \a access rights, and, optionally, annotations.
*/
/*!
\variable QDBusIntrospection::Property::name
The property's name.
*/
/*!
\variable QDBusIntrospection::Property::type
The property's type.
*/
/*!
\enum QDBusIntrospection::Property::Access
The possible access rights for a property:
\value Read
\value Write
\value ReadWrite
*/
/*!
\variable QDBusIntrospection::Property::access
The property's access rights.
*/
/*!
\variable QDBusIntrospection::Property::annotations
The annotations associated with the property. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\fn QDBusIntrospection::Property::operator==(const Property &other) const
Compares this object against \a other and return true if they are the same.
*/
/*!
\class QDBusIntrospection::Interface
\inmodule QtDBus
\brief Information about one interface on the bus.
Each interface on D-Bus has a unique \a name, identifying where that interface was defined.
Interfaces may have annotations, methods, signals and properties, but none are mandatory.
*/
/*!
\variable QDBusIntrospection::Interface::name
The interface's name.
*/
/*!
\variable QDBusIntrospection::Interface::introspection
The XML document fragment describing this interface.
If parsed again through parseInterface, the object returned should have the same contents as
this object.
*/
/*!
\variable QDBusIntrospection::Interface::annotations
The annotations associated with the interface. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\variable QDBusIntrospection::Interface::methods
The methods available in this interface. Note that method names are not unique (i.e., methods
can be overloaded with multiple arguments types).
*/
/*!
\variable QDBusIntrospection::Interface::signals_
The signals available in this interface. Note that signal names are not unique (i.e., signals
can be overloaded with multiple argument types).
This member is called "signals_" because "signals" is a reserved keyword in Qt.
*/
/*!
\variable QDBusIntrospection::Interface::properties
The properties available in this interface. Property names are unique.
*/
/*!
\fn QDBusIntrospection::Interface::operator==(const Interface &other) const
Compares this object against \a other and return true if they are the same.
Note that two interfaces are considered to be the same if they have the same name. The internal
structures in the objects are not compared.
*/
/*!
\class QDBusIntrospection::Object
\inmodule QtDBus
\brief Information about one object on the bus.
An object on the D-Bus bus is represented by its service and path on the service but, unlike
interfaces, objects are mutable. That is, their contents can change with time. Therefore,
while the (service, path) pair uniquely identifies an object, the information contained in
this struct may no longer represent the object.
An object can contain interfaces and child (sub) objects.
*/
/*!
\variable QDBusIntrospection::Object::service
The object's service name.
\sa parseObject()
*/
/*!
\variable QDBusIntrospection::Object::path
The object's path on the service. This is an absolute path.
\sa parseObject()
*/
/*!
\variable QDBusIntrospection::Object::interfaces
The list of interface names in this object.
*/
/*!
\variable QDBusIntrospection::Object::childObjects
The list of child object names in this object. Note that this is a relative name, not an
absolute path. To obtain the absolute path, concatenate with \l
{QDBusIntrospection::Object::path}{path}.
*/
/*!
\typedef QDBusIntrospection::Annotations
Contains a QMap of an annotation pair. The annotation's name is stored in the QMap key and
must be unique. The annotation's value is stored in the QMap's value and is arbitrary.
*/
/*!
\typedef QDBusIntrospection::Arguments
Contains a list of arguments to either a Method or a Signal. The arguments' order is important.
*/
/*!
\typedef QDBusIntrospection::Methods
Contains a QMap of methods and their names. The method's name is stored in the map's key and
is not necessarily unique. The order in which multiple methods with the same name are stored
in this map is undefined.
*/
/*!
\typedef QDBusIntrospection::Signals
Contains a QMap of signals and their names. The signal's name is stored in the map's key and
is not necessarily unique. The order in which multiple signals with the same name are stored
in this map is undefined.
*/
/*!
\typedef QDBusIntrospection::Properties
Contains a QMap of properties and their names. Each property must have a unique name.
*/
/*!
\typedef QDBusIntrospection::Interfaces
Contains a QMap of interfaces and their names. Each interface has a unique name.
*/
/*!
\typedef QDBusIntrospection::Objects
Contains a QMap of objects and their paths relative to their immediate parent.
*/
/*!
Parses the XML document fragment (given by \a xml) containing one interface.
The first element tag in this XML data must be either \<node\> or \<interface\>. If it is
\<node\>, then the \<interface\> tag must be a child tag of the \<node\> one.
If there are multiple interfaces in this XML data, it is undefined which one will be
returned.
*/
QDBusIntrospection::Interface
QDBusIntrospection::parseInterface(const QString &xml)
{
// be lazy
Interfaces ifs = parseInterfaces(xml);
if (ifs.isEmpty())
return Interface();
// return the first in map order (probably alphabetical order)
return *ifs.constBegin().value();
}
/*!
Parses the XML document fragment (given by \a xml) containing several interfaces.
If the first element tag in this document fragment is \<node\>, the interfaces parsed will
be those found as child elements of the \<node\> tag.
*/
QDBusIntrospection::Interfaces
QDBusIntrospection::parseInterfaces(const QString &xml)
{
QString null;
QDBusXmlParser parser(null, null, xml);
return parser.interfaces();
}
/*!
Parses the XML document fragment (given by \a xml) containing one object, found at the service
\a service and path \a path.
The first element tag in this document must be \<node\>. If that tag does not contain
a name attribute, the \a path argument will be used to determine the path of this
object node.
This function does not parse the interfaces contained in the node, nor sub-object's contents.
It will only list their names.
*/
QDBusIntrospection::Object
QDBusIntrospection::parseObject(const QString &xml, const QString &service, const QString &path)
{
QDBusXmlParser parser(service, path, xml);
QSharedDataPointer<QDBusIntrospection::Object> retval = parser.object();
if (!retval)
return QDBusIntrospection::Object();
return *retval;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

View File

@ -0,0 +1,135 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSINTROSPECTION_P_H
#define QDBUSINTROSPECTION_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/private/qtdbusglobal_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qpair.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class Q_DBUS_EXPORT QDBusIntrospection
{
public:
// forward declarations
struct Argument;
struct Method;
struct Signal;
struct Property;
struct Interface;
struct Object;
struct ObjectTree;
// typedefs
typedef QMap<QString, QString> Annotations;
typedef QList<Argument> Arguments;
typedef QMultiMap<QString, Method> Methods;
typedef QMultiMap<QString, Signal> Signals;
typedef QMap<QString, Property> Properties;
typedef QMap<QString, QSharedDataPointer<Interface> > Interfaces;
typedef QMap<QString, QSharedDataPointer<ObjectTree> > Objects;
public:
// the structs
struct Argument
{
QString type;
QString name;
inline bool operator==(const Argument& other) const
{ return name == other.name && type == other.type; }
};
struct Method
{
QString name;
Arguments inputArgs;
Arguments outputArgs;
Annotations annotations;
inline bool operator==(const Method& other) const
{ return name == other.name && annotations == other.annotations &&
inputArgs == other.inputArgs && outputArgs == other.outputArgs; }
};
struct Signal
{
QString name;
Arguments outputArgs;
Annotations annotations;
inline bool operator==(const Signal& other) const
{ return name == other.name && annotations == other.annotations &&
outputArgs == other.outputArgs; }
};
struct Property
{
enum Access { Read, Write, ReadWrite };
QString name;
QString type;
Access access;
Annotations annotations;
inline bool operator==(const Property& other) const
{ return access == other.access && name == other.name &&
annotations == other.annotations && type == other.type; }
};
struct Interface: public QSharedData
{
QString name;
QString introspection;
Annotations annotations;
Methods methods;
Signals signals_;
Properties properties;
inline bool operator==(const Interface &other) const
{ return !name.isEmpty() && name == other.name; }
};
struct Object: public QSharedData
{
QString service;
QString path;
QStringList interfaces;
QStringList childObjects;
};
public:
static Interface parseInterface(const QString &xml);
static Interfaces parseInterfaces(const QString &xml);
static Object parseObject(const QString &xml, const QString &service = QString(),
const QString &path = QString());
private:
QDBusIntrospection();
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,554 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusargument_p.h"
#include "qdbusconnection.h"
#include "qdbusmetatype_p.h"
#include "qdbusutil_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
static void qIterAppend(DBusMessageIter *it, QByteArray *ba, int type, const void *arg)
{
if (ba)
*ba += char(type);
else
q_dbus_message_iter_append_basic(it, type, arg);
}
QDBusMarshaller::~QDBusMarshaller()
{
close();
}
void QDBusMarshaller::unregisteredTypeError(QMetaType id)
{
const char *name = id.name();
qWarning("QDBusMarshaller: type '%s' (%d) is not registered with D-BUS. "
"Use qDBusRegisterMetaType to register it",
name ? name : "", id.id());
error("Unregistered type %1 passed in arguments"_L1
.arg(QLatin1StringView(id.name())));
}
inline QString QDBusMarshaller::currentSignature()
{
if (message)
return QString::fromUtf8(q_dbus_message_get_signature(message));
return QString();
}
inline void QDBusMarshaller::append(uchar arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_BYTE, &arg);
}
inline void QDBusMarshaller::append(bool arg)
{
dbus_bool_t cast = arg;
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_BOOLEAN, &cast);
}
inline void QDBusMarshaller::append(short arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_INT16, &arg);
}
inline void QDBusMarshaller::append(ushort arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_UINT16, &arg);
}
inline void QDBusMarshaller::append(int arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_INT32, &arg);
}
inline void QDBusMarshaller::append(uint arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_UINT32, &arg);
}
inline void QDBusMarshaller::append(qlonglong arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_INT64, &arg);
}
inline void QDBusMarshaller::append(qulonglong arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_UINT64, &arg);
}
inline void QDBusMarshaller::append(double arg)
{
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_DOUBLE, &arg);
}
void QDBusMarshaller::append(const QString &arg)
{
QByteArray data = arg.toUtf8();
const char *cdata = data.constData();
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_STRING, &cdata);
}
inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
{
QByteArray data = arg.path().toUtf8();
if (!ba && data.isEmpty()) {
error("Invalid object path passed in arguments"_L1);
} else {
const char *cdata = data.constData();
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
}
}
inline void QDBusMarshaller::append(const QDBusSignature &arg)
{
QByteArray data = arg.signature().toUtf8();
if (!ba && data.isEmpty()) {
error("Invalid signature passed in arguments"_L1);
} else {
const char *cdata = data.constData();
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
}
}
inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg)
{
int fd = arg.fileDescriptor();
if (!ba && fd == -1) {
error("Invalid file descriptor passed in arguments"_L1);
} else {
if (!skipSignature)
qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd);
}
}
inline void QDBusMarshaller::append(const QByteArray &arg)
{
if (ba) {
if (!skipSignature)
*ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
return;
}
const char* cdata = arg.constData();
DBusMessageIter subiterator;
q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING,
&subiterator);
q_dbus_message_iter_append_fixed_array(&subiterator, DBUS_TYPE_BYTE, &cdata, arg.size());
q_dbus_message_iter_close_container(&iterator, &subiterator);
}
inline bool QDBusMarshaller::append(const QDBusVariant &arg)
{
if (ba) {
if (!skipSignature)
*ba += DBUS_TYPE_VARIANT_AS_STRING;
return true;
}
const QVariant &value = arg.variant();
QMetaType id = value.metaType();
if (!id.isValid()) {
qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
error("Invalid QVariant passed in arguments"_L1);
return false;
}
QByteArray tmpSignature;
const char *signature = nullptr;
if (id == QDBusMetaTypeId::argument()) {
// take the signature from the QDBusArgument object we're marshalling
tmpSignature =
qvariant_cast<QDBusArgument>(value).currentSignature().toLatin1();
signature = tmpSignature.constData();
} else {
// take the signatuer from the metatype we're marshalling
signature = QDBusMetaType::typeToSignature(id);
}
if (!signature) {
unregisteredTypeError(id);
return false;
}
QDBusMarshaller sub(capabilities);
open(sub, DBUS_TYPE_VARIANT, signature);
bool isOk = sub.appendVariantInternal(value);
// don't call sub.close(): it auto-closes
return isOk;
}
inline void QDBusMarshaller::append(const QStringList &arg)
{
if (ba) {
if (!skipSignature)
*ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
return;
}
QDBusMarshaller sub(capabilities);
open(sub, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING);
QStringList::ConstIterator it = arg.constBegin();
QStringList::ConstIterator end = arg.constEnd();
for ( ; it != end; ++it)
sub.append(*it);
// don't call sub.close(): it auto-closes
}
inline QDBusMarshaller *QDBusMarshaller::beginStructure()
{
return beginCommon(DBUS_TYPE_STRUCT, nullptr);
}
inline QDBusMarshaller *QDBusMarshaller::beginArray(QMetaType id)
{
const char *signature = QDBusMetaType::typeToSignature(id);
if (!signature) {
unregisteredTypeError(id);
return this;
}
return beginCommon(DBUS_TYPE_ARRAY, signature);
}
inline QDBusMarshaller *QDBusMarshaller::beginMap(QMetaType kid, QMetaType vid)
{
const char *ksignature = QDBusMetaType::typeToSignature(kid);
if (!ksignature) {
unregisteredTypeError(kid);
return this;
}
if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) {
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wformat-overflow")
qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
kid.name(), kid.id());
QT_WARNING_POP
error("Type %1 passed in arguments cannot be used as a key in a map"_L1
.arg(QLatin1StringView(kid.name())));
return this;
}
const char *vsignature = QDBusMetaType::typeToSignature(vid);
if (!vsignature) {
unregisteredTypeError(vid);
return this;
}
QByteArray signature;
signature = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
signature += ksignature;
signature += vsignature;
signature += DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
return beginCommon(DBUS_TYPE_ARRAY, signature);
}
inline QDBusMarshaller *QDBusMarshaller::beginMapEntry()
{
return beginCommon(DBUS_TYPE_DICT_ENTRY, nullptr);
}
void QDBusMarshaller::open(QDBusMarshaller &sub, int code, const char *signature)
{
sub.parent = this;
sub.ba = ba;
sub.ok = true;
sub.capabilities = capabilities;
sub.skipSignature = skipSignature;
if (ba) {
if (!skipSignature) {
switch (code) {
case DBUS_TYPE_ARRAY:
*ba += char(code);
*ba += signature;
Q_FALLTHROUGH();
case DBUS_TYPE_DICT_ENTRY:
sub.closeCode = 0;
sub.skipSignature = true;
break;
case DBUS_TYPE_STRUCT:
*ba += DBUS_STRUCT_BEGIN_CHAR;
sub.closeCode = DBUS_STRUCT_END_CHAR;
break;
}
}
} else {
q_dbus_message_iter_open_container(&iterator, code, signature, &sub.iterator);
}
}
QDBusMarshaller *QDBusMarshaller::beginCommon(int code, const char *signature)
{
QDBusMarshaller *d = new QDBusMarshaller(capabilities);
open(*d, code, signature);
return d;
}
inline QDBusMarshaller *QDBusMarshaller::endStructure()
{ return endCommon(); }
inline QDBusMarshaller *QDBusMarshaller::endArray()
{ return endCommon(); }
inline QDBusMarshaller *QDBusMarshaller::endMap()
{ return endCommon(); }
inline QDBusMarshaller *QDBusMarshaller::endMapEntry()
{ return endCommon(); }
QDBusMarshaller *QDBusMarshaller::endCommon()
{
QDBusMarshaller *retval = parent;
delete this;
return retval;
}
void QDBusMarshaller::close()
{
if (ba) {
if (!skipSignature && closeCode)
*ba += closeCode;
} else if (parent) {
q_dbus_message_iter_close_container(&parent->iterator, &iterator);
}
}
void QDBusMarshaller::error(const QString &msg)
{
ok = false;
if (parent)
parent->error(msg);
else
errorString = msg;
}
bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
{
QMetaType id = arg.metaType();
if (!id.isValid()) {
qWarning("QDBusMarshaller: cannot add an invalid QVariant");
error("Invalid QVariant passed in arguments"_L1);
return false;
}
// intercept QDBusArgument parameters here
if (id == QDBusMetaTypeId::argument()) {
QDBusArgument dbusargument = qvariant_cast<QDBusArgument>(arg);
QDBusArgumentPrivate *d = QDBusArgumentPrivate::d(dbusargument);
if (!d->message)
return false; // can't append this one...
QDBusDemarshaller demarshaller(capabilities);
demarshaller.message = q_dbus_message_ref(d->message);
if (d->direction == Demarshalling) {
// it's demarshalling; just copy
demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
} else {
// it's marshalling; start over
if (!q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
return false; // error!
}
return appendCrossMarshalling(&demarshaller);
}
const char *signature = QDBusMetaType::typeToSignature(id);
if (!signature) {
unregisteredTypeError(id);
return false;
}
switch (*signature) {
#ifdef __OPTIMIZE__
case DBUS_TYPE_BYTE:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
qIterAppend(&iterator, ba, *signature, arg.constData());
return true;
case DBUS_TYPE_BOOLEAN:
append( arg.toBool() );
return true;
#else
case DBUS_TYPE_BYTE:
append( qvariant_cast<uchar>(arg) );
return true;
case DBUS_TYPE_BOOLEAN:
append( arg.toBool() );
return true;
case DBUS_TYPE_INT16:
append( qvariant_cast<short>(arg) );
return true;
case DBUS_TYPE_UINT16:
append( qvariant_cast<ushort>(arg) );
return true;
case DBUS_TYPE_INT32:
append( static_cast<dbus_int32_t>(arg.toInt()) );
return true;
case DBUS_TYPE_UINT32:
append( static_cast<dbus_uint32_t>(arg.toUInt()) );
return true;
case DBUS_TYPE_INT64:
append( arg.toLongLong() );
return true;
case DBUS_TYPE_UINT64:
append( arg.toULongLong() );
return true;
case DBUS_TYPE_DOUBLE:
append( arg.toDouble() );
return true;
#endif
case DBUS_TYPE_STRING:
append( arg.toString() );
return true;
case DBUS_TYPE_OBJECT_PATH:
append( qvariant_cast<QDBusObjectPath>(arg) );
return true;
case DBUS_TYPE_SIGNATURE:
append( qvariant_cast<QDBusSignature>(arg) );
return true;
// compound types:
case DBUS_TYPE_VARIANT:
// nested QVariant
return append( qvariant_cast<QDBusVariant>(arg) );
case DBUS_TYPE_ARRAY:
// could be many things
// find out what kind of array it is
switch (arg.metaType().id()) {
case QMetaType::QStringList:
append( arg.toStringList() );
return true;
case QMetaType::QByteArray:
append( arg.toByteArray() );
return true;
default:
;
}
Q_FALLTHROUGH();
case DBUS_TYPE_STRUCT:
case DBUS_STRUCT_BEGIN_CHAR:
return appendRegisteredType( arg );
case DBUS_TYPE_DICT_ENTRY:
case DBUS_DICT_ENTRY_BEGIN_CHAR:
qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!");
return false;
case DBUS_TYPE_UNIX_FD:
if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) {
append(qvariant_cast<QDBusUnixFileDescriptor>(arg));
return true;
}
Q_FALLTHROUGH();
default:
qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'",
signature);
return false;
}
return true;
}
bool QDBusMarshaller::appendRegisteredType(const QVariant &arg)
{
ref.ref(); // reference up
QDBusArgument self(QDBusArgumentPrivate::create(this));
return QDBusMetaType::marshall(self, arg.metaType(), arg.constData());
}
bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
{
int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
if (QDBusUtil::isValidBasicType(code)) {
// easy: just append
// do exactly like the D-BUS docs suggest
// (see apidocs for q_dbus_message_iter_get_basic)
qlonglong value;
q_dbus_message_iter_get_basic(&demarshaller->iterator, &value);
q_dbus_message_iter_next(&demarshaller->iterator);
q_dbus_message_iter_append_basic(&iterator, code, &value);
return true;
}
if (code == DBUS_TYPE_ARRAY) {
int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator);
if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) {
// another optimization: fixed size arrays
// code is exactly like QDBusDemarshaller::toByteArray
DBusMessageIter sub;
q_dbus_message_iter_recurse(&demarshaller->iterator, &sub);
q_dbus_message_iter_next(&demarshaller->iterator);
int len;
void* data;
q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
char signature[2] = { char(element), 0 };
q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, signature, &sub);
q_dbus_message_iter_append_fixed_array(&sub, element, &data, len);
q_dbus_message_iter_close_container(&iterator, &sub);
return true;
}
}
// We have to recurse
QDBusDemarshaller *drecursed = demarshaller->beginCommon();
QDBusMarshaller mrecursed(capabilities); // create on the stack makes it autoclose
QByteArray subSignature;
const char *sig = nullptr;
if (code == DBUS_TYPE_VARIANT || code == DBUS_TYPE_ARRAY) {
subSignature = drecursed->currentSignature().toLatin1();
if (!subSignature.isEmpty())
sig = subSignature.constData();
}
open(mrecursed, code, sig);
while (!drecursed->atEnd()) {
if (!mrecursed.appendCrossMarshalling(drecursed)) {
delete drecursed;
return false;
}
}
delete drecursed;
return true;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

846
src/dbus/qdbusmessage.cpp Normal file
View File

@ -0,0 +1,846 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusmessage.h"
#include "qdbusmessage_p.h"
#include <qdebug.h>
#include <qstringlist.h>
#include "qdbus_symbols_p.h"
#include "qdbusargument_p.h"
#include "qdbuserror.h"
#include "qdbusmetatype.h"
#include "qdbusconnection_p.h"
#include "qdbusutil_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
QT_IMPL_METATYPE_EXTERN(QDBusMessage)
static_assert(QDBusMessage::InvalidMessage == DBUS_MESSAGE_TYPE_INVALID);
static_assert(QDBusMessage::MethodCallMessage == DBUS_MESSAGE_TYPE_METHOD_CALL);
static_assert(QDBusMessage::ReplyMessage == DBUS_MESSAGE_TYPE_METHOD_RETURN);
static_assert(QDBusMessage::ErrorMessage == DBUS_MESSAGE_TYPE_ERROR);
static_assert(QDBusMessage::SignalMessage == DBUS_MESSAGE_TYPE_SIGNAL);
static inline const char *data(const QByteArray &arr)
{
return arr.isEmpty() ? nullptr : arr.constData();
}
QDBusMessagePrivate::QDBusMessagePrivate()
: msg(nullptr), reply(nullptr), localReply(nullptr), ref(1), type(QDBusMessage::InvalidMessage),
delayedReply(false), localMessage(false),
parametersValidated(false), autoStartService(true),
interactiveAuthorizationAllowed(false)
{
}
QDBusMessagePrivate::~QDBusMessagePrivate()
{
if (msg)
q_dbus_message_unref(msg);
if (reply)
q_dbus_message_unref(reply);
delete localReply;
}
/*!
\since 4.3
Returns the human-readable message associated with the error that was received.
*/
QString QDBusMessage::errorMessage() const
{
if (d_ptr->type == ErrorMessage) {
if (!d_ptr->message.isEmpty())
return d_ptr->message;
if (!d_ptr->arguments.isEmpty())
return d_ptr->arguments.at(0).toString();
}
return QString();
}
/*!
\internal
Constructs a DBusMessage object from \a message. The returned value must be de-referenced
with q_dbus_message_unref. The \a capabilities flags indicates which capabilities to use.
The \a error object is set to indicate the error if anything went wrong with the
marshalling. Usually, this error message will be placed in the reply, as if the call failed.
The \a error pointer must not be null.
*/
DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
QDBusError *error)
{
if (!qdbus_loadLibDBus()) {
*error = QDBusError(QDBusError::Failed, "Could not open lidbus-1 library"_L1);
return nullptr;
}
DBusMessage *msg = nullptr;
const QDBusMessagePrivate *d_ptr = message.d_ptr;
switch (d_ptr->type) {
case QDBusMessage::InvalidMessage:
//qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
break;
case QDBusMessage::MethodCallMessage:
// only service and interface can be empty -> path and name must not be empty
if (!d_ptr->parametersValidated) {
if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
return nullptr;
if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
return nullptr;
if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
return nullptr;
if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
return nullptr;
}
msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
q_dbus_message_set_allow_interactive_authorization(msg, d_ptr->interactiveAuthorizationAllowed);
break;
case QDBusMessage::ReplyMessage:
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
if (!d_ptr->localMessage) {
q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
}
break;
case QDBusMessage::ErrorMessage:
// error name can't be empty
if (!d_ptr->parametersValidated
&& !QDBusUtil::checkErrorName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error))
return nullptr;
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
if (!d_ptr->localMessage) {
q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
}
break;
case QDBusMessage::SignalMessage:
// only the service name can be empty here
if (!d_ptr->parametersValidated) {
if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
return nullptr;
if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
return nullptr;
if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
return nullptr;
if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
return nullptr;
}
msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
d_ptr->name.toUtf8());
q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
break;
}
// if we got here, the parameters validated
// and since the message parameters cannot be changed once the message is created
// we can record this fact
d_ptr->parametersValidated = true;
QDBusMarshaller marshaller(capabilities);
QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
QVariantList::ConstIterator cend = d_ptr->arguments.constEnd();
q_dbus_message_iter_init_append(msg, &marshaller.iterator);
if (!d_ptr->message.isEmpty())
// prepend the error message
marshaller.append(d_ptr->message);
for ( ; it != cend; ++it)
marshaller.appendVariantInternal(*it);
// check if everything is ok
if (marshaller.ok)
return msg;
// not ok;
q_dbus_message_unref(msg);
*error = QDBusError(QDBusError::Failed, "Marshalling failed: "_L1 + marshaller.errorString);
return nullptr;
}
/*
struct DBusMessage
{
DBusAtomic refcount;
DBusHeader header;
DBusString body;
char byte_order;
unsigned int locked : 1;
DBUS_DISABLE_CHECKS
unsigned int in_cache : 1;
#endif
DBusList *size_counters;
long size_counter_delta;
dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
DBusDataSlotList slot_list;
#ifndef DBUS_DISABLE_CHECKS
int generation;
#endif
};
*/
/*!
\internal
Constructs a QDBusMessage by parsing the given DBusMessage object.
*/
QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
{
QDBusMessage message;
if (!dmsg)
return message;
message.d_ptr->type = QDBusMessage::MessageType(q_dbus_message_get_type(dmsg));
message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
QString::fromUtf8(q_dbus_message_get_member(dmsg));
message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
message.d_ptr->interactiveAuthorizationAllowed = q_dbus_message_get_allow_interactive_authorization(dmsg);
message.d_ptr->msg = q_dbus_message_ref(dmsg);
QDBusDemarshaller demarshaller(capabilities);
demarshaller.message = q_dbus_message_ref(dmsg);
if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
while (!demarshaller.atEnd())
message << demarshaller.toVariantInternal();
return message;
}
bool QDBusMessagePrivate::isLocal(const QDBusMessage &message)
{
return message.d_ptr->localMessage;
}
QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
const QDBusMessage &asSent)
{
// simulate the message being sent to the bus and then received back
// the only field that the bus sets when delivering the message
// (as opposed to the message as we send it), is the sender
// so we simply set the sender to our unique name
// determine if we are carrying any complex types
QString computedSignature;
QVariantList::ConstIterator it = asSent.d_ptr->arguments.constBegin();
QVariantList::ConstIterator end = asSent.d_ptr->arguments.constEnd();
for ( ; it != end; ++it) {
QMetaType id = it->metaType();
const char *signature = QDBusMetaType::typeToSignature(id);
if ((id.id() != QMetaType::QStringList && id.id() != QMetaType::QByteArray &&
qstrlen(signature) != 1) || id == QMetaType::fromType<QDBusVariant>()) {
// yes, we are
// we must marshall and demarshall again so as to create QDBusArgument
// entries for the complex types
QDBusError error;
DBusMessage *message = toDBusMessage(asSent, conn.connectionCapabilities(), &error);
if (!message) {
// failed to marshall, so it's a call error
return QDBusMessage::createError(error);
}
q_dbus_message_set_sender(message, conn.baseService.toUtf8());
QDBusMessage retval = fromDBusMessage(message, conn.connectionCapabilities());
retval.d_ptr->localMessage = true;
q_dbus_message_unref(message);
if (retval.d_ptr->service.isEmpty())
retval.d_ptr->service = conn.baseService;
return retval;
} else {
computedSignature += QLatin1StringView(signature);
}
}
// no complex types seen
// optimize by using the variant list itself
QDBusMessage retval;
QDBusMessagePrivate *d = retval.d_ptr;
d->arguments = asSent.d_ptr->arguments;
d->path = asSent.d_ptr->path;
d->interface = asSent.d_ptr->interface;
d->name = asSent.d_ptr->name;
d->message = asSent.d_ptr->message;
d->type = asSent.d_ptr->type;
d->service = conn.baseService;
d->signature = computedSignature;
d->localMessage = true;
return retval;
}
QDBusMessage QDBusMessagePrivate::makeLocalReply(const QDBusConnectionPrivate &conn,
const QDBusMessage &callMsg)
{
// simulate the reply (return or error) message being sent to the bus and
// then received back.
if (callMsg.d_ptr->localReply)
return makeLocal(conn, *callMsg.d_ptr->localReply);
return QDBusMessage(); // failed
}
/*!
\class QDBusMessage
\inmodule QtDBus
\since 4.2
\brief The QDBusMessage class represents one message sent or
received over the D-Bus bus.
This object can represent any of the four different types of
messages (MessageType) that can occur on the bus:
\list
\li Method calls
\li Method return values
\li Signal emissions
\li Error codes
\endlist
Objects of this type are created with the static createError(),
createMethodCall() and createSignal() functions. Use the
QDBusConnection::send() function to send the messages.
*/
/*!
\enum QDBusMessage::MessageType
The possible message types:
\value MethodCallMessage a message representing an outgoing or incoming method call
\value SignalMessage a message representing an outgoing or incoming signal emission
\value ReplyMessage a message representing the return values of a method call
\value ErrorMessage a message representing an error condition in response to a method call
\value InvalidMessage an invalid message: this is never set on messages received from D-Bus
*/
/*!
Constructs a new DBus message with the given \a path, \a interface
and \a name, representing a signal emission.
A DBus signal is emitted from one application and is received by
all applications that are listening for that signal from that
interface.
The QDBusMessage object that is returned can be sent using the
QDBusConnection::send() function.
*/
QDBusMessage QDBusMessage::createSignal(const QString &path, const QString &interface,
const QString &name)
{
QDBusMessage message;
message.d_ptr->type = SignalMessage;
message.d_ptr->path = path;
message.d_ptr->interface = interface;
message.d_ptr->name = name;
return message;
}
/*!
\since 5.6
Constructs a new DBus message with the given \a path, \a interface
and \a name, representing a signal emission to a specific destination.
A DBus signal is emitted from one application and is received only by
the application owning the destination \a service name.
The QDBusMessage object that is returned can be sent using the
QDBusConnection::send() function.
*/
QDBusMessage QDBusMessage::createTargetedSignal(const QString &service, const QString &path,
const QString &interface, const QString &name)
{
QDBusMessage message;
message.d_ptr->type = SignalMessage;
message.d_ptr->service = service;
message.d_ptr->path = path;
message.d_ptr->interface = interface;
message.d_ptr->name = name;
return message;
}
/*!
Constructs a new DBus message representing a method call.
A method call always informs its destination address
(\a service, \a path, \a interface and \a method).
The DBus bus allows calling a method on a given remote object without specifying the
destination interface, if the method name is unique. However, if two interfaces on the
remote object export the same method name, the result is undefined (one of the two may be
called or an error may be returned).
When using DBus in a peer-to-peer context (i.e., not on a bus), the \a service parameter is
optional.
The QDBusInterface class provides a simpler abstraction to synchronous
method calling.
This function returns a QDBusMessage object that can be sent with
QDBusConnection::call().
*/
QDBusMessage QDBusMessage::createMethodCall(const QString &service, const QString &path,
const QString &interface, const QString &method)
{
QDBusMessage message;
message.d_ptr->type = MethodCallMessage;
message.d_ptr->service = service;
message.d_ptr->path = path;
message.d_ptr->interface = interface;
message.d_ptr->name = method;
return message;
}
/*!
Constructs a new DBus message representing an error,
with the given \a name and \a msg.
*/
QDBusMessage QDBusMessage::createError(const QString &name, const QString &msg)
{
QDBusMessage error;
error.d_ptr->type = ErrorMessage;
error.d_ptr->name = name;
error.d_ptr->message = msg;
return error;
}
/*!
\fn QDBusMessage QDBusMessage::createError(const QDBusError &error)
Constructs a new DBus message representing the given \a error.
*/
/*!
\fn QDBusMessage QDBusMessage::createError(QDBusError::ErrorType type, const QString &msg)
Constructs a new DBus message for the error type \a type using
the message \a msg. Returns the DBus message.
*/
/*!
\fn QDBusMessage QDBusMessage::createReply(const QList<QVariant> &arguments) const
Constructs a new DBus message representing a reply, with the given
\a arguments.
*/
QDBusMessage QDBusMessage::createReply(const QVariantList &arguments) const
{
QDBusMessage reply;
reply.setArguments(arguments);
reply.d_ptr->type = ReplyMessage;
if (d_ptr->msg)
reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
if (d_ptr->localMessage) {
reply.d_ptr->localMessage = true;
d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
}
// the reply must have a msg or be a local-loop optimization
Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
return reply;
}
/*!
Constructs a new DBus message representing an error reply message,
with the given \a name and \a msg.
*/
QDBusMessage QDBusMessage::createErrorReply(const QString &name, const QString &msg) const
{
QDBusMessage reply = QDBusMessage::createError(name, msg);
if (d_ptr->msg)
reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
if (d_ptr->localMessage) {
reply.d_ptr->localMessage = true;
d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
}
// the reply must have a msg or be a local-loop optimization
Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
return reply;
}
/*!
Constructs a new DBus message representing a reply, with the
given \a argument.
*/
QDBusMessage QDBusMessage::createReply(const QVariant &argument) const
{
return createReply(QList{argument});
}
/*!
\fn QDBusMessage QDBusMessage::createErrorReply(const QDBusError &error) const
Constructs a new DBus message representing an error reply message,
from the given \a error object.
*/
/*!
\fn QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType type, const QString &msg) const
Constructs a new DBus reply message for the error type \a type using
the message \a msg. Returns the DBus message.
*/
QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
{
QDBusMessage msg = createErrorReply(QDBusError::errorString(atype), amsg);
msg.d_ptr->parametersValidated = true;
return msg;
}
/*!
Constructs an empty, invalid QDBusMessage object.
\sa createError(), createMethodCall(), createSignal()
*/
QDBusMessage::QDBusMessage()
{
d_ptr = new QDBusMessagePrivate;
}
/*!
Constructs a copy of the object given by \a other.
Note: QDBusMessage objects are shared. Modifications made to the
copy will affect the original one as well. See setDelayedReply()
for more information.
*/
QDBusMessage::QDBusMessage(const QDBusMessage &other)
{
d_ptr = other.d_ptr;
d_ptr->ref.ref();
}
/*!
Disposes of the object and frees any resources that were being held.
*/
QDBusMessage::~QDBusMessage()
{
if (!d_ptr->ref.deref())
delete d_ptr;
}
/*!
Copies the contents of the object given by \a other.
Note: QDBusMessage objects are shared. Modifications made to the
copy will affect the original one as well. See setDelayedReply()
for more information.
*/
QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
{
qAtomicAssign(d_ptr, other.d_ptr);
return *this;
}
/*!
Returns the name of the service or the bus address of the remote method call.
*/
QString QDBusMessage::service() const
{
return d_ptr->service;
}
/*!
Returns the path of the object that this message is being sent to (in the case of a
method call) or being received from (for a signal).
*/
QString QDBusMessage::path() const
{
return d_ptr->path;
}
/*!
Returns the interface of the method being called (in the case of a method call) or of
the signal being received from.
*/
QString QDBusMessage::interface() const
{
return d_ptr->interface;
}
/*!
Returns the name of the signal that was emitted or the name of the method that was called.
*/
QString QDBusMessage::member() const
{
if (d_ptr->type != ErrorMessage)
return d_ptr->name;
return QString();
}
/*!
Returns the name of the error that was received.
*/
QString QDBusMessage::errorName() const
{
if (d_ptr->type == ErrorMessage)
return d_ptr->name;
return QString();
}
/*!
Returns the signature of the signal that was received or for the output arguments
of a method call.
*/
QString QDBusMessage::signature() const
{
return d_ptr->signature;
}
/*!
Returns the flag that indicates if this message should see a reply
or not. This is only meaningful for \l {MethodCallMessage}{method
call messages}: any other kind of message cannot have replies and
this function will always return false for them.
*/
bool QDBusMessage::isReplyRequired() const
{
// Only method calls can have replies
if (d_ptr->type != QDBusMessage::MethodCallMessage)
return false;
if (!d_ptr->msg)
return d_ptr->localMessage; // if it's a local message, reply is required
return !q_dbus_message_get_no_reply(d_ptr->msg);
}
/*!
Sets whether the message will be replied later (if \a enable is
true) or if an automatic reply should be generated by Qt D-Bus
(if \a enable is false).
In D-Bus, all method calls must generate a reply to the caller, unless the
caller explicitly indicates otherwise (see isReplyRequired()). QtDBus
automatically generates such replies for any slots being called, but it
also allows slots to indicate whether they will take responsibility
of sending the reply at a later time, after the function has finished
processing.
\sa {Delayed Replies}
*/
void QDBusMessage::setDelayedReply(bool enable) const
{
d_ptr->delayedReply = enable;
}
/*!
Returns the delayed reply flag, as set by setDelayedReply(). By default, this
flag is false, which means Qt D-Bus will generate automatic replies
when necessary.
*/
bool QDBusMessage::isDelayedReply() const
{
return d_ptr->delayedReply;
}
/*!
Sets the auto start flag to \a enable. This flag only makes sense
for method call messages, where it tells the D-Bus server to
either auto start the service responsible for the service name, or
not to auto start it.
By default this flag is true, i.e. a service is autostarted.
This means:
When the service that this method call is sent to is already
running, the method call is sent to it. If the service is not
running yet, the D-Bus daemon is requested to autostart the
service that is assigned to this service name. This is
handled by .service files that are placed in a directory known
to the D-Bus server. These files then each contain a service
name and the path to a program that should be executed when
this service name is requested.
\since 4.7
*/
void QDBusMessage::setAutoStartService(bool enable)
{
d_ptr->autoStartService = enable;
}
/*!
Returns the auto start flag, as set by setAutoStartService(). By default, this
flag is true, which means Qt D-Bus will auto start a service, if it is
not running already.
\sa setAutoStartService()
\since 4.7
*/
bool QDBusMessage::autoStartService() const
{
return d_ptr->autoStartService;
}
/*!
Sets the interactive authorization flag to \a enable.
This flag only makes sense for method call messages, where it
tells the D-Bus server that the caller of the method is prepared
to wait for interactive authorization to take place (for instance
via Polkit) before the actual method is processed.
By default this flag is false and the other end is expected to
make any authorization decisions non-interactively and promptly.
The \c org.freedesktop.DBus.Error.InteractiveAuthorizationRequired
error indicates that authorization failed, but could have succeeded
if this flag had been set.
\sa isInteractiveAuthorizationAllowed()
\since 5.12
*/
void QDBusMessage::setInteractiveAuthorizationAllowed(bool enable)
{
d_ptr->interactiveAuthorizationAllowed = enable;
}
/*!
Returns the interactive authorization allowed flag, as set by
setInteractiveAuthorizationAllowed(). By default this flag
is false and the other end is expected to make any authorization
decisions non-interactively and promptly.
\sa setInteractiveAuthorizationAllowed()
\since 5.12
*/
bool QDBusMessage::isInteractiveAuthorizationAllowed() const
{
return d_ptr->interactiveAuthorizationAllowed;
}
/*!
Sets the arguments that are going to be sent over D-Bus to \a arguments. Those
will be the arguments to a method call or the parameters in the signal.
\sa arguments()
*/
void QDBusMessage::setArguments(const QList<QVariant> &arguments)
{
d_ptr->arguments = arguments;
}
/*!
Returns the list of arguments that are going to be sent or were received from
D-Bus.
*/
QList<QVariant> QDBusMessage::arguments() const
{
return d_ptr->arguments;
}
/*!
Appends the argument \a arg to the list of arguments to be sent over D-Bus in
a method call or signal emission.
*/
QDBusMessage &QDBusMessage::operator<<(const QVariant &arg)
{
d_ptr->arguments.append(arg);
return *this;
}
/*!
Returns the message type.
*/
QDBusMessage::MessageType QDBusMessage::type() const
{
switch (d_ptr->type) {
case DBUS_MESSAGE_TYPE_METHOD_CALL:
return MethodCallMessage;
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
return ReplyMessage;
case DBUS_MESSAGE_TYPE_ERROR:
return ErrorMessage;
case DBUS_MESSAGE_TYPE_SIGNAL:
return SignalMessage;
default:
break;
}
return InvalidMessage;
}
#ifndef QT_NO_DEBUG_STREAM
static QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
{
switch (t)
{
case QDBusMessage::MethodCallMessage:
return dbg << "MethodCall";
case QDBusMessage::ReplyMessage:
return dbg << "MethodReturn";
case QDBusMessage::SignalMessage:
return dbg << "Signal";
case QDBusMessage::ErrorMessage:
return dbg << "Error";
default:
return dbg << "Invalid";
}
}
static void debugVariantList(QDebug dbg, const QVariantList &list)
{
bool first = true;
QVariantList::ConstIterator it = list.constBegin();
QVariantList::ConstIterator end = list.constEnd();
for ( ; it != end; ++it) {
if (!first)
dbg.nospace() << ", ";
dbg.nospace() << qPrintable(QDBusUtil::argumentToString(*it));
first = false;
}
}
QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QDBusMessage(type=" << msg.type()
<< ", service=" << msg.service();
if (msg.type() == QDBusMessage::MethodCallMessage ||
msg.type() == QDBusMessage::SignalMessage)
dbg.nospace() << ", path=" << msg.path()
<< ", interface=" << msg.interface()
<< ", member=" << msg.member();
if (msg.type() == QDBusMessage::ErrorMessage)
dbg.nospace() << ", error name=" << msg.errorName()
<< ", error message=" << msg.errorMessage();
dbg.nospace() << ", signature=" << msg.signature()
<< ", contents=(";
debugVariantList(dbg, msg.arguments());
dbg.nospace() << ") )";
return dbg;
}
#endif
/*!
\fn void QDBusMessage::swap(QDBusMessage &other)
Swaps this QDBusMessage instance with \a other.
*/
QT_END_NAMESPACE
#endif // QT_NO_DBUS

104
src/dbus/qdbusmessage.h Normal file
View File

@ -0,0 +1,104 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSMESSAGE_H
#define QDBUSMESSAGE_H
#include <QtDBus/qtdbusglobal.h>
#include <QtDBus/qdbuserror.h>
#include <QtCore/qlist.h>
#include <QtCore/qvariant.h>
#if !defined(QT_NO_DBUS) && !defined(QT_BOOTSTRAPPED)
#if defined(Q_OS_WIN) && defined(interface)
# undef interface
#endif
QT_BEGIN_NAMESPACE
class QDBusMessagePrivate;
class Q_DBUS_EXPORT QDBusMessage
{
public:
enum MessageType {
InvalidMessage,
MethodCallMessage,
ReplyMessage,
ErrorMessage,
SignalMessage
};
QDBusMessage();
QDBusMessage(const QDBusMessage &other);
QDBusMessage &operator=(QDBusMessage &&other) noexcept { swap(other); return *this; }
QDBusMessage &operator=(const QDBusMessage &other);
~QDBusMessage();
void swap(QDBusMessage &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); }
static QDBusMessage createSignal(const QString &path, const QString &interface,
const QString &name);
static QDBusMessage createTargetedSignal(const QString &service, const QString &path,
const QString &interface, const QString &name);
static QDBusMessage createMethodCall(const QString &destination, const QString &path,
const QString &interface, const QString &method);
static QDBusMessage createError(const QString &name, const QString &msg);
static inline QDBusMessage createError(const QDBusError &err)
{ return createError(err.name(), err.message()); }
static inline QDBusMessage createError(QDBusError::ErrorType type, const QString &msg)
{ return createError(QDBusError::errorString(type), msg); }
QDBusMessage createReply(const QList<QVariant> &arguments = QList<QVariant>()) const;
QDBusMessage createReply(const QVariant &argument) const;
QDBusMessage createErrorReply(const QString &name, const QString &msg) const;
inline QDBusMessage createErrorReply(const QDBusError &err) const
{ return createErrorReply(err.name(), err.message()); }
QDBusMessage createErrorReply(QDBusError::ErrorType type, const QString &msg) const;
// there are no setters; if this changes, see qdbusmessage_p.h
QString service() const;
QString path() const;
QString interface() const;
QString member() const;
QString errorName() const;
QString errorMessage() const;
MessageType type() const;
QString signature() const;
bool isReplyRequired() const;
void setDelayedReply(bool enable) const;
bool isDelayedReply() const;
void setAutoStartService(bool enable);
bool autoStartService() const;
void setInteractiveAuthorizationAllowed(bool enable);
bool isInteractiveAuthorizationAllowed() const;
void setArguments(const QList<QVariant> &arguments);
QList<QVariant> arguments() const;
QDBusMessage &operator<<(const QVariant &arg);
private:
friend class QDBusMessagePrivate;
QDBusMessagePrivate *d_ptr;
};
Q_DECLARE_SHARED(QDBusMessage)
#ifndef QT_NO_DEBUG_STREAM
Q_DBUS_EXPORT QDebug operator<<(QDebug, const QDBusMessage &);
#endif
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QDBusMessage, Q_DBUS_EXPORT)
#else
class Q_DBUS_EXPORT QDBusMessage {}; // dummy class for moc
#endif // QT_NO_DBUS
#endif

73
src/dbus/qdbusmessage_p.h Normal file
View File

@ -0,0 +1,73 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSMESSAGE_P_H
#define QDBUSMESSAGE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qatomic.h>
#include <qstring.h>
#include <qdbusmessage.h>
#include <qdbusconnection.h>
struct DBusMessage;
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnectionPrivate;
class QDBusMessagePrivate
{
public:
QDBusMessagePrivate();
~QDBusMessagePrivate();
QList<QVariant> arguments;
// the following parameters are "const": they are not changed after the constructors
// the parametersValidated member below controls whether they've been validated already
QString service, path, interface, name, message, signature;
DBusMessage *msg;
DBusMessage *reply;
mutable QDBusMessage *localReply;
QAtomicInt ref;
QDBusMessage::MessageType type;
mutable uint delayedReply : 1;
uint localMessage : 1;
mutable uint parametersValidated : 1;
uint autoStartService : 1;
uint interactiveAuthorizationAllowed : 1;
static void setParametersValidated(QDBusMessage &msg, bool enable)
{ msg.d_ptr->parametersValidated = enable; }
static DBusMessage *toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
QDBusError *error);
static QDBusMessage fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities);
static bool isLocal(const QDBusMessage &msg);
static QDBusMessage makeLocal(const QDBusConnectionPrivate &conn,
const QDBusMessage &asSent);
static QDBusMessage makeLocalReply(const QDBusConnectionPrivate &conn,
const QDBusMessage &asSent);
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,698 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusmetaobject_p.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qhash.h>
#include <QtCore/qstring.h>
#include <QtCore/qvarlengtharray.h>
#include "qdbusutil_p.h"
#include "qdbuserror.h"
#include "qdbusmetatype.h"
#include "qdbusargument.h"
#include "qdbusintrospection_p.h"
#include "qdbusabstractinterface_p.h"
#include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
class QDBusMetaObjectGenerator
{
public:
QDBusMetaObjectGenerator(const QString &interface,
const QDBusIntrospection::Interface *parsedData);
void write(QDBusMetaObject *obj);
void writeWithoutXml(QDBusMetaObject *obj);
private:
struct Method {
QList<QByteArray> parameterNames;
QByteArray tag;
QByteArray name;
QVarLengthArray<int, 4> inputTypes;
QVarLengthArray<int, 4> outputTypes;
QByteArray rawReturnType;
quint32 flags;
};
struct Property {
QByteArray typeName;
QByteArray signature;
int type;
quint32 flags;
};
struct Type {
int id;
QByteArray name;
};
QMap<QByteArray, Method> signals_;
QMap<QByteArray, Method> methods;
QMap<QByteArray, Property> properties;
const QDBusIntrospection::Interface *data;
QString interface;
Type findType(const QByteArray &signature,
const QDBusIntrospection::Annotations &annotations,
const char *direction = "Out", int id = -1);
void parseMethods();
void parseSignals();
void parseProperties();
static qsizetype aggregateParameterCount(const QMap<QByteArray, Method> &map);
};
static const qsizetype intsPerProperty = 2;
static const qsizetype intsPerMethod = 2;
struct QDBusMetaObjectPrivate : public QMetaObjectPrivate
{
int propertyDBusData;
int methodDBusData;
};
QDBusMetaObjectGenerator::QDBusMetaObjectGenerator(const QString &interfaceName,
const QDBusIntrospection::Interface *parsedData)
: data(parsedData), interface(interfaceName)
{
if (data) {
parseProperties();
parseSignals(); // call parseSignals first so that slots override signals
parseMethods();
}
}
static int registerComplexDBusType(const QByteArray &typeName)
{
struct QDBusRawTypeHandler : QtPrivate::QMetaTypeInterface
{
const QByteArray name;
QDBusRawTypeHandler(const QByteArray &name)
: QtPrivate::QMetaTypeInterface {
0, sizeof(void *), sizeof(void *), QMetaType::RelocatableType, 0, nullptr,
name.constData(),
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr
},
name(name)
{}
};
Q_CONSTINIT static QBasicMutex mutex;
Q_CONSTINIT static struct Hash : QHash<QByteArray, QMetaType>
{
~Hash()
{
for (QMetaType entry : *this)
QMetaType::unregisterMetaType(std::move(entry));
}
} hash;
QMutexLocker lock(&mutex);
QMetaType &metatype = hash[typeName];
if (!metatype.isValid())
metatype = QMetaType(new QDBusRawTypeHandler(typeName));
return metatype.id();
}
Q_DBUS_EXPORT bool qt_dbus_metaobject_skip_annotations = false;
QDBusMetaObjectGenerator::Type
QDBusMetaObjectGenerator::findType(const QByteArray &signature,
const QDBusIntrospection::Annotations &annotations,
const char *direction, int id)
{
Type result;
result.id = QMetaType::UnknownType;
int type = QDBusMetaType::signatureToMetaType(signature).id();
if (type == QMetaType::UnknownType && !qt_dbus_metaobject_skip_annotations) {
// it's not a type normally handled by our meta type system
// it must contain an annotation
QString annotationName = QString::fromLatin1("org.qtproject.QtDBus.QtTypeName");
if (id >= 0)
annotationName += QString::fromLatin1(".%1%2")
.arg(QLatin1StringView(direction))
.arg(id);
// extract from annotations:
QByteArray typeName = annotations.value(annotationName).toLatin1();
// verify that it's a valid one
if (typeName.isEmpty()) {
// try the old annotation from Qt 4
annotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName");
if (id >= 0)
annotationName += QString::fromLatin1(".%1%2")
.arg(QLatin1StringView(direction))
.arg(id);
typeName = annotations.value(annotationName).toLatin1();
}
if (!typeName.isEmpty()) {
// type name found
type = QMetaType::fromName(typeName).id();
}
if (type == QMetaType::UnknownType || signature != QDBusMetaType::typeToSignature(QMetaType(type))) {
// type is still unknown or doesn't match back to the signature that it
// was expected to, so synthesize a fake type
typeName = "QDBusRawType<0x" + signature.toHex() + ">*";
type = registerComplexDBusType(typeName);
}
result.name = typeName;
} else if (type == QMetaType::UnknownType) {
// this case is used only by the qdbus command-line tool
// invalid, let's create an impossible type that contains the signature
if (signature == "av") {
result.name = "QVariantList";
type = QMetaType::QVariantList;
} else if (signature == "a{sv}") {
result.name = "QVariantMap";
type = QMetaType::QVariantMap;
} else if (signature == "a{ss}") {
result.name = "QMap<QString,QString>";
type = qMetaTypeId<QMap<QString, QString> >();
} else if (signature == "aay") {
result.name = "QByteArrayList";
type = qMetaTypeId<QByteArrayList>();
} else {
result.name = "{D-Bus type \"" + signature + "\"}";
type = registerComplexDBusType(result.name);
}
} else {
result.name = QMetaType(type).name();
}
result.id = type;
return result; // success
}
void QDBusMetaObjectGenerator::parseMethods()
{
//
// TODO:
// Add cloned methods when the remote object has return types
//
QDBusIntrospection::Methods::ConstIterator method_it = data->methods.constBegin();
QDBusIntrospection::Methods::ConstIterator method_end = data->methods.constEnd();
for ( ; method_it != method_end; ++method_it) {
const QDBusIntrospection::Method &m = *method_it;
Method mm;
mm.name = m.name.toLatin1();
QByteArray prototype = mm.name;
prototype += '(';
bool ok = true;
// build the input argument list
for (qsizetype i = 0; i < m.inputArgs.size(); ++i) {
const QDBusIntrospection::Argument &arg = m.inputArgs.at(i);
Type type = findType(arg.type.toLatin1(), m.annotations, "In", i);
if (type.id == QMetaType::UnknownType) {
ok = false;
break;
}
mm.inputTypes.append(type.id);
mm.parameterNames.append(arg.name.toLatin1());
prototype.append(type.name);
prototype.append(',');
}
if (!ok) continue;
// build the output argument list:
for (qsizetype i = 0; i < m.outputArgs.size(); ++i) {
const QDBusIntrospection::Argument &arg = m.outputArgs.at(i);
Type type = findType(arg.type.toLatin1(), m.annotations, "Out", i);
if (type.id == QMetaType::UnknownType) {
ok = false;
break;
}
mm.outputTypes.append(type.id);
if (i == 0 && type.id == -1) {
mm.rawReturnType = type.name;
}
if (i != 0) {
// non-const ref parameter
mm.parameterNames.append(arg.name.toLatin1());
prototype.append(type.name);
prototype.append("&,");
}
}
if (!ok) continue;
// convert the last commas:
if (!mm.parameterNames.isEmpty())
prototype[prototype.size() - 1] = ')';
else
prototype.append(')');
// check the async tag
if (m.annotations.value(ANNOTATION_NO_WAIT ""_L1) == "true"_L1)
mm.tag = "Q_NOREPLY";
// meta method flags
mm.flags = AccessPublic | MethodSlot | MethodScriptable;
// add
methods.insert(QMetaObject::normalizedSignature(prototype), mm);
}
}
void QDBusMetaObjectGenerator::parseSignals()
{
QDBusIntrospection::Signals::ConstIterator signal_it = data->signals_.constBegin();
QDBusIntrospection::Signals::ConstIterator signal_end = data->signals_.constEnd();
for ( ; signal_it != signal_end; ++signal_it) {
const QDBusIntrospection::Signal &s = *signal_it;
Method mm;
mm.name = s.name.toLatin1();
QByteArray prototype = mm.name;
prototype += '(';
bool ok = true;
// build the output argument list
for (qsizetype i = 0; i < s.outputArgs.size(); ++i) {
const QDBusIntrospection::Argument &arg = s.outputArgs.at(i);
Type type = findType(arg.type.toLatin1(), s.annotations, "Out", i);
if (type.id == QMetaType::UnknownType) {
ok = false;
break;
}
mm.inputTypes.append(type.id);
mm.parameterNames.append(arg.name.toLatin1());
prototype.append(type.name);
prototype.append(',');
}
if (!ok) continue;
// convert the last commas:
if (!mm.parameterNames.isEmpty())
prototype[prototype.size() - 1] = ')';
else
prototype.append(')');
// meta method flags
mm.flags = AccessPublic | MethodSignal | MethodScriptable;
// add
signals_.insert(QMetaObject::normalizedSignature(prototype), mm);
}
}
void QDBusMetaObjectGenerator::parseProperties()
{
QDBusIntrospection::Properties::ConstIterator prop_it = data->properties.constBegin();
QDBusIntrospection::Properties::ConstIterator prop_end = data->properties.constEnd();
for ( ; prop_it != prop_end; ++prop_it) {
const QDBusIntrospection::Property &p = *prop_it;
Property mp;
Type type = findType(p.type.toLatin1(), p.annotations);
if (type.id == QMetaType::UnknownType)
continue;
QByteArray name = p.name.toLatin1();
mp.signature = p.type.toLatin1();
mp.type = type.id;
mp.typeName = type.name;
// build the flags:
mp.flags = StdCppSet | Scriptable | Stored | Designable;
if (p.access != QDBusIntrospection::Property::Write)
mp.flags |= Readable;
if (p.access != QDBusIntrospection::Property::Read)
mp.flags |= Writable;
// add the property:
properties.insert(name, mp);
}
}
// Returns the sum of all parameters (including return type) for the given
// \a map of methods. This is needed for calculating the size of the methods'
// parameter type/name meta-data.
qsizetype QDBusMetaObjectGenerator::aggregateParameterCount(const QMap<QByteArray, Method> &map)
{
qsizetype sum = 0;
QMap<QByteArray, Method>::const_iterator it;
for (it = map.constBegin(); it != map.constEnd(); ++it) {
const Method &m = it.value();
sum += m.inputTypes.size() + qMax(qsizetype(1), m.outputTypes.size());
}
return sum;
}
void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
{
// this code here is mostly copied from qaxbase.cpp
// with a few modifications to make it cleaner
QString className = interface;
className.replace(u'.', "::"_L1);
if (className.isEmpty())
className = "QDBusInterface"_L1;
QVarLengthArray<uint> idata;
idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(uint));
qsizetype methodParametersDataSize =
((aggregateParameterCount(signals_)
+ aggregateParameterCount(methods)) * 2) // types and parameter names
- signals_.size() // return "parameters" don't have names
- methods.size(); // ditto
QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
static_assert(QMetaObjectPrivate::OutputRevision == 11, "QtDBus meta-object generator should generate the same version as moc");
header->revision = QMetaObjectPrivate::OutputRevision;
header->className = 0;
header->classInfoCount = 0;
header->classInfoData = 0;
header->methodCount = int(signals_.size() + methods.size());
header->methodData = int(idata.size());
header->propertyCount = int(properties.size());
header->propertyData = int(header->methodData + header->methodCount *
QMetaObjectPrivate::IntsPerMethod + methodParametersDataSize);
header->enumeratorCount = 0;
header->enumeratorData = 0;
header->constructorCount = 0;
header->constructorData = 0;
header->flags = RequiresVariantMetaObject;
header->signalCount = signals_.size();
// These are specific to QDBusMetaObject:
header->propertyDBusData = int(header->propertyData + header->propertyCount
* QMetaObjectPrivate::IntsPerProperty);
header->methodDBusData = int(header->propertyDBusData + header->propertyCount * intsPerProperty);
qsizetype data_size = idata.size() +
(header->methodCount * (QMetaObjectPrivate::IntsPerMethod+intsPerMethod)) + methodParametersDataSize +
(header->propertyCount * (QMetaObjectPrivate::IntsPerProperty+intsPerProperty));
for (const Method &mm : std::as_const(signals_))
data_size += 2 + mm.inputTypes.size() + mm.outputTypes.size();
for (const Method &mm : std::as_const(methods))
data_size += 2 + mm.inputTypes.size() + mm.outputTypes.size();
idata.resize(data_size + 1);
QMetaStringTable strings(className.toLatin1());
qsizetype offset = header->methodData;
qsizetype parametersOffset = offset + header->methodCount * QMetaObjectPrivate::IntsPerMethod;
qsizetype signatureOffset = header->methodDBusData;
qsizetype typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod;
idata[typeidOffset++] = 0; // eod
qsizetype totalMetaTypeCount = properties.size();
++totalMetaTypeCount; // + 1 for metatype of dynamic metaobject
for (const auto& methodContainer: {signals_, methods}) {
for (const auto& method: methodContainer) {
qsizetype argc = method.inputTypes.size() + qMax(qsizetype(0), method.outputTypes.size() - 1);
totalMetaTypeCount += argc + 1;
}
}
QMetaType *metaTypes = new QMetaType[totalMetaTypeCount];
int propertyId = 0;
// add each method:
qsizetype currentMethodMetaTypeOffset = properties.size() + 1;
for (int x = 0; x < 2; ++x) {
// Signals must be added before other methods, to match moc.
QMap<QByteArray, Method> &map = (x == 0) ? signals_ : methods;
for (QMap<QByteArray, Method>::ConstIterator it = map.constBegin();
it != map.constEnd(); ++it) {
const Method &mm = it.value();
qsizetype argc = mm.inputTypes.size() + qMax(qsizetype(0), mm.outputTypes.size() - 1);
idata[offset++] = strings.enter(mm.name);
idata[offset++] = argc;
idata[offset++] = parametersOffset;
idata[offset++] = strings.enter(mm.tag);
idata[offset++] = mm.flags;
idata[offset++] = currentMethodMetaTypeOffset;
// Parameter types
for (qsizetype i = -1; i < argc; ++i) {
int type;
QByteArray typeName;
if (i < 0) { // Return type
if (!mm.outputTypes.isEmpty()) {
type = mm.outputTypes.first();
if (type == -1) {
type = IsUnresolvedType | strings.enter(mm.rawReturnType);
}
} else {
type = QMetaType::Void;
}
} else if (i < mm.inputTypes.size()) {
type = mm.inputTypes.at(i);
} else {
Q_ASSERT(mm.outputTypes.size() > 1);
type = mm.outputTypes.at(i - mm.inputTypes.size() + 1);
// Output parameters are references; type id not available
typeName = QMetaType(type).name();
typeName.append('&');
type = QMetaType::UnknownType;
}
int typeInfo;
if (!typeName.isEmpty())
typeInfo = IsUnresolvedType | strings.enter(typeName);
else
typeInfo = type;
metaTypes[currentMethodMetaTypeOffset++] = QMetaType(type);
idata[parametersOffset++] = typeInfo;
}
// Parameter names
for (qsizetype i = 0; i < argc; ++i)
idata[parametersOffset++] = strings.enter(mm.parameterNames.at(i));
idata[signatureOffset++] = typeidOffset;
idata[typeidOffset++] = mm.inputTypes.size();
memcpy(idata.data() + typeidOffset, mm.inputTypes.data(), mm.inputTypes.size() * sizeof(uint));
typeidOffset += mm.inputTypes.size();
idata[signatureOffset++] = typeidOffset;
idata[typeidOffset++] = mm.outputTypes.size();
memcpy(idata.data() + typeidOffset, mm.outputTypes.data(), mm.outputTypes.size() * sizeof(uint));
typeidOffset += mm.outputTypes.size();
}
}
Q_ASSERT(offset == header->methodData + header->methodCount * QMetaObjectPrivate::IntsPerMethod);
Q_ASSERT(parametersOffset == header->propertyData);
Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod);
Q_ASSERT(typeidOffset == idata.size());
offset += methodParametersDataSize;
Q_ASSERT(offset == header->propertyData);
// add each property
signatureOffset = header->propertyDBusData;
for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin();
it != properties.constEnd(); ++it) {
const Property &mp = it.value();
// form is name, typeinfo, flags
idata[offset++] = strings.enter(it.key()); // name
Q_ASSERT(mp.type != QMetaType::UnknownType);
idata[offset++] = mp.type;
idata[offset++] = mp.flags;
idata[offset++] = -1; // notify index
idata[offset++] = 0; // revision
idata[signatureOffset++] = strings.enter(mp.signature);
idata[signatureOffset++] = mp.type;
metaTypes[propertyId++] = QMetaType(mp.type);
}
metaTypes[propertyId] = QMetaType(); // we can't know our own metatype
Q_ASSERT(offset == header->propertyDBusData);
Q_ASSERT(signatureOffset == header->methodDBusData);
char *string_data = new char[strings.blobSize()];
strings.writeBlob(string_data);
uint *uint_data = new uint[idata.size()];
memcpy(uint_data, idata.data(), idata.size() * sizeof(uint));
// put the metaobject together
obj->d.data = uint_data;
obj->d.relatedMetaObjects = nullptr;
obj->d.static_metacall = nullptr;
obj->d.extradata = nullptr;
obj->d.stringdata = reinterpret_cast<const uint *>(string_data);
obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
obj->d.metaTypes = reinterpret_cast<QtPrivate::QMetaTypeInterface *const *>(metaTypes);
}
#if 0
void QDBusMetaObjectGenerator::writeWithoutXml(const QString &interface)
{
// no XML definition
QString tmp(interface);
tmp.replace(u'.', "::"_L1);
QByteArray name(tmp.toLatin1());
QDBusMetaObjectPrivate *header = new QDBusMetaObjectPrivate;
memset(header, 0, sizeof *header);
header->revision = 1;
// leave the rest with 0
char *stringdata = new char[name.length() + 1];
stringdata[name.length()] = '\0';
d.data = reinterpret_cast<uint*>(header);
d.relatedMetaObjects = 0;
d.static_metacall = 0;
d.extradata = 0;
d.stringdata = stringdata;
d.superdata = &QDBusAbstractInterface::staticMetaObject;
cached = false;
}
#endif
/////////
// class QDBusMetaObject
QDBusMetaObject *QDBusMetaObject::createMetaObject(const QString &interface, const QString &xml,
QHash<QString, QDBusMetaObject *> &cache,
QDBusError &error)
{
error = QDBusError();
QDBusIntrospection::Interfaces parsed = QDBusIntrospection::parseInterfaces(xml);
QDBusMetaObject *we = nullptr;
QDBusIntrospection::Interfaces::ConstIterator it = parsed.constBegin();
QDBusIntrospection::Interfaces::ConstIterator end = parsed.constEnd();
for ( ; it != end; ++it) {
// check if it's in the cache
bool us = it.key() == interface;
QDBusMetaObject *obj = cache.value(it.key(), 0);
if (!obj && (us || !interface.startsWith("local."_L1 ))) {
// not in cache; create
obj = new QDBusMetaObject;
QDBusMetaObjectGenerator generator(it.key(), it.value().constData());
generator.write(obj);
if ((obj->cached = !it.key().startsWith("local."_L1)))
// cache it
cache.insert(it.key(), obj);
else if (!us)
delete obj;
}
if (us)
// it's us
we = obj;
}
if (we)
return we;
// still nothing?
if (parsed.isEmpty()) {
// object didn't return introspection
we = new QDBusMetaObject;
QDBusMetaObjectGenerator generator(interface, nullptr);
generator.write(we);
we->cached = false;
return we;
} else if (interface.isEmpty()) {
// merge all interfaces
it = parsed.constBegin();
QDBusIntrospection::Interface merged = *it.value().constData();
for (++it; it != end; ++it) {
merged.annotations.insert(it.value()->annotations);
merged.methods.unite(it.value()->methods);
merged.signals_.unite(it.value()->signals_);
merged.properties.insert(it.value()->properties);
}
merged.name = "local.Merged"_L1;
merged.introspection.clear();
we = new QDBusMetaObject;
QDBusMetaObjectGenerator generator(merged.name, &merged);
generator.write(we);
we->cached = false;
return we;
}
// mark as an error
error = QDBusError(QDBusError::UnknownInterface,
"Interface '%1' was not found"_L1.arg(interface));
return nullptr;
}
QDBusMetaObject::QDBusMetaObject()
{
}
static inline const QDBusMetaObjectPrivate *priv(const uint* data)
{
return reinterpret_cast<const QDBusMetaObjectPrivate *>(data);
}
const int *QDBusMetaObject::inputTypesForMethod(int id) const
{
//id -= methodOffset();
if (id >= 0 && id < priv(d.data)->methodCount) {
int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
return reinterpret_cast<const int*>(d.data + d.data[handle]);
}
return nullptr;
}
const int *QDBusMetaObject::outputTypesForMethod(int id) const
{
//id -= methodOffset();
if (id >= 0 && id < priv(d.data)->methodCount) {
int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
return reinterpret_cast<const int*>(d.data + d.data[handle + 1]);
}
return nullptr;
}
int QDBusMetaObject::propertyMetaType(int id) const
{
//id -= propertyOffset();
if (id >= 0 && id < priv(d.data)->propertyCount) {
int handle = priv(d.data)->propertyDBusData + id*intsPerProperty;
return d.data[handle + 1];
}
return 0;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

View File

@ -0,0 +1,61 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSMETAOBJECT_P_H
#define QDBUSMETAOBJECT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#include <QtDBus/private/qtdbusglobal_p.h>
#include <QtCore/qmetaobject.h>
#ifndef QT_NO_DBUS
#ifdef interface
# undef interface
#endif
QT_BEGIN_NAMESPACE
class QDBusError;
struct QDBusMetaObjectPrivate;
struct Q_DBUS_EXPORT QDBusMetaObject: public QMetaObject
{
bool cached;
static QDBusMetaObject *createMetaObject(const QString &interface, const QString &xml,
QHash<QString, QDBusMetaObject *> &map,
QDBusError &error);
~QDBusMetaObject()
{
delete [] reinterpret_cast<const char *>(d.stringdata);
delete [] d.data;
delete [] reinterpret_cast<const QMetaType *>(d.metaTypes);
}
// methods (slots & signals):
const int *inputTypesForMethod(int id) const;
const int *outputTypesForMethod(int id) const;
// properties:
int propertyMetaType(int id) const;
private:
QDBusMetaObject();
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

463
src/dbus/qdbusmetatype.cpp Normal file
View File

@ -0,0 +1,463 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusmetatype.h"
#include "qdbusmetatype_p.h"
#include <string.h>
#include "qdbus_symbols_p.h"
#include <qbytearray.h>
#include <qglobal.h>
#include <qlist.h>
#include <qreadwritelock.h>
#include <qdatetime.h>
#include <qrect.h>
#include <qsize.h>
#include <qpoint.h>
#include <qline.h>
#include "qdbusargument_p.h"
#include "qdbusutil_p.h"
#include "qdbusunixfiledescriptor.h"
#ifndef QT_BOOTSTRAPPED
#include "qdbusmessage.h"
#endif
#ifndef QT_NO_DBUS
#ifndef DBUS_TYPE_UNIX_FD
# define DBUS_TYPE_UNIX_FD int('h')
# define DBUS_TYPE_UNIX_FD_AS_STRING "h"
#endif
QT_BEGIN_NAMESPACE
class QDBusCustomTypeInfo
{
public:
QDBusCustomTypeInfo() : signature(), marshall(nullptr), demarshall(nullptr)
{ }
// Suggestion:
// change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
QByteArray signature;
QDBusMetaType::MarshallFunction marshall;
QDBusMetaType::DemarshallFunction demarshall;
};
void QDBusMetaTypeId::init()
{
Q_CONSTINIT static QBasicAtomicInt initialized = Q_BASIC_ATOMIC_INITIALIZER(false);
// reentrancy is not a problem since everything else is locked on their own
// set the guard variable at the end
if (!initialized.loadRelaxed()) {
// register our types with Qt Core (calling qMetaTypeId<T>() does this implicitly)
(void)message();
(void)argument();
(void)variant();
(void)objectpath();
(void)signature();
(void)error();
(void)unixfd();
#ifndef QDBUS_NO_SPECIALTYPES
// and register Qt Core's with us
qDBusRegisterMetaType<QDate>();
qDBusRegisterMetaType<QTime>();
qDBusRegisterMetaType<QDateTime>();
qDBusRegisterMetaType<QRect>();
qDBusRegisterMetaType<QRectF>();
qDBusRegisterMetaType<QSize>();
qDBusRegisterMetaType<QSizeF>();
qDBusRegisterMetaType<QPoint>();
qDBusRegisterMetaType<QPointF>();
qDBusRegisterMetaType<QLine>();
qDBusRegisterMetaType<QLineF>();
qDBusRegisterMetaType<QVariantList>();
qDBusRegisterMetaType<QVariantMap>();
qDBusRegisterMetaType<QVariantHash>();
qDBusRegisterMetaType<QDBusObjectPath>();
qDBusRegisterMetaType<QList<bool> >();
qDBusRegisterMetaType<QList<short> >();
qDBusRegisterMetaType<QList<ushort> >();
qDBusRegisterMetaType<QList<int> >();
qDBusRegisterMetaType<QList<uint> >();
qDBusRegisterMetaType<QList<qlonglong> >();
qDBusRegisterMetaType<QList<qulonglong> >();
qDBusRegisterMetaType<QList<double> >();
qDBusRegisterMetaType<QList<QDBusObjectPath> >();
qDBusRegisterMetaType<QList<QDBusSignature> >();
qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
#endif
initialized.storeRelaxed(true);
}
}
using QDBusCustomTypeHash = QHash<int, QDBusCustomTypeInfo>;
Q_GLOBAL_STATIC(QDBusCustomTypeHash, customTypes)
Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
/*!
\class QDBusMetaType
\inmodule QtDBus
\brief Meta-type registration system for the Qt D-Bus module.
\internal
The QDBusMetaType class allows you to register class types for
marshalling and demarshalling over D-Bus. D-Bus supports a very
limited set of primitive types, but allows one to extend the type
system by creating compound types, such as arrays (lists) and
structs. In order to use them with Qt D-Bus, those types must be
registered.
See \l {qdbustypesystem.html}{Qt D-Bus Type System} for more
information on the type system and how to register additional
types.
\sa {qdbustypesystem.html}{Qt D-Bus Type System},
qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
*/
/*!
\fn int qDBusRegisterMetaType()
\relates QDBusArgument
\threadsafe
\since 4.2
Registers \c{T} with the
\l {qdbustypesystem.html}{Qt D-Bus Type System} and the Qt \l
{QMetaType}{meta-type system}, if it's not already registered.
To register a type, it must be declared as a meta-type with the
Q_DECLARE_METATYPE() macro, and then registered as in the
following example:
\snippet code/src_qdbus_qdbusmetatype.cpp 0-0
\codeline
\snippet code/src_qdbus_qdbusmetatype.cpp 0-1
If \c{T} isn't one of
Qt's \l{container classes}, the \c{operator<<} and
\c{operator>>} streaming operators between \c{T} and QDBusArgument
must be already declared. See the \l {qdbustypesystem.html}{Qt D-Bus
Type System} page for more information on how to declare such
types.
This function returns the Qt meta type id for the type (the same
value that is returned from qRegisterMetaType()).
\note The feature that a \c{T} inheriting a streamable type (including
the containers QList, QHash or QMap) can be streamed without providing
custom \c{operator<<} and \c{operator>>} is deprecated as of Qt 5.7,
because it ignores everything in \c{T} except the base class. There is
no diagnostic. You should always provide these operators for all types
you wish to stream and not rely on Qt-provided stream operators for
base classes.
\sa {qdbustypesystem.html}{Qt D-Bus Type System}, qRegisterMetaType(), QMetaType
*/
/*!
\typedef QDBusMetaType::MarshallFunction
\internal
*/
/*!
\typedef QDBusMetaType::DemarshallFunction
\internal
*/
/*!
\internal
Registers the marshalling and demarshalling functions for meta
type \a metaType.
*/
void QDBusMetaType::registerMarshallOperators(QMetaType metaType, MarshallFunction mf,
DemarshallFunction df)
{
int id = metaType.id();
auto *ct = customTypes();
if (id < 0 || !mf || !df || !ct)
return; // error!
QWriteLocker locker(customTypesLock());
QDBusCustomTypeInfo &info = (*ct)[id];
info.marshall = mf;
info.demarshall = df;
}
/*!
\internal
Executes the marshalling of type \a metaType (whose data is contained in
\a data) to the D-Bus marshalling argument \a arg. Returns \c true if
the marshalling succeeded, or false if an error occurred.
*/
bool QDBusMetaType::marshall(QDBusArgument &arg, QMetaType metaType, const void *data)
{
int id = metaType.id();
QDBusMetaTypeId::init();
MarshallFunction mf;
{
QReadLocker locker(customTypesLock());
auto *ct = customTypes();
auto it = ct->constFind(id);
if (it == ct->cend())
return false; // non-existent
const QDBusCustomTypeInfo &info = *it;
if (!info.marshall) {
mf = nullptr; // make gcc happy
return false;
} else
mf = info.marshall;
}
mf(arg, data);
return true;
}
/*!
\internal
Executes the demarshalling of type \a metaType (whose data will be placed in
\a data) from the D-Bus marshalling argument \a arg. Returns \c true if
the demarshalling succeeded, or false if an error occurred.
*/
bool QDBusMetaType::demarshall(const QDBusArgument &arg, QMetaType metaType, void *data)
{
int id = metaType.id();
QDBusMetaTypeId::init();
DemarshallFunction df;
{
QReadLocker locker(customTypesLock());
auto *ct = customTypes();
auto it = ct->constFind(id);
if (it == ct->cend())
return false; // non-existent
const QDBusCustomTypeInfo &info = *it;
if (!info.demarshall) {
df = nullptr; // make gcc happy
return false;
} else
df = info.demarshall;
}
#ifndef QT_BOOTSTRAPPED
QDBusArgument copy = arg;
df(copy, data);
#else
Q_UNUSED(arg);
Q_UNUSED(data);
Q_UNUSED(df);
#endif
return true;
}
/*!
\fn QDBusMetaType::signatureToType(const char *signature)
\internal
Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
by \a signature.
Note: this function only handles the basic D-Bus types.
\sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
QVariant::metaType()
*/
QMetaType QDBusMetaType::signatureToMetaType(const char *signature)
{
if (!signature)
return QMetaType(QMetaType::UnknownType);
QDBusMetaTypeId::init();
switch (signature[0])
{
case DBUS_TYPE_BOOLEAN:
return QMetaType(QMetaType::Bool);
case DBUS_TYPE_BYTE:
return QMetaType(QMetaType::UChar);
case DBUS_TYPE_INT16:
return QMetaType(QMetaType::Short);
case DBUS_TYPE_UINT16:
return QMetaType(QMetaType::UShort);
case DBUS_TYPE_INT32:
return QMetaType(QMetaType::Int);
case DBUS_TYPE_UINT32:
return QMetaType(QMetaType::UInt);
case DBUS_TYPE_INT64:
return QMetaType(QMetaType::LongLong);
case DBUS_TYPE_UINT64:
return QMetaType(QMetaType::ULongLong);
case DBUS_TYPE_DOUBLE:
return QMetaType(QMetaType::Double);
case DBUS_TYPE_STRING:
return QMetaType(QMetaType::QString);
case DBUS_TYPE_OBJECT_PATH:
return QDBusMetaTypeId::objectpath();
case DBUS_TYPE_SIGNATURE:
return QDBusMetaTypeId::signature();
case DBUS_TYPE_UNIX_FD:
return QDBusMetaTypeId::unixfd();
case DBUS_TYPE_VARIANT:
return QDBusMetaTypeId::variant();
case DBUS_TYPE_ARRAY: // special case
switch (signature[1]) {
case DBUS_TYPE_BYTE:
return QMetaType(QMetaType::QByteArray);
case DBUS_TYPE_STRING:
return QMetaType(QMetaType::QStringList);
case DBUS_TYPE_VARIANT:
return QMetaType(QMetaType::QVariantList);
case DBUS_TYPE_OBJECT_PATH:
return QMetaType::fromType<QList<QDBusObjectPath> >();
case DBUS_TYPE_SIGNATURE:
return QMetaType::fromType<QList<QDBusSignature> >();
}
Q_FALLTHROUGH();
default:
return QMetaType(QMetaType::UnknownType);
}
}
/*!
\fn QDBusMetaType::registerCustomType(QMetaType type, const QByteArray &signature)
\internal
Registers the meta type \a type to be represeneted by the given D-Bus \a signature.
This is used in qdbuscpp2xml for custom types which aren't known to the C++ type system.
*/
void QDBusMetaType::registerCustomType(QMetaType type, const QByteArray &signature)
{
auto *ct = customTypes();
QWriteLocker locker(customTypesLock());
auto &info = (*ct)[type.id()];
info.signature = signature;
// note how marshall/demarshall are not set, the type is never used at runtime
}
/*!
\fn QDBusMetaType::typeToSignature(int type)
\internal
Returns the D-Bus signature equivalent to the supplied meta type id \a type.
More types can be registered with the qDBusRegisterMetaType() function.
\sa QDBusUtil::isValidSingleSignature(), signatureToType(),
QVariant::metaType()
*/
const char *QDBusMetaType::typeToSignature(QMetaType type)
{
// check if it's a static type
switch (type.id())
{
case QMetaType::UChar:
return DBUS_TYPE_BYTE_AS_STRING;
case QMetaType::Bool:
return DBUS_TYPE_BOOLEAN_AS_STRING;
case QMetaType::Short:
return DBUS_TYPE_INT16_AS_STRING;
case QMetaType::UShort:
return DBUS_TYPE_UINT16_AS_STRING;
case QMetaType::Int:
return DBUS_TYPE_INT32_AS_STRING;
case QMetaType::UInt:
return DBUS_TYPE_UINT32_AS_STRING;
case QMetaType::LongLong:
return DBUS_TYPE_INT64_AS_STRING;
case QMetaType::ULongLong:
return DBUS_TYPE_UINT64_AS_STRING;
case QMetaType::Double:
return DBUS_TYPE_DOUBLE_AS_STRING;
case QMetaType::QString:
return DBUS_TYPE_STRING_AS_STRING;
case QMetaType::QStringList:
return DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_STRING_AS_STRING; // as
case QMetaType::QByteArray:
return DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING; // ay
}
QDBusMetaTypeId::init();
if (type == QDBusMetaTypeId::variant())
return DBUS_TYPE_VARIANT_AS_STRING;
else if (type == QDBusMetaTypeId::objectpath())
return DBUS_TYPE_OBJECT_PATH_AS_STRING;
else if (type == QDBusMetaTypeId::signature())
return DBUS_TYPE_SIGNATURE_AS_STRING;
else if (type == QDBusMetaTypeId::unixfd())
return DBUS_TYPE_UNIX_FD_AS_STRING;
// try the database
auto *ct = customTypes();
{
QReadLocker locker(customTypesLock());
auto it = ct->constFind(type.id());
if (it == ct->end())
return nullptr;
const QDBusCustomTypeInfo &info = *it;
if (!info.signature.isNull())
return info.signature;
if (!info.marshall)
return nullptr; // type not registered with us
}
// call to user code to construct the signature type
QDBusCustomTypeInfo *info;
{
// createSignature will never return a null QByteArray
// if there was an error, it'll return ""
QByteArray signature = QDBusArgumentPrivate::createSignature(type.id());
// re-acquire lock
QWriteLocker locker(customTypesLock());
info = &(*ct)[type.id()];
info->signature = signature;
}
return info->signature;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

46
src/dbus/qdbusmetatype.h Normal file
View File

@ -0,0 +1,46 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSMETATYPE_H
#define QDBUSMETATYPE_H
#include <QtDBus/qtdbusglobal.h>
#include "QtCore/qmetatype.h"
#include <QtDBus/qdbusargument.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class Q_DBUS_EXPORT QDBusMetaType
{
public:
typedef void (*MarshallFunction)(QDBusArgument &, const void *);
typedef void (*DemarshallFunction)(const QDBusArgument &, void *);
static void registerMarshallOperators(QMetaType typeId, MarshallFunction, DemarshallFunction);
static bool marshall(QDBusArgument &, QMetaType id, const void *data);
static bool demarshall(const QDBusArgument &, QMetaType id, void *data);
static void registerCustomType(QMetaType type, const QByteArray &signature);
static QMetaType signatureToMetaType(const char *signature);
static const char *typeToSignature(QMetaType type);
};
template<typename T>
QMetaType qDBusRegisterMetaType()
{
auto mf = [](QDBusArgument &arg, const void *t) { arg << *static_cast<const T *>(t); };
auto df = [](const QDBusArgument &arg, void *t) { arg >> *static_cast<T *>(t); };
QMetaType metaType = QMetaType::fromType<T>();
QDBusMetaType::registerMarshallOperators(metaType, mf, df);
return metaType;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,68 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSMETATYPE_P_H
#define QDBUSMETATYPE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qdbusmetatype.h>
#include <qdbusmessage.h>
#include <qdbusargument.h>
#include <qdbusextratypes.h>
#include <qdbuserror.h>
#include <qdbusunixfiledescriptor.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
struct QDBusMetaTypeId
{
static QMetaType message(); // QDBusMessage
static QMetaType argument(); // QDBusArgument
static QMetaType variant(); // QDBusVariant
static QMetaType objectpath(); // QDBusObjectPath
static QMetaType signature(); // QDBusSignature
static QMetaType error(); // QDBusError
static QMetaType unixfd(); // QDBusUnixFileDescriptor
static void init();
};
inline QMetaType QDBusMetaTypeId::message()
{ return QMetaType::fromType<QDBusMessage>(); }
inline QMetaType QDBusMetaTypeId::argument()
{ return QMetaType::fromType<QDBusArgument>(); }
inline QMetaType QDBusMetaTypeId::variant()
{ return QMetaType::fromType<QDBusVariant>(); }
inline QMetaType QDBusMetaTypeId::objectpath()
{ return QMetaType::fromType<QDBusObjectPath>(); }
inline QMetaType QDBusMetaTypeId::signature()
{ return QMetaType::fromType<QDBusSignature>(); }
inline QMetaType QDBusMetaTypeId::error()
{ return QMetaType::fromType<QDBusError>(); }
inline QMetaType QDBusMetaTypeId::unixfd()
{ return QMetaType::fromType<QDBusUnixFileDescriptor>(); }
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

182
src/dbus/qdbusmisc.cpp Normal file
View File

@ -0,0 +1,182 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <string.h>
#ifndef QT_BOOTSTRAPPED
#include <QtCore/qcoreapplication.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qvariant.h>
#include "qdbusutil_p.h"
#include "qdbusconnection_p.h"
#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
#endif
#include "qdbusmetatype_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
bool qDBusCheckAsyncTag(const char *tag)
{
static const char noReplyTag[] = "Q_NOREPLY";
if (!tag || !*tag)
return false;
const char *p = strstr(tag, noReplyTag);
if (p != nullptr &&
(p == tag || *(p-1) == ' ') &&
(p[sizeof noReplyTag - 1] == '\0' || p[sizeof noReplyTag - 1] == ' '))
return true;
return false;
}
#ifndef QT_BOOTSTRAPPED
QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
{
QString interface;
int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
if (idx >= mo->classInfoOffset()) {
interface = QLatin1StringView(mo->classInfo(idx).value());
} else {
interface = QLatin1StringView(mo->className());
interface.replace("::"_L1, "."_L1);
if (interface.startsWith("QDBus"_L1)) {
interface.prepend("org.qtproject.QtDBus."_L1);
} else if (interface.startsWith(u'Q') &&
interface.size() >= 2 && interface.at(1).isUpper()) {
// assume it's Qt
interface.prepend("org.qtproject.Qt."_L1);
} else if (!QCoreApplication::instance()||
QCoreApplication::instance()->applicationName().isEmpty()) {
interface.prepend("local."_L1);
} else {
interface.prepend(u'.').prepend(QCoreApplication::instance()->applicationName());
const QString organizationDomain = QCoreApplication::instance()->organizationDomain();
const auto domainName = QStringView{organizationDomain}.split(u'.', Qt::SkipEmptyParts);
if (domainName.isEmpty()) {
interface.prepend("local."_L1);
} else {
QString composedDomain;
// + 1 for additional dot, e.g. organizationDomain equals "example.com",
// then composedDomain will be equal "com.example."
composedDomain.reserve(organizationDomain.size() + 1);
for (auto it = domainName.rbegin(), end = domainName.rend(); it != end; ++it)
composedDomain += *it + u'.';
interface.prepend(composedDomain);
}
}
}
return interface;
}
bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
{
const QMetaObject *mo = obj->metaObject();
for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
if (interface_name == qDBusInterfaceFromMetaObject(mo))
return true;
return false;
}
// calculates the metatypes for the method
// the slot must have the parameters in the following form:
// - zero or more value or const-ref parameters of any kind
// - zero or one const ref of QDBusMessage
// - zero or more non-const ref parameters
// No parameter may be a template.
// this function returns -1 if the parameters don't match the above form
// this function returns the number of *input* parameters, including the QDBusMessage one if any
// this function does not check the return type, so metaTypes[0] is always 0 and always present
// metaTypes.count() >= retval + 1 in all cases
//
// sig must be the normalised signature for the method
int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg)
{
return qDBusParametersForMethod(mm.parameterTypes(), metaTypes, errorMsg);
}
#endif // QT_BOOTSTRAPPED
int qDBusParametersForMethod(const QList<QByteArray> &parameterTypes, QList<QMetaType> &metaTypes,
QString &errorMsg)
{
QDBusMetaTypeId::init();
metaTypes.clear();
metaTypes.append(QMetaType()); // return type
int inputCount = 0;
bool seenMessage = false;
QList<QByteArray>::ConstIterator it = parameterTypes.constBegin();
QList<QByteArray>::ConstIterator end = parameterTypes.constEnd();
for ( ; it != end; ++it) {
QByteArray type = *it;
if (type.endsWith('*')) {
errorMsg = "Pointers are not supported: "_L1 + QLatin1StringView(type);
return -1;
}
if (type.endsWith('&')) {
QByteArray basictype = type;
basictype.truncate(type.size() - 1);
QMetaType id = QMetaType::fromName(basictype);
if (!id.isValid()) {
errorMsg = "Unregistered output type in parameter list: "_L1 + QLatin1StringView(type);
return -1;
} else if (QDBusMetaType::typeToSignature(id) == nullptr)
return -1;
metaTypes.append(id);
seenMessage = true; // it cannot appear anymore anyways
continue;
}
if (seenMessage) { // && !type.endsWith('&')
errorMsg = "Invalid method, non-output parameters after message or after output parameters: "_L1 + QLatin1StringView(type);
return -1; // not allowed
}
if (type.startsWith("QVector<"))
type = "QList<" + type.mid(sizeof("QVector<") - 1);
QMetaType id = QMetaType::fromName(type);
#ifdef QT_BOOTSTRAPPED
// in bootstrap mode QDBusMessage isn't included, thus we need to resolve it manually here
if (type == "QDBusMessage") {
id = QDBusMetaTypeId::message();
}
#endif
if (!id.isValid()) {
errorMsg = "Unregistered input type in parameter list: "_L1 + QLatin1StringView(type);
return -1;
}
if (id == QDBusMetaTypeId::message())
seenMessage = true;
else if (QDBusMetaType::typeToSignature(id) == nullptr) {
errorMsg = "Type not registered with QtDBus in parameter list: "_L1 + QLatin1StringView(type);
return -1;
}
metaTypes.append(id);
++inputCount;
}
return inputCount;
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

View File

@ -0,0 +1,519 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbuspendingcall.h"
#include "qdbuspendingcall_p.h"
#include "qdbusconnection_p.h"
#include "qdbusmetatype_p.h"
#include "qdbusutil_p.h"
#include "qcoreapplication.h"
#include "qcoreevent.h"
#include <private/qobject_p.h>
#include <private/qlocking_p.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
/*!
\class QDBusPendingCall
\inmodule QtDBus
\ingroup shared
\since 4.5
\brief The QDBusPendingCall class refers to one pending asynchronous call.
A QDBusPendingCall object is a reference to a method call that was
sent over D-Bus without waiting for a reply. QDBusPendingCall is an
opaque type, meant to be used as a handle for a pending reply.
In most programs, the QDBusPendingCall class will not be used
directly. It can be safely replaced with the template-based
QDBusPendingReply, in order to access the contents of the reply or
wait for it to be complete.
The QDBusPendingCallWatcher class allows one to connect to a signal
that will indicate when the reply has arrived or if the call has
timed out. It also provides the
QDBusPendingCallWatcher::waitForFinished() method which will suspend
the execution of the program until the reply has arrived.
\note If you create a copy of a QDBusPendingCall object, all
information will be shared among the many copies. Therefore,
QDBusPendingCall is an explicitly-shared object and does not
provide a method of detaching the copies (since they refer
to the same pending call)
\sa QDBusPendingReply, QDBusPendingCallWatcher
*/
/*!
\class QDBusPendingCallWatcher
\inmodule QtDBus
\since 4.5
\brief The QDBusPendingCallWatcher class provides a convenient way for
waiting for asynchronous replies.
The QDBusPendingCallWatcher provides the finished() signal that will be
emitted when a reply arrives.
It is usually used like the following example:
\snippet code/src_qdbus_qdbuspendingcall.cpp 0
Note that it is not necessary to keep the original QDBusPendingCall
object around since QDBusPendingCallWatcher inherits from that class
too.
The slot connected to by the above code could be something similar
to the following:
\snippet code/src_qdbus_qdbuspendingcall.cpp 1
Note the use of QDBusPendingReply to validate the argument types in
the reply. If the reply did not contain exactly two arguments
(one string and one QByteArray), QDBusPendingReply::isError() will
return true.
\sa QDBusPendingReply
*/
/*!
\fn void QDBusPendingCallWatcher::finished(QDBusPendingCallWatcher *self)
This signal is emitted when the pending call has finished and its
reply is available. The \a self parameter is a pointer to the
object itself, passed for convenience so that the slot can access
the properties and determine the contents of the reply.
*/
void QDBusPendingCallWatcherHelper::add(QDBusPendingCallWatcher *watcher)
{
connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
}
QDBusPendingCallPrivate::~QDBusPendingCallPrivate()
{
if (pending) {
q_dbus_pending_call_cancel(pending);
q_dbus_pending_call_unref(pending);
}
delete watcherHelper;
}
bool QDBusPendingCallPrivate::setReplyCallback(QObject *target, const char *member)
{
receiver = target;
metaTypes.clear();
methodIdx = -1;
if (!target)
return true;; // unsetting
if (!member || !*member) {
// would not be able to deliver a reply
qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
target ? target->metaObject()->className() : "(null)",
member ? member + 1 : "(null)",
target ? qPrintable(target->objectName()) : "no name");
return false;
}
QString errorMsg;
methodIdx = QDBusConnectionPrivate::findSlot(target, member + 1, metaTypes, errorMsg);
if (methodIdx == -1) {
QByteArray normalizedName = QMetaObject::normalizedSignature(member + 1);
methodIdx = QDBusConnectionPrivate::findSlot(target, normalizedName, metaTypes, errorMsg);
}
if (methodIdx == -1) {
// would not be able to deliver a reply
qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s) "
"because %s",
target->metaObject()->className(), member + 1, qPrintable(target->objectName()),
qPrintable(errorMsg));
return false;
}
// success
// construct the expected signature
int count = metaTypes.size() - 1;
if (count == 1 && metaTypes.at(1) == QDBusMetaTypeId::message()) {
// wildcard slot, can receive anything, so don't set the signature
return true;
}
if (metaTypes.at(count) == QDBusMetaTypeId::message())
--count;
setMetaTypes(count, count ? metaTypes.constData() + 1 : nullptr);
return true;
}
void QDBusPendingCallPrivate::setMetaTypes(int count, const QMetaType *types)
{
if (count == 0) {
expectedReplySignature = ""_L1; // not null
return;
}
QByteArray sig;
sig.reserve(count + count / 2);
for (int i = 0; i < count; ++i) {
const char *typeSig = QDBusMetaType::typeToSignature(types[i]);
if (Q_UNLIKELY(!typeSig))
qFatal("QDBusPendingReply: type %s is not registered with QtDBus", types[i].name());
sig += typeSig;
}
expectedReplySignature = QString::fromLatin1(sig);
}
void QDBusPendingCallPrivate::checkReceivedSignature()
{
// MUST BE CALLED WITH A LOCKED MUTEX!
if (replyMessage.type() == QDBusMessage::InvalidMessage)
return; // not yet finished - no message to
// validate against
if (replyMessage.type() == QDBusMessage::ErrorMessage)
return; // we don't have to check the signature of an error reply
if (expectedReplySignature.isNull())
return; // no signature to validate against
// can't use startsWith here because a null string doesn't start or end with an empty string
if (replyMessage.signature().indexOf(expectedReplySignature) != 0) {
const auto errorMsg = "Unexpected reply signature: got \"%1\", expected \"%2\""_L1;
replyMessage = QDBusMessage::createError(
QDBusError::InvalidSignature,
errorMsg.arg(replyMessage.signature(), expectedReplySignature));
}
}
void QDBusPendingCallPrivate::waitForFinished()
{
const auto locker = qt_scoped_lock(mutex);
if (replyMessage.type() != QDBusMessage::InvalidMessage)
return; // already finished
waitForFinishedCondition.wait(&mutex);
}
/*!
Creates a copy of the \a other pending asynchronous call. Note
that both objects will refer to the same pending call.
*/
QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other)
: d(other.d)
{
}
/*!
\internal
*/
QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
: d(dd)
{
if (dd) {
bool r = dd->ref.deref();
Q_ASSERT(r);
Q_UNUSED(r);
}
}
/*!
Destroys this copy of the QDBusPendingCall object. If this copy is
also the last copy of a pending asynchronous call, the call will
be canceled and no further notifications will be received. There
will be no way of accessing the reply's contents when it arrives.
*/
QDBusPendingCall::~QDBusPendingCall()
{
// d deleted by QExplicitlySharedDataPointer
}
/*!
Creates a copy of the \a other pending asynchronous call and drops
the reference to the previously-referenced call. Note that both
objects will refer to the same pending call after this function.
If this object contained the last reference of a pending
asynchronous call, the call will be canceled and no further
notifications will be received. There will be no way of accessing
the reply's contents when it arrives.
*/
QDBusPendingCall &QDBusPendingCall::operator=(const QDBusPendingCall &other)
{
d = other.d;
return *this;
}
/*!
\fn void QDBusPendingCall::swap(QDBusPendingCall &other)
\since 5.0
Swaps this pending call instance with \a other. This function is
very fast and never fails.
*/
/*!
\fn bool QDBusPendingCallWatcher::isFinished() const
Returns \c true if the pending call has finished processing and the
reply has been received.
Note that this function only changes state if you call
waitForFinished() or if an external D-Bus event happens, which in
general only happens if you return to the event loop execution.
\sa QDBusPendingReply::isFinished()
*/
/*!
\fn template <typename... Types> bool QDBusPendingReply<Types...>::isFinished() const
Returns \c true if the pending call has finished processing and the
reply has been received. If this function returns \c true, the
isError(), error() and reply() methods should return valid
information.
Note that this function only changes state if you call
waitForFinished() or if an external D-Bus event happens, which in
general only happens if you return to the event loop execution.
\sa QDBusPendingCallWatcher::isFinished()
*/
bool QDBusPendingCall::isFinished() const
{
if (!d)
return true; // considered finished
const auto locker = qt_scoped_lock(d->mutex);
return d->replyMessage.type() != QDBusMessage::InvalidMessage;
}
void QDBusPendingCall::waitForFinished()
{
if (d) d->waitForFinished();
}
/*!
\fn template <typename... Types> bool QDBusPendingReply<Types...>::isValid() const
Returns \c true if the reply contains a normal reply message, false
if it contains anything else.
If the pending call has not finished processing, this function
return false.
*/
bool QDBusPendingCall::isValid() const
{
if (!d)
return false;
const auto locker = qt_scoped_lock(d->mutex);
return d->replyMessage.type() == QDBusMessage::ReplyMessage;
}
/*!
\fn template <typename... Types> bool QDBusPendingReply<Types...>::isError() const
Returns \c true if the reply contains an error message, false if it
contains a normal method reply.
If the pending call has not finished processing, this function
also returns \c true.
*/
bool QDBusPendingCall::isError() const
{
if (!d)
return true; // considered finished and an error
const auto locker = qt_scoped_lock(d->mutex);
return d->replyMessage.type() == QDBusMessage::ErrorMessage;
}
/*!
\fn template <typename... Types> QDBusError QDBusPendingReply<Types...>::error() const
Retrieves the error content of the reply message, if it has
finished processing. If the reply message has not finished
processing or if it contains a normal reply message (non-error),
this function returns an invalid QDBusError.
*/
QDBusError QDBusPendingCall::error() const
{
if (d) {
const auto locker = qt_scoped_lock(d->mutex);
return QDBusError(d->replyMessage);
}
// not connected, return an error
QDBusError err = QDBusError(QDBusError::Disconnected,
QDBusUtil::disconnectedErrorMessage());
return err;
}
/*!
\fn template <typename... Types> QDBusMessage QDBusPendingReply<Types...>::reply() const
Retrieves the reply message received for the asynchronous call
that was sent, if it has finished processing. If the pending call
is not finished, this function returns a QDBusMessage of type
QDBusMessage::InvalidMessage.
After it has finished processing, the message type will either be
an error message or a normal method reply message.
*/
QDBusMessage QDBusPendingCall::reply() const
{
if (!d)
return QDBusMessage::createError(error());
const auto locker = qt_scoped_lock(d->mutex);
return d->replyMessage;
}
#if 0
/*
Sets the slot \a member in object \a target to be called when the
reply arrives. The slot's parameter list must match the reply
message's arguments for it to be called.
It may, optionally, contain a QDBusMessage final parameter. If it
is present, the parameter will contain the reply message object.
The callback will not be called if the reply is an error message.
This function returns \c true if it could set the callback, false
otherwise. It is not a guarantee that the callback will be
called.
\warning QDBusPendingCall only supports one callback per pending
asynchronous call, even if multiple QDBusPendingCall
objects are referencing the same pending call.
*/
bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
{
if (!d)
return false;
return d->setReplyCallback(target, member);
}
#endif
/*!
\since 4.6
Creates a QDBusPendingCall object based on the error condition
\a error. The resulting pending call object will be in the
"finished" state and QDBusPendingReply<Types...>::isError() will return true.
\sa fromCompletedCall()
*/
QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
{
return fromCompletedCall(QDBusMessage::createError(error));
}
/*!
\since 4.6
Creates a QDBusPendingCall object based on the message \a msg.
The message must be of type QDBusMessage::ErrorMessage or
QDBusMessage::ReplyMessage (that is, a message that is typical
of a completed call).
This function is useful for code that requires simulating a pending
call, but that has already finished.
\sa fromError()
*/
QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
{
QDBusPendingCallPrivate *d = nullptr;
if (msg.type() == QDBusMessage::ErrorMessage ||
msg.type() == QDBusMessage::ReplyMessage) {
d = new QDBusPendingCallPrivate(QDBusMessage(), nullptr);
d->replyMessage = msg;
d->ref.storeRelaxed(1);
}
return QDBusPendingCall(d);
}
class QDBusPendingCallWatcherPrivate: public QObjectPrivate
{
public:
void _q_finished();
Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
};
inline void QDBusPendingCallWatcherPrivate::_q_finished()
{
Q_Q(QDBusPendingCallWatcher);
emit q->finished(q);
}
/*!
Creates a QDBusPendingCallWatcher object to watch for replies on the
asynchronous pending call \a call and sets this object's parent
to \a parent.
*/
QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
: QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
{
if (d) { // QDBusPendingCall::d
const auto locker = qt_scoped_lock(d->mutex);
if (!d->watcherHelper) {
d->watcherHelper = new QDBusPendingCallWatcherHelper;
if (d->replyMessage.type() != QDBusMessage::InvalidMessage) {
// cause a signal emission anyways
QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection);
}
}
d->watcherHelper->add(this);
}
}
/*!
Destroys this object. If this QDBusPendingCallWatcher object was the
last reference to the unfinished pending call, the call will be
canceled.
*/
QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
{
}
/*!
\fn void QDBusPendingCallWatcher::waitForFinished()
Suspends the execution of the calling thread until the reply is
received and processed. After this function returns, isFinished()
should return true, indicating the reply's contents are ready to
be processed.
\sa QDBusPendingReply::waitForFinished()
*/
void QDBusPendingCallWatcher::waitForFinished()
{
if (d) {
d->waitForFinished();
// our signals were queued, so deliver them
QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
}
}
QT_END_NAMESPACE
#include "moc_qdbuspendingcall_p.cpp"
#endif // QT_NO_DBUS
#include "moc_qdbuspendingcall.cpp"

View File

@ -0,0 +1,85 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSPENDINGCALL_H
#define QDBUSPENDINGCALL_H
#include <QtDBus/qtdbusglobal.h>
#include <QtDBus/qdbusmessage.h>
#include <QtCore/qobject.h>
#include <QtCore/qshareddata.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnection;
class QDBusError;
class QDBusPendingCallWatcher;
class QDBusPendingCallPrivate;
class Q_DBUS_EXPORT QDBusPendingCall
{
public:
QDBusPendingCall(const QDBusPendingCall &other);
~QDBusPendingCall();
QDBusPendingCall &operator=(QDBusPendingCall &&other) noexcept { swap(other); return *this; }
QDBusPendingCall &operator=(const QDBusPendingCall &other);
void swap(QDBusPendingCall &other) noexcept { d.swap(other.d); }
#ifndef Q_QDOC
// pretend that they aren't here
bool isFinished() const;
void waitForFinished();
bool isError() const;
bool isValid() const;
QDBusError error() const;
QDBusMessage reply() const;
#endif
static QDBusPendingCall fromError(const QDBusError &error);
static QDBusPendingCall fromCompletedCall(const QDBusMessage &message);
protected:
QExplicitlySharedDataPointer<QDBusPendingCallPrivate> d;
friend class QDBusPendingCallPrivate;
friend class QDBusPendingCallWatcher;
friend class QDBusConnection;
QDBusPendingCall(QDBusPendingCallPrivate *dd);
private:
QDBusPendingCall(); // not defined
};
Q_DECLARE_SHARED(QDBusPendingCall)
class QDBusPendingCallWatcherPrivate;
class Q_DBUS_EXPORT QDBusPendingCallWatcher: public QObject, public QDBusPendingCall
{
Q_OBJECT
public:
explicit QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent = nullptr);
~QDBusPendingCallWatcher();
#ifdef Q_QDOC
// trick qdoc into thinking this method is here
bool isFinished() const;
#endif
void waitForFinished(); // non-virtual override
Q_SIGNALS:
void finished(QDBusPendingCallWatcher *self = nullptr);
private:
Q_DECLARE_PRIVATE(QDBusPendingCallWatcher)
Q_PRIVATE_SLOT(d_func(), void _q_finished())
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,101 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSPENDINGCALL_P_H
#define QDBUSPENDINGCALL_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qlist.h>
#include <qmutex.h>
#include <qpointer.h>
#include <qshareddata.h>
#include <qwaitcondition.h>
#include "qdbusmessage.h"
#include "qdbus_symbols_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusPendingCall;
class QDBusPendingCallWatcher;
class QDBusPendingCallWatcherHelper;
class QDBusConnectionPrivate;
class QDBusPendingCallPrivate: public QSharedData
{
public:
// {
// set only during construction:
const QDBusMessage sentMessage;
QDBusConnectionPrivate * const connection;
// for the callback mechanism (see setReplyCallback and QDBusConnectionPrivate::sendWithReplyAsync)
QPointer<QObject> receiver;
QList<QMetaType> metaTypes;
int methodIdx;
// }
mutable QMutex mutex;
QWaitCondition waitForFinishedCondition;
// {
// protected by the mutex above:
QDBusPendingCallWatcherHelper *watcherHelper;
QDBusMessage replyMessage;
DBusPendingCall *pending;
QString expectedReplySignature;
// }
QDBusPendingCallPrivate(const QDBusMessage &sent, QDBusConnectionPrivate *connection)
: sentMessage(sent), connection(connection), watcherHelper(nullptr), pending(nullptr)
{ }
~QDBusPendingCallPrivate();
bool setReplyCallback(QObject *target, const char *member);
void waitForFinished();
void setMetaTypes(int count, const QMetaType *types);
void checkReceivedSignature();
static QDBusPendingCall fromMessage(const QDBusMessage &msg);
};
class QDBusPendingCallWatcherHelper: public QObject
{
Q_OBJECT
public:
void add(QDBusPendingCallWatcher *watcher);
void emitSignals(const QDBusMessage &replyMessage, const QDBusMessage &sentMessage)
{
if (replyMessage.type() == QDBusMessage::ReplyMessage)
emit reply(replyMessage);
else
emit error(QDBusError(replyMessage), sentMessage);
emit finished();
}
Q_SIGNALS:
void finished();
void reply(const QDBusMessage &msg);
void error(const QDBusError &error, const QDBusMessage &msg);
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,249 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbuspendingreply.h"
#include "qdbuspendingcall_p.h"
#include "qdbusmetatype.h"
#include <QtCore/private/qlocking_p.h>
#ifndef QT_NO_DBUS
/*!
\class QDBusPendingReply
\inmodule QtDBus
\since 4.5
\brief The QDBusPendingReply class contains the reply to an asynchronous method call.
The QDBusPendingReply is a variadic template class. The template parameters
are the types that will be used to extract the contents of the reply's data.
This class is similar in functionality to QDBusReply, but with two
important differences:
\list
\li QDBusReply accepts exactly one return type, whereas
QDBusPendingReply can have any number of types
\li QDBusReply only works on already completed replies, whereas
QDBusPendingReply allows one to wait for replies from pending
calls
\endlist
Where with QDBusReply you would write:
\snippet code/src_qdbus_qdbusreply.cpp 0
with QDBusPendingReply, the equivalent code (including the blocking
wait for the reply) would be:
\snippet code/src_qdbus_qdbuspendingreply.cpp 0
For method calls that have more than one output argument, with
QDBusReply, you would write:
\snippet code/src_qdbus_qdbusreply.cpp 1
whereas with QDBusPendingReply, all of the output arguments should
be template parameters:
\snippet code/src_qdbus_qdbuspendingreply.cpp 2
QDBusPendingReply objects can be associated with
QDBusPendingCallWatcher objects, which emit signals when the reply
arrives.
\sa QDBusPendingCallWatcher, QDBusReply
*/
/*!
\fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply()
Creates an empty QDBusPendingReply object. Without assigning a
QDBusPendingCall object to this reply, QDBusPendingReply cannot do
anything. All functions return their failure values.
*/
/*!
\fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply(const QDBusPendingReply &other)
Creates a copy of the \a other QDBusPendingReply object. Just like
QDBusPendingCall and QDBusPendingCallWatcher, this QDBusPendingReply
object will share the same pending call reference. All copies
share the same return values.
*/
/*!
\fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply(const QDBusPendingCall &call)
Creates a QDBusPendingReply object that will take its contents from
the \a call pending asynchronous call. This QDBusPendingReply object
will share the same pending call reference as \a call.
*/
/*!
\fn template<typename... Types> QDBusPendingReply<Types...>::QDBusPendingReply(const QDBusMessage &message)
Creates a QDBusPendingReply object that will take its contents from
the message \a message. In this case, this object will be already
in its finished state and the reply's contents will be accessible.
\sa isFinished()
*/
/*!
\fn template<typename... Types> QDBusPendingReply &QDBusPendingReply<Types...>::operator=(const QDBusPendingReply &other)
Makes a copy of \a other and drops the reference to the current
pending call. If the current reference is to an unfinished pending
call and this is the last reference, the pending call will be
canceled and there will be no way of retrieving the reply's
contents, when they arrive.
*/
/*!
\fn template<typename... Types> QDBusPendingReply &QDBusPendingReply<Types...>::operator=(const QDBusPendingCall &call)
Makes this object take its contents from the \a call pending call
and drops the reference to the current pending call. If the
current reference is to an unfinished pending call and this is the
last reference, the pending call will be canceled and there will
be no way of retrieving the reply's contents, when they arrive.
*/
/*!
\fn template<typename... Types> QDBusPendingReply &QDBusPendingReply<Types...>::operator=(const QDBusMessage &message)
Makes this object take its contents from the \a message message
and drops the reference to the current pending call. If the
current reference is to an unfinished pending call and this is the
last reference, the pending call will be canceled and there will
be no way of retrieving the reply's contents, when they arrive.
After this function is finished, the QDBusPendingReply object will
be in its "finished" state and the \a message contents will be
accessible.
\sa isFinished()
*/
/*!
\enum QDBusPendingReply::anonymous
\value Count The number of arguments the reply is expected to have
*/
/*!
\fn template<typename... Types> int QDBusPendingReply<Types...>::count() const
Return the number of arguments the reply is supposed to have. This
number matches the number of non-void template parameters in this
class.
If the reply arrives with a different number of arguments (or with
different types), it will be transformed into an error reply
indicating a bad signature.
*/
/*!
\fn template<typename... Types> QVariant QDBusPendingReply<Types...>::argumentAt(int index) const
Returns the argument at position \a index in the reply's
contents. If the reply doesn't have that many elements, this
function's return value is undefined (will probably cause an
assertion failure), so it is important to verify that the
processing is finished and the reply is valid.
If the reply does not contain an argument at position \a index or if the
reply was an error, this function returns an invalid QVariant. Since D-Bus
messages can never contain invalid QVariants, this return can be used to
detect an error condition.
*/
/*!
\fn template<typename... Types> typename Select<0>::Type QDBusPendingReply<Types...>::value() const
Returns the first argument in this reply, cast to type \c Types[0] (the
first template parameter of this class). This is equivalent to
calling argumentAt<0>().
This function is provided as a convenience, matching the
QDBusReply::value() function.
Note that, if the reply hasn't arrived, this function causes the
calling thread to block until the reply is processed.
If the reply is an error reply, this function returns a default-constructed
\c Types[0] object, which may be indistinguishable from a valid value. To
reliably determine whether the message was an error, use isError().
*/
/*!
\fn template<typename... Types> QDBusPendingReply<Types...>::operator typename Select<0>::Type() const
Returns the first argument in this reply, cast to type \c Types[0] (the
first template parameter of this class). This is equivalent to
calling argumentAt<0>().
This function is provided as a convenience, matching the
QDBusReply::value() function.
Note that, if the reply hasn't arrived, this function causes the
calling thread to block until the reply is processed.
If the reply is an error reply, this function returns a default-constructed
\c Types[0] object, which may be indistinguishable from a valid value. To
reliably determine whether the message was an error, use isError().
*/
/*!
\fn template<typename... Types> void QDBusPendingReply<Types...>::waitForFinished()
Suspends the execution of the calling thread until the reply is
received and processed. After this function returns, isFinished()
should return true, indicating the reply's contents are ready to
be processed.
\sa QDBusPendingCallWatcher::waitForFinished()
*/
QDBusPendingReplyBase::QDBusPendingReplyBase()
: QDBusPendingCall(nullptr) // initialize base class empty
{
}
QDBusPendingReplyBase::~QDBusPendingReplyBase()
{
}
void QDBusPendingReplyBase::assign(const QDBusPendingCall &other)
{
QDBusPendingCall::operator=(other);
}
void QDBusPendingReplyBase::assign(const QDBusMessage &message)
{
d = new QDBusPendingCallPrivate(QDBusMessage(), nullptr); // drops the reference to the old one
d->replyMessage = message;
}
QVariant QDBusPendingReplyBase::argumentAt(int index) const
{
if (!d)
return QVariant();
d->waitForFinished(); // bypasses "const"
return d->replyMessage.arguments().value(index);
}
void QDBusPendingReplyBase::setMetaTypes(int count, const QMetaType *types)
{
Q_ASSERT(d);
const auto locker = qt_scoped_lock(d->mutex);
d->setMetaTypes(count, types);
d->checkReceivedSignature();
}
#endif // QT_NO_DBUS

View File

@ -0,0 +1,173 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSPENDINGREPLY_H
#define QDBUSPENDINGREPLY_H
#include <QtDBus/qtdbusglobal.h>
#include <QtDBus/qdbusargument.h>
#include <QtDBus/qdbuspendingcall.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class Q_DBUS_EXPORT QDBusPendingReplyBase : public QDBusPendingCall
{
protected:
QDBusPendingReplyBase();
~QDBusPendingReplyBase();
void assign(const QDBusPendingCall &call);
void assign(const QDBusMessage &message);
QVariant argumentAt(int index) const;
void setMetaTypes(int count, const QMetaType *metaTypes);
};
namespace QDBusPendingReplyTypes {
template<int Index, typename T, typename... Types>
struct Select
{
typedef Select<Index - 1, Types...> Next;
typedef typename Next::Type Type;
};
template<typename T, typename... Types>
struct Select<0, T, Types...>
{
typedef T Type;
};
template<typename T> inline QMetaType metaTypeFor()
{ return QMetaType::fromType<T>(); }
// specialize for QVariant, allowing it to be used in place of QDBusVariant
template<> inline QMetaType metaTypeFor<QVariant>()
{ return QMetaType::fromType<QDBusVariant>(); }
}
template<typename... Types>
class QDBusPendingReply : public QDBusPendingReplyBase
{
template<int Index> using Select = QDBusPendingReplyTypes::Select<Index, Types...>;
public:
enum { Count = std::is_same_v<typename Select<0>::Type, void> ? 0 : sizeof...(Types) };
inline constexpr int count() const { return Count; }
inline QDBusPendingReply() = default;
inline QDBusPendingReply(const QDBusPendingReply &other)
: QDBusPendingReplyBase(other)
{ }
inline Q_IMPLICIT QDBusPendingReply(const QDBusPendingCall &call) // required by qdbusxml2cpp-generated code
{ *this = call; }
inline Q_IMPLICIT QDBusPendingReply(const QDBusMessage &message)
{ *this = message; }
inline QDBusPendingReply &operator=(const QDBusPendingReply &other)
{ assign(other); return *this; }
inline QDBusPendingReply &operator=(const QDBusPendingCall &call)
{ assign(call); return *this; }
inline QDBusPendingReply &operator=(const QDBusMessage &message)
{ assign(message); return *this; }
using QDBusPendingReplyBase::argumentAt;
template<int Index> inline
typename Select<Index>::Type argumentAt() const
{
static_assert(Index >= 0 && Index < Count, "Index out of bounds");
typedef typename Select<Index>::Type ResultType;
return qdbus_cast<ResultType>(argumentAt(Index));
}
#if defined(Q_QDOC)
bool isFinished() const;
void waitForFinished();
QVariant argumentAt(int index) const;
bool isValid() const;
bool isError() const;
QDBusError error() const;
QDBusMessage reply() const;
#endif
inline typename Select<0>::Type value() const
{
return argumentAt<0>();
}
inline operator typename Select<0>::Type() const
{
return argumentAt<0>();
}
private:
inline void calculateMetaTypes()
{
if (!d) return;
if constexpr (Count == 0) {
setMetaTypes(0, nullptr);
} else {
std::array<QMetaType, Count> typeIds = { QDBusPendingReplyTypes::metaTypeFor<Types>()... };
setMetaTypes(Count, typeIds.data());
}
}
inline void assign(const QDBusPendingCall &call)
{
QDBusPendingReplyBase::assign(call);
calculateMetaTypes();
}
inline void assign(const QDBusMessage &message)
{
QDBusPendingReplyBase::assign(message);
calculateMetaTypes();
}
};
template<>
class QDBusPendingReply<> : public QDBusPendingReplyBase
{
public:
enum { Count = 0 };
inline int count() const { return Count; }
inline QDBusPendingReply() = default;
inline QDBusPendingReply(const QDBusPendingReply &other)
: QDBusPendingReplyBase(other)
{ }
inline Q_IMPLICIT QDBusPendingReply(const QDBusPendingCall &call) // required by qdbusxml2cpp-generated code
{ *this = call; }
inline Q_IMPLICIT QDBusPendingReply(const QDBusMessage &message)
{ *this = message; }
inline QDBusPendingReply &operator=(const QDBusPendingReply &other)
{ assign(other); return *this; }
inline QDBusPendingReply &operator=(const QDBusPendingCall &call)
{ assign(call); return *this; }
inline QDBusPendingReply &operator=(const QDBusMessage &message)
{ assign(message); return *this; }
private:
inline void assign(const QDBusPendingCall &call)
{
QDBusPendingReplyBase::assign(call);
if (d)
setMetaTypes(0, nullptr);
}
inline void assign(const QDBusMessage &message)
{
QDBusPendingReplyBase::assign(message);
if (d)
setMetaTypes(0, nullptr);
}
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

222
src/dbus/qdbusreply.cpp Normal file
View File

@ -0,0 +1,222 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusreply.h"
#include "qdbusmetatype.h"
#include "qdbusmetatype_p.h"
#include <QDebug>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
/*!
\class QDBusReply
\inmodule QtDBus
\since 4.2
\brief The QDBusReply class stores the reply for a method call to a remote object.
A QDBusReply object is a subset of the QDBusMessage object that represents a method call's
reply. It contains only the first output argument or the error code and is used by
QDBusInterface-derived classes to allow returning the error code as the function's return
argument.
It can be used in the following manner:
\snippet code/src_qdbus_qdbusreply.cpp 0
If the remote method call cannot fail, you can skip the error checking:
\snippet code/src_qdbus_qdbusreply.cpp 1
However, if it does fail under those conditions, the value returned by QDBusReply<T>::value() is
a default-constructed value. It may be indistinguishable from a valid return value.
QDBusReply objects are used for remote calls that have no output
arguments or return values (i.e., they have a "void" return
type). Use the isValid() function to test if the reply succeeded.
\sa QDBusMessage, QDBusInterface
*/
/*!
\fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusReply &other)
\since 5.15
Constructs a copy of \a other.
*/
/*!
\fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusMessage &reply)
Automatically construct a QDBusReply object from the reply message \a reply, extracting the
first return value from it if it is a success reply.
*/
/*!
\fn template<typename T> QDBusReply<T>::QDBusReply(const QDBusPendingReply<T> &reply)
Constructs a QDBusReply object from the pending reply message, \a reply.
*/
/*!
\fn template <typename T> QDBusReply<T>::QDBusReply(const QDBusPendingCall &pcall)
Automatically construct a QDBusReply object from the asynchronous
pending call \a pcall. If the call isn't finished yet, QDBusReply
will call QDBusPendingCall::waitForFinished(), which is a blocking
operation.
If the return types patch, QDBusReply will extract the first
return argument from the reply.
*/
/*!
\fn template <typename T> QDBusReply<T>::QDBusReply(const QDBusError &error)
Constructs an error reply from the D-Bus error code given by \a error.
*/
/*!
\fn template <typename T> QDBusReply<T>::operator=(const QDBusReply &other)
Makes this object be a copy of the object \a other.
*/
/*!
\fn template <typename T> QDBusReply<T>::operator=(const QDBusError &dbusError)
Sets this object to contain the error code given by \a dbusError. You
can later access it with error().
*/
/*!
\fn template <typename T> QDBusReply<T>::operator=(const QDBusMessage &reply)
Makes this object contain the \a reply message. If \a reply
is an error message, this function will
copy the error code and message into this object
If \a reply is a standard reply message and contains at least
one parameter, it will be copied into this object, as long as it
is of the correct type. If it's not of the same type as this
QDBusError object, this function will instead set an error code
indicating a type mismatch.
*/
/*!
\fn template <typename T> QDBusReply<T>::operator=(const QDBusPendingCall &pcall)
Makes this object contain the reply specified by the pending
asynchronous call \a pcall. If the call is not finished yet, this
function will call QDBusPendingCall::waitForFinished() to block
until the reply arrives.
If \a pcall finishes with an error message, this function will
copy the error code and message into this object
If \a pcall finished with a standard reply message and contains at
least one parameter, it will be copied into this object, as long
as it is of the correct type. If it's not of the same type as this
QDBusError object, this function will instead set an error code
indicating a type mismatch.
*/
/*!
\fn template <typename T> bool QDBusReply<T>::isValid() const
Returns \c true if no error occurred; otherwise, returns \c false.
\sa error()
*/
/*!
\fn template<typename T> const QDBusError& QDBusReply<T>::error() const
Returns the error code that was returned from the remote function call. If the remote call did
not return an error (i.e., if it succeeded), then the QDBusError object that is returned will
not be a valid error code (QDBusError::isValid() will return false).
\sa isValid()
*/
/*!
\fn template <typename T> const QDBusError& QDBusReply<T>::error()
\overload
*/
/*!
\fn template <typename T> QDBusReply<T>::value() const
Returns the remote function's calls return value. If the remote call returned with an error,
the return value of this function is undefined and may be undistinguishable from a valid return
value.
This function is not available if the remote call returns \c void.
*/
/*!
\fn template <typename T> QDBusReply<T>::operator Type() const
Returns the same as value().
This function is not available if the remote call returns \c void.
*/
/*!
\internal
Fills in the QDBusReply data \a error and \a data from the reply message \a reply.
*/
void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data)
{
error = QDBusError(reply);
if (error.isValid()) {
data = QVariant(); // clear it
return;
}
if (reply.arguments().size() >= 1 && reply.arguments().at(0).metaType() == data.metaType()) {
data = reply.arguments().at(0);
return;
}
const char *expectedSignature = QDBusMetaType::typeToSignature(data.metaType());
const char *receivedType = nullptr;
QByteArray receivedSignature;
if (reply.arguments().size() >= 1) {
if (reply.arguments().at(0).metaType() == QDBusMetaTypeId::argument()) {
// compare signatures instead
QDBusArgument arg = qvariant_cast<QDBusArgument>(reply.arguments().at(0));
receivedSignature = arg.currentSignature().toLatin1();
if (receivedSignature == expectedSignature) {
// matched. Demarshall it
QDBusMetaType::demarshall(arg, data.metaType(), data.data());
return;
}
} else {
// not an argument and doesn't match?
QMetaType type = reply.arguments().at(0).metaType();
receivedType = type.name();
receivedSignature = QDBusMetaType::typeToSignature(type);
}
}
// error
if (receivedSignature.isEmpty())
receivedSignature = "<empty signature>";
QString errorMsg;
if (receivedType) {
errorMsg = "Unexpected reply signature: got \"%1\" (%4), expected \"%2\" (%3)"_L1
.arg(QLatin1StringView(receivedSignature),
QLatin1StringView(expectedSignature),
QLatin1StringView(data.typeName()),
QLatin1StringView(receivedType));
} else {
errorMsg = "Unexpected reply signature: got \"%1\", expected \"%2\" (%3)"_L1
.arg(QLatin1StringView(receivedSignature),
QLatin1StringView(expectedSignature),
QLatin1StringView(data.typeName()));
}
error = QDBusError(QDBusError::InvalidSignature, errorMsg);
data = QVariant(); // clear it
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

159
src/dbus/qdbusreply.h Normal file
View File

@ -0,0 +1,159 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSREPLY_H
#define QDBUSREPLY_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qvariant.h>
#include <QtDBus/qdbusmessage.h>
#include <QtDBus/qdbuserror.h>
#include <QtDBus/qdbusextratypes.h>
#include <QtDBus/qdbuspendingreply.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
Q_DBUS_EXPORT void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data);
template<typename T>
class QDBusReply
{
typedef T Type;
public:
inline QDBusReply(const QDBusMessage &reply)
{
*this = reply;
}
inline QDBusReply(const QDBusReply &) = default;
inline QDBusReply& operator=(const QDBusMessage &reply)
{
QVariant data(QMetaType::fromType<Type>());
qDBusReplyFill(reply, m_error, data);
m_data = qvariant_cast<Type>(data);
return *this;
}
inline QDBusReply(const QDBusPendingCall &pcall)
{
*this = pcall;
}
inline QDBusReply &operator=(const QDBusPendingCall &pcall)
{
QDBusPendingCall other(pcall);
other.waitForFinished();
return *this = other.reply();
}
inline QDBusReply(const QDBusPendingReply<T> &reply)
{
*this = static_cast<QDBusPendingCall>(reply);
}
inline QDBusReply(const QDBusError &dbusError = QDBusError())
: m_error(dbusError), m_data(Type())
{
}
inline QDBusReply& operator=(const QDBusError& dbusError)
{
m_error = dbusError;
m_data = Type();
return *this;
}
inline QDBusReply& operator=(const QDBusReply& other)
{
m_error = other.m_error;
m_data = other.m_data;
return *this;
}
inline bool isValid() const { return !m_error.isValid(); }
inline const QDBusError& error() { return m_error; }
inline const QDBusError& error() const { return m_error; }
inline Type value() const
{
return m_data;
}
inline operator Type () const
{
return m_data;
}
private:
QDBusError m_error;
Type m_data;
};
# ifndef Q_QDOC
// specialize for QVariant:
template<> inline QDBusReply<QVariant>&
QDBusReply<QVariant>::operator=(const QDBusMessage &reply)
{
QVariant data(QMetaType::fromType<QDBusVariant>());
qDBusReplyFill(reply, m_error, data);
m_data = qvariant_cast<QDBusVariant>(data).variant();
return *this;
}
// specialize for void:
template<>
class QDBusReply<void>
{
public:
inline QDBusReply(const QDBusMessage &reply)
: m_error(reply)
{
}
inline QDBusReply& operator=(const QDBusMessage &reply)
{
m_error = QDBusError(reply);
return *this;
}
inline QDBusReply(const QDBusError &dbusError = QDBusError())
: m_error(dbusError)
{
}
inline QDBusReply(const QDBusPendingCall &pcall)
{
*this = pcall;
}
inline QDBusReply &operator=(const QDBusPendingCall &pcall)
{
QDBusPendingCall other(pcall);
other.waitForFinished();
return *this = other.reply();
}
inline QDBusReply& operator=(const QDBusError& dbusError)
{
m_error = dbusError;
return *this;
}
inline QDBusReply(const QDBusReply &) = default;
inline QDBusReply& operator=(const QDBusReply& other)
{
m_error = other.m_error;
return *this;
}
inline bool isValid() const { return !m_error.isValid(); }
inline const QDBusError& error() { return m_error; }
inline const QDBusError& error() const { return m_error; }
private:
QDBusError m_error;
};
# endif
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

167
src/dbus/qdbusserver.cpp Normal file
View File

@ -0,0 +1,167 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusserver.h"
#include "qdbusconnection_p.h"
#include "qdbusconnectionmanager_p.h"
#include "qdbusutil_p.h"
#include <QtCore/private/qlocking_p.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
/*!
\class QDBusServer
\inmodule QtDBus
\brief The QDBusServer class provides peer-to-peer communication
between processes on the same computer.
*/
/*!
Constructs a QDBusServer with the given \a address, and the given
\a parent.
*/
QDBusServer::QDBusServer(const QString &address, QObject *parent)
: QObject(parent), d(nullptr)
{
if (address.isEmpty())
return;
if (!qdbus_loadLibDBus())
return;
QDBusConnectionManager *instance = QDBusConnectionManager::instance();
if (!instance)
return;
emit instance->serverRequested(address, this);
QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)),
this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection);
}
/*!
Constructs a QDBusServer with the given \a parent. The server will listen
for connections in \c {/tmp} (on Unix systems) or on a TCP port bound to
localhost (elsewhere).
*/
QDBusServer::QDBusServer(QObject *parent)
: QObject(parent), d(nullptr)
{
#ifdef Q_OS_UNIX
// Use Unix sockets on Unix systems only
const QString address = QStringLiteral("unix:tmpdir=/tmp");
#else
const QString address = QStringLiteral("tcp:");
#endif
if (!qdbus_loadLibDBus())
return;
QDBusConnectionManager *instance = QDBusConnectionManager::instance();
if (!instance)
return;
emit instance->serverRequested(address, this);
QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)),
this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection);
}
/*!
Destructs a QDBusServer
*/
QDBusServer::~QDBusServer()
{
QMutex *managerMutex = nullptr;
if (QDBusConnectionManager::instance())
managerMutex = &QDBusConnectionManager::instance()->mutex;
QMutexLocker locker(managerMutex);
QWriteLocker writeLocker(&d->lock);
if (QDBusConnectionManager::instance()) {
for (const QString &name : std::as_const(d->serverConnectionNames))
QDBusConnectionManager::instance()->removeConnection(name);
d->serverConnectionNames.clear();
locker.unlock();
}
d->serverObject = nullptr;
d->ref.storeRelaxed(0);
d->deleteLater();
}
/*!
Returns \c true if this QDBusServer object is connected.
If it isn't connected, you need to call the constructor again.
*/
bool QDBusServer::isConnected() const
{
return d && d->server && q_dbus_server_get_is_connected(d->server);
}
/*!
Returns the last error that happened in this server.
This function is provided for low-level code.
*/
QDBusError QDBusServer::lastError() const
{
return d ? d->lastError : QDBusError(QDBusError::Disconnected, QDBusUtil::disconnectedErrorMessage());
}
/*!
Returns the address this server is associated with.
*/
QString QDBusServer::address() const
{
QString addr;
if (d && d->server) {
char *c = q_dbus_server_get_address(d->server);
addr = QString::fromUtf8(c);
q_dbus_free(c);
}
return addr;
}
/*!
\since 5.3
If \a value is set to true, an incoming connection can proceed even if the
connecting client is not authenticated as a user.
By default, this value is false.
\sa isAnonymousAuthenticationAllowed()
*/
void QDBusServer::setAnonymousAuthenticationAllowed(bool value)
{
d->anonymousAuthenticationAllowed = value;
}
/*!
\since 5.3
Returns true if anonymous authentication is allowed.
\sa setAnonymousAuthenticationAllowed()
*/
bool QDBusServer::isAnonymousAuthenticationAllowed() const
{
return d->anonymousAuthenticationAllowed;
}
/*!
\fn void QDBusServer::newConnection(const QDBusConnection &connection)
This signal is emitted when a new client connection \a connection is
established to the server.
*/
QT_END_NAMESPACE
#include "moc_qdbusserver.cpp"
#endif // QT_NO_DBUS

48
src/dbus/qdbusserver.h Normal file
View File

@ -0,0 +1,48 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSSERVER_H
#define QDBUSSERVER_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusConnectionPrivate;
class QDBusError;
class QDBusConnection;
class Q_DBUS_EXPORT QDBusServer: public QObject
{
Q_OBJECT
public:
explicit QDBusServer(const QString &address, QObject *parent = nullptr);
explicit QDBusServer(QObject *parent = nullptr);
virtual ~QDBusServer();
bool isConnected() const;
QDBusError lastError() const;
QString address() const;
void setAnonymousAuthenticationAllowed(bool value);
bool isAnonymousAuthenticationAllowed() const;
Q_SIGNALS:
void newConnection(const QDBusConnection &connection);
private:
Q_DISABLE_COPY(QDBusServer)
Q_PRIVATE_SLOT(d, void _q_newConnection(QDBusConnectionPrivate*))
QDBusConnectionPrivate *d;
friend class QDBusConnectionPrivate;
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,378 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusservicewatcher.h"
#include "qdbusconnection.h"
#include "qdbusutil_p.h"
#include <QStringList>
#include <private/qproperty_p.h>
#include <private/qobject_p.h>
#include <private/qdbusconnection_p.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusServiceWatcherPrivate: public QObjectPrivate
{
Q_DECLARE_PUBLIC(QDBusServiceWatcher)
public:
QDBusServiceWatcherPrivate(const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm)
: connection(c), watchMode(wm)
{
}
void setWatchedServicesForwardToQ(const QStringList &list)
{
q_func()->setWatchedServices(list);
}
Q_OBJECT_COMPAT_PROPERTY(QDBusServiceWatcherPrivate, QStringList, watchedServicesData,
&QDBusServiceWatcherPrivate::setWatchedServicesForwardToQ)
QDBusConnection connection;
void setWatchModeForwardToQ(QDBusServiceWatcher::WatchMode mode)
{
q_func()->setWatchMode(mode);
}
Q_OBJECT_COMPAT_PROPERTY(QDBusServiceWatcherPrivate, QDBusServiceWatcher::WatchMode, watchMode,
&QDBusServiceWatcherPrivate::setWatchModeForwardToQ)
void _q_serviceOwnerChanged(const QString &, const QString &, const QString &);
void setConnection(const QStringList &services, const QDBusConnection &c, QDBusServiceWatcher::WatchMode watchMode);
void addService(const QString &service);
void removeService(const QString &service);
};
void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
{
Q_Q(QDBusServiceWatcher);
emit q->serviceOwnerChanged(service, oldOwner, newOwner);
if (oldOwner.isEmpty())
emit q->serviceRegistered(service);
else if (newOwner.isEmpty())
emit q->serviceUnregistered(service);
}
void QDBusServiceWatcherPrivate::setConnection(const QStringList &services,
const QDBusConnection &c,
QDBusServiceWatcher::WatchMode wm)
{
if (connection.isConnected()) {
// remove older rules
for (const QString &s : std::as_const(watchedServicesData.value()))
removeService(s);
}
connection = c;
watchMode.setValueBypassingBindings(wm); // caller has to call notify()
watchedServicesData.setValueBypassingBindings(services); // caller has to call notify()
if (connection.isConnected()) {
// add new rules
for (const QString &s : std::as_const(watchedServicesData.value()))
addService(s);
}
}
void QDBusServiceWatcherPrivate::addService(const QString &service)
{
QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection);
if (d && d->shouldWatchService(service))
d->watchService(service, watchMode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
}
void QDBusServiceWatcherPrivate::removeService(const QString &service)
{
QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection);
if (d && d->shouldWatchService(service))
d->unwatchService(service, watchMode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
}
/*!
\class QDBusServiceWatcher
\since 4.6
\inmodule QtDBus
\brief The QDBusServiceWatcher class allows the user to watch for a bus service change.
A QDBusServiceWatcher object can be used to notify the application about
an ownership change of a service name on the bus. It has three watch
modes:
\list
\li Watching for service registration only.
\li Watching for service unregistration only.
\li Watching for any kind of service ownership change (the default mode).
\endlist
Besides being created or deleted, services may change owners without a
unregister/register operation happening. So the serviceRegistered()
and serviceUnregistered() signals may not be emitted if that
happens.
This class is more efficient than using the
QDBusConnectionInterface::serviceOwnerChanged() signal because it allows
one to receive only the signals for which the class is interested in.
Ending a service name with the character '*' will match all service names
within the specified namespace.
For example "com.example.backend1*" will match
\list
\li com.example.backend1
\li com.example.backend1.foo
\li com.example.backend1.foo.bar
\endlist
Substrings in the same domain will not be matched, i.e "com.example.backend12".
\sa QDBusConnection
*/
/*!
\enum QDBusServiceWatcher::WatchModeFlag
QDBusServiceWatcher supports three different watch modes, which are configured by this flag:
\value WatchForRegistration watch for service registration only, ignoring
any signals related to other service ownership change.
\value WatchForUnregistration watch for service unregistration only,
ignoring any signals related to other service ownership change.
\value WatchForOwnerChange watch for any kind of service ownership
change.
*/
/*!
\property QDBusServiceWatcher::watchMode
\brief the current watch mode for this QDBusServiceWatcher object.
The default value for this property is
QDBusServiceWatcher::WatchForOwnershipChange.
*/
/*!
\property QDBusServiceWatcher::watchedServices
\brief the list of services watched.
\note Modifying this list with setServicesWatched() is an expensive
operation. If you can, prefer to change it by way of addWatchedService()
and removeWatchedService().
*/
/*!
\fn void QDBusServiceWatcher::serviceRegistered(const QString &serviceName)
This signal is emitted whenever this object detects that the service \a
serviceName became available on the bus.
\sa serviceUnregistered(), serviceOwnerChanged()
*/
/*!
\fn void QDBusServiceWatcher::serviceUnregistered(const QString &serviceName)
This signal is emitted whenever this object detects that the service \a
serviceName was unregistered from the bus and is no longer available.
\sa serviceRegistered(), serviceOwnerChanged()
*/
/*!
\fn void QDBusServiceWatcher::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
This signal is emitted whenever this object detects that there was a
service ownership change relating to the \a serviceName service. The \a
oldOwner parameter contains the old owner name and \a newOwner is the new
owner. Both \a oldOwner and \a newOwner are unique connection names.
Note that this signal is also emitted whenever the \a serviceName service
was registered or unregistered. If it was registered, \a oldOwner will
contain an empty string, whereas if it was unregistered, \a newOwner will
contain an empty string.
If you need only to find out if the service is registered or unregistered
only, without being notified that the ownership changed, consider using
the specific modes for those operations. This class is more efficient if
you use the more specific modes.
\sa serviceRegistered(), serviceUnregistered()
*/
/*!
Creates a QDBusServiceWatcher object. Note that until you set a
connection with setConnection(), this object will not emit any signals.
The \a parent parameter is passed to QObject to set the parent of this
object.
*/
QDBusServiceWatcher::QDBusServiceWatcher(QObject *parent)
: QObject(*new QDBusServiceWatcherPrivate(QDBusConnection(QString()), WatchForOwnerChange), parent)
{
}
/*!
Creates a QDBusServiceWatcher object and attaches it to the \a connection
connection. Also, this function immediately starts watching for \a
watchMode changes to service \a service.
The \a parent parameter is passed to QObject to set the parent of this
object.
*/
QDBusServiceWatcher::QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode, QObject *parent)
: QObject(*new QDBusServiceWatcherPrivate(connection, watchMode), parent)
{
d_func()->setConnection(QStringList() << service, connection, watchMode);
}
/*!
Destroys the QDBusServiceWatcher object and releases any resources
associated with it.
*/
QDBusServiceWatcher::~QDBusServiceWatcher()
{
}
/*!
Returns the list of D-Bus services that are being watched.
\sa setWatchedServices()
*/
QStringList QDBusServiceWatcher::watchedServices() const
{
return d_func()->watchedServicesData;
}
/*!
Sets the list of D-Bus services being watched to be \a services.
Note that setting the entire list means removing all previous rules for
watching services and adding new ones. This is an expensive operation and
should be avoided, if possible. Instead, use addWatchedService() and
removeWatchedService() if you can to manipulate entries in the list.
Removes any existing binding of watchedServices.
*/
void QDBusServiceWatcher::setWatchedServices(const QStringList &services)
{
Q_D(QDBusServiceWatcher);
d->watchedServicesData.removeBindingUnlessInWrapper();
if (services == d->watchedServicesData)
return;
d->setConnection(services, d->connection, d->watchMode);
d->watchedServicesData.notify();
}
QBindable<QStringList> QDBusServiceWatcher::bindableWatchedServices()
{
Q_D(QDBusServiceWatcher);
return &d->watchedServicesData;
}
/*!
Adds \a newService to the list of services to be watched by this object.
This function is more efficient than setWatchedServices() and should be
used whenever possible to add services.
Removes any existing binding of watchedServices.
*/
void QDBusServiceWatcher::addWatchedService(const QString &newService)
{
Q_D(QDBusServiceWatcher);
d->watchedServicesData.removeBindingUnlessInWrapper();
if (d->watchedServicesData.value().contains(newService))
return;
d->addService(newService);
auto templist = d->watchedServicesData.valueBypassingBindings();
templist << newService;
d->watchedServicesData.setValueBypassingBindings(templist);
d->watchedServicesData.notify();
}
/*!
Removes the \a service from the list of services being watched by this
object. Note that D-Bus notifications are asynchronous, so there may
still be signals pending delivery about \a service. Those signals will
still be emitted whenever the D-Bus messages are processed.
Removes any existing binding of watchedServices.
This function returns \c true if any services were removed.
*/
bool QDBusServiceWatcher::removeWatchedService(const QString &service)
{
Q_D(QDBusServiceWatcher);
d->watchedServicesData.removeBindingUnlessInWrapper();
d->removeService(service);
auto tempList = d->watchedServicesData.value();
bool result = tempList.removeOne(service);
if (result) {
d->watchedServicesData.setValueBypassingBindings(tempList);
d->watchedServicesData.notify();
return true;
} else {
// nothing changed
return false;
}
}
QDBusServiceWatcher::WatchMode QDBusServiceWatcher::watchMode() const
{
return d_func()->watchMode;
}
QBindable<QDBusServiceWatcher::WatchMode> QDBusServiceWatcher::bindableWatchMode()
{
return &d_func()->watchMode;
}
void QDBusServiceWatcher::setWatchMode(WatchMode mode)
{
Q_D(QDBusServiceWatcher);
d->watchMode.removeBindingUnlessInWrapper();
if (mode == d->watchMode.value())
return;
d->setConnection(d->watchedServicesData, d->connection, mode);
d->watchMode.notify();
}
/*!
Returns the QDBusConnection that this object is attached to.
\sa setConnection()
*/
QDBusConnection QDBusServiceWatcher::connection() const
{
return d_func()->connection;
}
/*!
Sets the D-Bus connection that this object is attached to be \a
connection. All services watched will be transferred to this connection.
Note that QDBusConnection objects are reference counted:
QDBusServiceWatcher will keep a reference for this connection while it
exists. The connection is not closed until the reference count drops to
zero, so this will ensure that any notifications are received while this
QDBusServiceWatcher object exists.
\sa connection()
*/
void QDBusServiceWatcher::setConnection(const QDBusConnection &connection)
{
Q_D(QDBusServiceWatcher);
if (connection.name() == d->connection.name())
return;
d->setConnection(d->watchedServicesData, connection, d->watchMode);
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#include "moc_qdbusservicewatcher.cpp"

View File

@ -0,0 +1,71 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSSERVICEWATCHER_H
#define QDBUSSERVICEWATCHER_H
#include <QtCore/QObject>
#include <QtCore/qcontainerfwd.h> // Q(String)List
#include <QtDBus/qtdbusglobal.h>
#if !defined(QT_NO_DBUS) && !defined(QT_NO_QOBJECT)
QT_BEGIN_NAMESPACE
class QString;
template<typename T>
class QBindable;
class QDBusConnection;
class QDBusServiceWatcherPrivate;
class Q_DBUS_EXPORT QDBusServiceWatcher: public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList watchedServices READ watchedServices WRITE setWatchedServices
BINDABLE bindableWatchedServices)
Q_PROPERTY(WatchMode watchMode READ watchMode WRITE setWatchMode BINDABLE bindableWatchMode)
public:
enum WatchModeFlag {
WatchForRegistration = 0x01,
WatchForUnregistration = 0x02,
WatchForOwnerChange = 0x03
};
Q_DECLARE_FLAGS(WatchMode, WatchModeFlag)
Q_FLAG(WatchMode)
explicit QDBusServiceWatcher(QObject *parent = nullptr);
QDBusServiceWatcher(const QString &service, const QDBusConnection &connection,
WatchMode watchMode = WatchForOwnerChange, QObject *parent = nullptr);
~QDBusServiceWatcher();
QStringList watchedServices() const;
void setWatchedServices(const QStringList &services);
void addWatchedService(const QString &newService);
bool removeWatchedService(const QString &service);
QBindable<QStringList> bindableWatchedServices();
WatchMode watchMode() const;
void setWatchMode(WatchMode mode);
QBindable<WatchMode> bindableWatchMode();
QDBusConnection connection() const;
void setConnection(const QDBusConnection &connection);
Q_SIGNALS:
void serviceRegistered(const QString &service);
void serviceUnregistered(const QString &service);
void serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner);
private:
Q_PRIVATE_SLOT(d_func(), void _q_serviceOwnerChanged(QString,QString,QString))
Q_DISABLE_COPY(QDBusServiceWatcher)
Q_DECLARE_PRIVATE(QDBusServiceWatcher)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusServiceWatcher::WatchMode)
QT_END_NAMESPACE
#endif // QT_NO_DBUS || QT_NO_QOBJECT
#endif // QDBUSSERVICEWATCHER_H

View File

@ -0,0 +1,153 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSTHREADDEBUG_P_H
#define QDBUSTHREADDEBUG_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/private/qtdbusglobal_p.h>
#ifndef QT_NO_DBUS
#if !defined(QDBUS_THREAD_DEBUG) && defined(QT_BUILD_INTERNAL)
# define QDBUS_THREAD_DEBUG 1
#endif
#if QDBUS_THREAD_DEBUG
QT_BEGIN_NAMESPACE
typedef void (*qdbusThreadDebugFunc)(int, int, QDBusConnectionPrivate *);
Q_DBUS_EXPORT void qdbusDefaultThreadDebug(int, int, QDBusConnectionPrivate *);
extern Q_DBUS_EXPORT qdbusThreadDebugFunc qdbusThreadDebug;
QT_END_NAMESPACE
#endif
enum ThreadAction {
ConnectAction = 0,
DisconnectAction = 1,
RegisterObjectAction = 2,
UnregisterObjectAction = 3,
ObjectRegisteredAtAction = 4,
CloseConnectionAction = 10,
ObjectDestroyedAction = 11,
RelaySignalAction = 12,
HandleObjectCallAction = 13,
HandleSignalAction = 14,
ConnectRelayAction = 15,
DisconnectRelayAction = 16,
FindMetaObject1Action = 17,
FindMetaObject2Action = 18,
RegisterServiceAction = 19,
UnregisterServiceAction = 20,
UpdateSignalHookOwnerAction = 21,
HandleObjectCallPostEventAction = 22,
HandleObjectCallSemaphoreAction = 23,
DoDispatchAction = 24,
SetDispatchEnabledAction = 25,
MessageResultReceivedAction = 26,
ActivateSignalAction = 27,
PendingCallBlockAction = 28,
SendMessageAction = 29,
HuntAndEmitAction = 30,
};
struct QDBusLockerBase
{
enum Condition
{
BeforeLock,
AfterLock,
BeforeUnlock,
AfterUnlock,
BeforePost,
AfterPost,
BeforeDeliver,
AfterDeliver,
BeforeAcquire,
AfterAcquire,
BeforeRelease,
AfterRelease
};
#if QDBUS_THREAD_DEBUG
static inline void reportThreadAction(int action, int condition, QDBusConnectionPrivate *ptr)
{ if (qdbusThreadDebug) qdbusThreadDebug(action, condition, ptr); }
#else
static inline void reportThreadAction(int, int, QDBusConnectionPrivate *) { }
#endif
};
struct QDBusReadLocker: QDBusLockerBase
{
QDBusConnectionPrivate *self;
ThreadAction action;
inline QDBusReadLocker(ThreadAction a, QDBusConnectionPrivate *s)
: self(s), action(a)
{
reportThreadAction(action, BeforeLock, self);
self->lock.lockForRead();
reportThreadAction(action, AfterLock, self);
}
inline ~QDBusReadLocker()
{
reportThreadAction(action, BeforeUnlock, self);
self->lock.unlock();
reportThreadAction(action, AfterUnlock, self);
}
};
struct QDBusWriteLocker: QDBusLockerBase
{
QDBusConnectionPrivate *self;
ThreadAction action;
inline QDBusWriteLocker(ThreadAction a, QDBusConnectionPrivate *s)
: self(s), action(a)
{
reportThreadAction(action, BeforeLock, self);
self->lock.lockForWrite();
reportThreadAction(action, AfterLock, self);
}
inline ~QDBusWriteLocker()
{
reportThreadAction(action, BeforeUnlock, self);
self->lock.unlock();
reportThreadAction(action, AfterUnlock, self);
}
};
#if QDBUS_THREAD_DEBUG
# define SEM_ACQUIRE(action, sem) \
do { \
QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforeAcquire, this); \
sem.acquire(); \
QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterAcquire, this); \
} while (false)
# define SEM_RELEASE(action, sem) \
do { \
QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforeRelease, that); \
sem.release(); \
QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterRelease, that); \
} while (false)
#else
# define SEM_ACQUIRE(action, sem) sem.acquire()
# define SEM_RELEASE(action, sem) sem.release()
#endif
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,310 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusunixfiledescriptor.h"
#ifdef Q_OS_UNIX
# include <private/qcore_unix_p.h>
#endif
QT_BEGIN_NAMESPACE
#ifndef QT_NO_DBUS
QT_IMPL_METATYPE_EXTERN(QDBusUnixFileDescriptor)
/*!
\class QDBusUnixFileDescriptor
\inmodule QtDBus
\ingroup shared
\since 4.8
\brief The QDBusUnixFileDescriptor class holds one Unix file descriptor.
The QDBusUnixFileDescriptor class is used to hold one Unix file
descriptor for use with the Qt D-Bus module. This allows applications to
send and receive Unix file descriptors over the D-Bus connection, mapping
automatically to the D-Bus type 'h'.
Objects of type QDBusUnixFileDescriptors can be used also as parameters
in signals and slots that get exported to D-Bus by registering with
QDBusConnection::registerObject.
QDBusUnixFileDescriptor does not take ownership of the file descriptor.
Instead, it will use the Unix system call \c dup(2) to make a copy of the
file descriptor. This file descriptor belongs to the
QDBusUnixFileDescriptor object and should not be stored or closed by the
user. Instead, you should make your own copy if you need that.
\section2 Availability
Unix file descriptor passing is not available in all D-Bus connections.
This feature is present with D-Bus library and bus daemon version 1.4 and
upwards on Unix systems. Qt D-Bus automatically enables the feature if such
a version was found at compile-time and run-time.
To verify that your connection does support passing file descriptors,
check if the QDBusConnection::UnixFileDescriptorPassing capability is set
with QDBusConnection::connectionCapabilities(). If the flag is not
active, then you will not be able to make calls to methods that have
QDBusUnixFileDescriptor as arguments or even embed such a type in a
variant. You will also not receive calls containing that type.
Note also that remote applications may not have support for Unix file
descriptor passing. If you make a D-Bus to a remote application that
cannot receive such a type, you will receive an error reply. If you try
to send a signal containing a D-Bus file descriptor or return one from a
method call, the message will be silently dropped.
Even if the feature is not available, QDBusUnixFileDescriptor will
continue to operate, so code need not have compile-time checks for the
availability of this feature.
On non-Unix systems, QDBusUnixFileDescriptor will always report an
invalid state and QDBusUnixFileDescriptor::isSupported() will return
false.
\sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities()
*/
/*!
\typedef QDBusUnixFileDescriptor::Data
\internal
*/
/*!
\variable QDBusUnixFileDescriptor::d
\internal
*/
class QDBusUnixFileDescriptorPrivate : public QSharedData {
public:
QDBusUnixFileDescriptorPrivate() : fd(-1) { }
QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other)
: QSharedData(other), fd(-1)
{ }
~QDBusUnixFileDescriptorPrivate();
QAtomicInt fd;
};
template<> inline
QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate>::~QExplicitlySharedDataPointer()
{ if (d && !d->ref.deref()) delete d; }
/*!
Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor.
This is equivalent to constructing the object with an invalid file
descriptor (like -1).
\sa fileDescriptor(), isValid()
*/
QDBusUnixFileDescriptor::QDBusUnixFileDescriptor()
: d(nullptr)
{
}
/*!
Constructs a QDBusUnixFileDescriptor object by copying the \a
fileDescriptor parameter. The original file descriptor is not touched and
must be closed by the user.
Note that the value returned by fileDescriptor() will be different from
the \a fileDescriptor parameter passed.
If the \a fileDescriptor parameter is not valid, isValid() will return
false and fileDescriptor() will return -1.
\sa setFileDescriptor(), fileDescriptor()
*/
QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor)
: d(nullptr)
{
if (fileDescriptor != -1)
setFileDescriptor(fileDescriptor);
}
/*!
Constructs a QDBusUnixFileDescriptor object by copying \a other.
*/
QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other)
: d(other.d)
{
}
/*!
Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor
object. If the current object contained a file descriptor, it will be
properly disposed of before.
*/
QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other)
{
if (this != &other)
d.operator=(other.d);
return *this;
}
/*!
\fn QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(QDBusUnixFileDescriptor &&other)
Move-assigns \a other to this QDBusUnixFileDescriptor.
*/
/*!
Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained.
*/
QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor()
{
}
/*!
\fn void QDBusUnixFileDescriptor::swap(QDBusUnixFileDescriptor &other)
\since 5.0
Swaps this file descriptor instance with \a other. This function
is very fast and never fails.
*/
/*!
Returns \c true if this Unix file descriptor is valid. A valid Unix file
descriptor is not -1.
\sa fileDescriptor()
*/
bool QDBusUnixFileDescriptor::isValid() const
{
return d ? d->fd.loadRelaxed() != -1 : false;
}
/*!
Returns the Unix file descriptor contained by this
QDBusUnixFileDescriptor object. An invalid file descriptor is represented
by the value -1.
Note that the file descriptor returned by this function is owned by the
QDBusUnixFileDescriptor object and must not be stored past the lifetime
of this object. It is ok to use it while this object is valid, but if one
wants to store it for longer use, the file descriptor should be cloned
using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions.
\sa isValid()
*/
int QDBusUnixFileDescriptor::fileDescriptor() const
{
return d ? d->fd.loadRelaxed() : -1;
}
// actual implementation
#ifdef Q_OS_UNIX
// qdoc documentation is generated on Unix
/*!
Returns \c true if Unix file descriptors are supported on this platform. In
other words, this function returns \c true if this is a Unix platform.
Note that QDBusUnixFileDescriptor continues to operate even if this
function returns \c false. The only difference is that the
QDBusUnixFileDescriptor objects will always be in the isValid() == false
state and fileDescriptor() will always return -1. The class will not
consume any operating system resources.
*/
bool QDBusUnixFileDescriptor::isSupported()
{
return true;
}
/*!
Sets the file descriptor that this QDBusUnixFileDescriptor object holds
to a copy of \a fileDescriptor. The original file descriptor is not
touched and must be closed by the user.
Note that the value returned by fileDescriptor() will be different from
the \a fileDescriptor parameter passed.
If the \a fileDescriptor parameter is not valid, isValid() will return
false and fileDescriptor() will return -1.
\sa isValid(), fileDescriptor()
*/
void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor)
{
if (fileDescriptor != -1)
giveFileDescriptor(qt_safe_dup(fileDescriptor));
}
/*!
\internal
Sets the Unix file descriptor to \a fileDescriptor without copying.
\sa setFileDescriptor()
*/
void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor)
{
// if we are the sole ref, d remains unchanged
// if detaching happens, d->fd will be -1
if (d)
d.detach();
else
d = new QDBusUnixFileDescriptorPrivate;
const int fdl = d->fd.loadRelaxed();
if (fdl != -1)
qt_safe_close(fdl);
if (fileDescriptor != -1)
d->fd.storeRelaxed(fileDescriptor);
}
/*!
\internal
Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object
and transfers ownership.
Note: since QDBusUnixFileDescriptor is implicitly shared, this function
is inherently racy and should be avoided.
*/
int QDBusUnixFileDescriptor::takeFileDescriptor()
{
if (!d)
return -1;
return d->fd.fetchAndStoreRelaxed(-1);
}
QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
{
const int fdl = fd.loadRelaxed();
if (fdl != -1)
qt_safe_close(fdl);
}
#else
bool QDBusUnixFileDescriptor::isSupported()
{
return false;
}
void QDBusUnixFileDescriptor::setFileDescriptor(int)
{
}
void QDBusUnixFileDescriptor::giveFileDescriptor(int)
{
}
int QDBusUnixFileDescriptor::takeFileDescriptor()
{
return -1;
}
QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
{
}
#endif
#endif // QT_NO_DBUS
QT_END_NAMESPACE

View File

@ -0,0 +1,55 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSUNIXFILEDESCRIPTOR_H
#define QDBUSUNIXFILEDESCRIPTOR_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qshareddata.h>
#ifndef QT_NO_DBUS
#include <utility>
QT_BEGIN_NAMESPACE
class QDBusUnixFileDescriptorPrivate;
class Q_DBUS_EXPORT QDBusUnixFileDescriptor
{
public:
QDBusUnixFileDescriptor();
explicit QDBusUnixFileDescriptor(int fileDescriptor);
QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other);
QDBusUnixFileDescriptor &operator=(QDBusUnixFileDescriptor &&other) noexcept { swap(other); return *this; }
QDBusUnixFileDescriptor &operator=(const QDBusUnixFileDescriptor &other);
~QDBusUnixFileDescriptor();
void swap(QDBusUnixFileDescriptor &other) noexcept
{ d.swap(other.d); }
bool isValid() const;
int fileDescriptor() const;
void setFileDescriptor(int fileDescriptor);
void giveFileDescriptor(int fileDescriptor);
int takeFileDescriptor();
static bool isSupported();
protected:
typedef QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate> Data;
Data d;
};
Q_DECLARE_SHARED(QDBusUnixFileDescriptor)
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QDBusUnixFileDescriptor, Q_DBUS_EXPORT)
#endif // QT_NO_DBUS
#endif // QDBUSUNIXFILEDESCRIPTOR_H

550
src/dbus/qdbusutil.cpp Normal file
View File

@ -0,0 +1,550 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusutil_p.h"
#include "qdbus_symbols_p.h"
#include <QtCore/qlist.h>
#include <QtCore/qstringlist.h>
#include <private/qtools_p.h>
#include "qdbusargument.h"
#include "qdbusunixfiledescriptor.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
using namespace QtMiscUtils;
static inline bool isValidCharacterNoDash(QChar c)
{
ushort u = c.unicode();
return isAsciiLetterOrNumber(u) || (u == '_');
}
static inline bool isValidCharacter(QChar c)
{
ushort u = c.unicode();
return isAsciiLetterOrNumber(u)
|| (u == '_') || (u == '-');
}
static inline bool isValidNumber(QChar c)
{
return (isAsciiDigit(c.toLatin1()));
}
#ifndef QT_BOOTSTRAPPED
static bool argToString(const QDBusArgument &arg, QString &out);
static bool variantToString(const QVariant &arg, QString &out)
{
int argType = arg.metaType().id();
if (argType == QMetaType::QStringList) {
out += u'{';
const QStringList list = arg.toStringList();
for (const QString &item : list)
out += u'\"' + item + "\", "_L1;
if (!list.isEmpty())
out.chop(2);
out += u'}';
} else if (argType == QMetaType::QByteArray) {
out += u'{';
QByteArray list = arg.toByteArray();
for (int i = 0; i < list.size(); ++i) {
out += QString::number(list.at(i));
out += ", "_L1;
}
if (!list.isEmpty())
out.chop(2);
out += u'}';
} else if (argType == QMetaType::QVariantList) {
out += u'{';
const QList<QVariant> list = arg.toList();
for (const QVariant &item : list) {
if (!variantToString(item, out))
return false;
out += ", "_L1;
}
if (!list.isEmpty())
out.chop(2);
out += u'}';
} else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
|| argType == QMetaType::Long || argType == QMetaType::LongLong) {
out += QString::number(arg.toLongLong());
} else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
|| argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
out += QString::number(arg.toULongLong());
} else if (argType == QMetaType::Double) {
out += QString::number(arg.toDouble());
} else if (argType == QMetaType::Bool) {
out += arg.toBool() ? "true"_L1 : "false"_L1;
} else if (argType == qMetaTypeId<QDBusArgument>()) {
argToString(qvariant_cast<QDBusArgument>(arg), out);
} else if (argType == qMetaTypeId<QDBusObjectPath>()) {
const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
out += "[ObjectPath: "_L1;
out += path;
out += u']';
} else if (argType == qMetaTypeId<QDBusSignature>()) {
out += "[Signature: "_L1 + qvariant_cast<QDBusSignature>(arg).signature();
out += u']';
} else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) {
out += "[Unix FD: "_L1;
out += qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid"_L1 : "not valid"_L1;
out += u']';
} else if (argType == qMetaTypeId<QDBusVariant>()) {
const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
out += "[Variant"_L1;
QMetaType vUserType = v.metaType();
if (vUserType != QMetaType::fromType<QDBusVariant>()
&& vUserType != QMetaType::fromType<QDBusSignature>()
&& vUserType != QMetaType::fromType<QDBusObjectPath>()
&& vUserType != QMetaType::fromType<QDBusArgument>())
out += u'(' + QLatin1StringView(v.typeName()) + u')';
out += ": "_L1;
if (!variantToString(v, out))
return false;
out += u']';
} else if (arg.canConvert<QString>()) {
out += u'\"' + arg.toString() + u'\"';
} else {
out += u'[';
out += QLatin1StringView(arg.typeName());
out += u']';
}
return true;
}
bool argToString(const QDBusArgument &busArg, QString &out)
{
QString busSig = busArg.currentSignature();
bool doIterate = false;
QDBusArgument::ElementType elementType = busArg.currentType();
if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
&& elementType != QDBusArgument::MapEntryType)
out += "[Argument: "_L1 + busSig + u' ';
switch (elementType) {
case QDBusArgument::BasicType:
case QDBusArgument::VariantType:
if (!variantToString(busArg.asVariant(), out))
return false;
break;
case QDBusArgument::StructureType:
busArg.beginStructure();
doIterate = true;
break;
case QDBusArgument::ArrayType:
busArg.beginArray();
out += u'{';
doIterate = true;
break;
case QDBusArgument::MapType:
busArg.beginMap();
out += u'{';
doIterate = true;
break;
case QDBusArgument::MapEntryType:
busArg.beginMapEntry();
if (!variantToString(busArg.asVariant(), out))
return false;
out += " = "_L1;
if (!argToString(busArg, out))
return false;
busArg.endMapEntry();
break;
case QDBusArgument::UnknownType:
default:
out += "<ERROR - Unknown Type>"_L1;
return false;
}
if (doIterate && !busArg.atEnd()) {
while (!busArg.atEnd()) {
if (!argToString(busArg, out))
return false;
out += ", "_L1;
}
out.chop(2);
}
switch (elementType) {
case QDBusArgument::BasicType:
case QDBusArgument::VariantType:
case QDBusArgument::UnknownType:
case QDBusArgument::MapEntryType:
// nothing to do
break;
case QDBusArgument::StructureType:
busArg.endStructure();
break;
case QDBusArgument::ArrayType:
out += u'}';
busArg.endArray();
break;
case QDBusArgument::MapType:
out += u'}';
busArg.endMap();
break;
}
if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
&& elementType != QDBusArgument::MapEntryType)
out += u']';
return true;
}
#endif
//------- D-Bus Types --------
static const char oneLetterTypes[] = "vsogybnqiuxtdh";
static const char basicTypes[] = "sogybnqiuxtdh";
static const char fixedTypes[] = "ybnqiuxtdh";
static bool isBasicType(int c)
{
return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != nullptr;
}
static bool isFixedType(int c)
{
return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != nullptr;
}
// Returns a pointer to one-past-end of this type if it's valid;
// returns NULL if it isn't valid.
static const char *validateSingleType(const char *signature)
{
char c = *signature;
if (c == DBUS_TYPE_INVALID)
return nullptr;
// is it one of the one-letter types?
if (strchr(oneLetterTypes, c) != nullptr)
return signature + 1;
// is it an array?
if (c == DBUS_TYPE_ARRAY) {
// then it's valid if the next type is valid
// or if it's a dict-entry
c = *++signature;
if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) {
// beginning of a dictionary entry
// a dictionary entry has a key which is of basic types
// and a free value
c = *++signature;
if (!isBasicType(c))
return nullptr;
signature = validateSingleType(signature + 1);
return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : nullptr;
}
return validateSingleType(signature);
}
if (c == DBUS_STRUCT_BEGIN_CHAR) {
// beginning of a struct
++signature;
while (true) {
signature = validateSingleType(signature);
if (!signature)
return nullptr;
if (*signature == DBUS_STRUCT_END_CHAR)
return signature + 1;
}
}
// invalid/unknown type
return nullptr;
}
/*!
\namespace QDBusUtil
\inmodule QtDBus
\internal
\brief The QDBusUtil namespace contains a few functions that are of general use when
dealing with D-Bus strings.
*/
namespace QDBusUtil
{
/*!
\internal
\since 4.5
Dumps the contents of a Qt D-Bus argument from \a arg into a string.
*/
QString argumentToString(const QVariant &arg)
{
QString out;
#ifndef QT_BOOTSTRAPPED
variantToString(arg, out);
#else
Q_UNUSED(arg);
#endif
return out;
}
/*!
\internal
\fn bool isValidPartOfObjectPath(QStringView part)
See isValidObjectPath
*/
bool isValidPartOfObjectPath(QStringView part)
{
if (part.isEmpty())
return false; // can't be valid if it's empty
const QChar *c = part.data();
for (int i = 0; i < part.size(); ++i)
if (!isValidCharacterNoDash(c[i]))
return false;
return true;
}
/*!
\internal
\fn bool isValidPartOfObjectPath(const QString &part)
\overload
*/
/*!
\fn bool isValidInterfaceName(const QString &ifaceName)
Returns \c true if this is \a ifaceName is a valid interface name.
Valid interface names must:
\list
\li not be empty
\li not exceed 255 characters in length
\li be composed of dot-separated string components that contain only ASCII letters, digits
and the underscore ("_") character
\li contain at least two such components
\endlist
*/
bool isValidInterfaceName(const QString& ifaceName)
{
if (ifaceName.isEmpty() || ifaceName.size() > DBUS_MAXIMUM_NAME_LENGTH)
return false;
const auto parts = QStringView{ifaceName}.split(u'.');
if (parts.size() < 2)
return false; // at least two parts
for (auto part : parts)
if (!isValidMemberName(part))
return false;
return true;
}
/*!
\fn bool isValidUniqueConnectionName(QStringView connName)
Returns \c true if \a connName is a valid unique connection name.
Unique connection names start with a colon (":") and are followed by a list of dot-separated
components composed of ASCII letters, digits, the hyphen or the underscore ("_") character.
*/
bool isValidUniqueConnectionName(QStringView connName)
{
if (connName.isEmpty() || connName.size() > DBUS_MAXIMUM_NAME_LENGTH ||
!connName.startsWith(u':'))
return false;
const auto parts = connName.mid(1).split(u'.');
if (parts.size() < 1)
return false;
for (QStringView part : parts) {
if (part.isEmpty())
return false;
const QChar* c = part.data();
for (int j = 0; j < part.size(); ++j)
if (!isValidCharacter(c[j]))
return false;
}
return true;
}
/*!
\fn bool isValidUniqueConnectionName(const QString &connName)
\overload
*/
/*!
\fn bool isValidBusName(const QString &busName)
Returns \c true if \a busName is a valid bus name.
A valid bus name is either a valid unique connection name or follows the rules:
\list
\li is not empty
\li does not exceed 255 characters in length
\li be composed of dot-separated string components that contain only ASCII letters, digits,
hyphens or underscores ("_"), but don't start with a digit
\li contains at least two such elements
\endlist
\sa isValidUniqueConnectionName()
*/
bool isValidBusName(const QString &busName)
{
if (busName.isEmpty() || busName.size() > DBUS_MAXIMUM_NAME_LENGTH)
return false;
if (busName.startsWith(u':'))
return isValidUniqueConnectionName(busName);
const auto parts = QStringView{busName}.split(u'.');
if (parts.size() < 1)
return false;
for (QStringView part : parts) {
if (part.isEmpty())
return false;
const QChar *c = part.data();
if (isValidNumber(c[0]))
return false;
for (int j = 0; j < part.size(); ++j)
if (!isValidCharacter(c[j]))
return false;
}
return true;
}
/*!
\fn bool isValidMemberName(QStringView memberName)
Returns \c true if \a memberName is a valid member name. A valid member name does not exceed
255 characters in length, is not empty, is composed only of ASCII letters, digits and
underscores, but does not start with a digit.
*/
bool isValidMemberName(QStringView memberName)
{
if (memberName.isEmpty() || memberName.size() > DBUS_MAXIMUM_NAME_LENGTH)
return false;
const QChar* c = memberName.data();
if (isValidNumber(c[0]))
return false;
for (int j = 0; j < memberName.size(); ++j)
if (!isValidCharacterNoDash(c[j]))
return false;
return true;
}
/*!
\fn bool isValidMemberName(const QString &memberName)
\overload
*/
/*!
\fn bool isValidErrorName(const QString &errorName)
Returns \c true if \a errorName is a valid error name. Valid error names are valid interface
names and vice-versa, so this function is actually an alias for isValidInterfaceName.
*/
bool isValidErrorName(const QString &errorName)
{
return isValidInterfaceName(errorName);
}
/*!
\fn bool isValidObjectPath(const QString &path)
Returns \c true if \a path is valid object path.
Valid object paths follow the rules:
\list
\li start with the slash character ("/")
\li do not end in a slash, unless the path is just the initial slash
\li do not contain any two slashes in sequence
\li contain slash-separated parts, each of which is composed of ASCII letters, digits and
underscores ("_")
\endlist
*/
bool isValidObjectPath(const QString &path)
{
if (path == "/"_L1)
return true;
if (!path.startsWith(u'/') || path.indexOf("//"_L1) != -1 ||
path.endsWith(u'/'))
return false;
// it starts with /, so we skip the empty first part
const auto parts = QStringView{path}.mid(1).split(u'/');
for (QStringView part : parts)
if (!isValidPartOfObjectPath(part))
return false;
return true;
}
/*!
\fn bool isValidBasicType(int type)
Returns \c true if \a c is a valid, basic D-Bus type.
*/
bool isValidBasicType(int c)
{
return isBasicType(c);
}
/*!
\fn bool isValidFixedType(int type)
Returns \c true if \a c is a valid, fixed D-Bus type.
*/
bool isValidFixedType(int c)
{
return isFixedType(c);
}
/*!
\fn bool isValidSignature(const QString &signature)
Returns \c true if \a signature is a valid D-Bus type signature for one or more types.
This function returns \c true if it can all of \a signature into valid, individual types and no
characters remain in \a signature.
\sa isValidSingleSignature()
*/
bool isValidSignature(const QString &signature)
{
QByteArray ba = signature.toLatin1();
const char *data = ba.constData();
while (true) {
data = validateSingleType(data);
if (!data)
return false;
if (*data == '\0')
return true;
}
}
/*!
\fn bool isValidSingleSignature(const QString &signature)
Returns \c true if \a signature is a valid D-Bus type signature for exactly one full type. This
function tries to convert the type signature into a D-Bus type and, if it succeeds and no
characters remain in the signature, it returns \c true.
*/
bool isValidSingleSignature(const QString &signature)
{
QByteArray ba = signature.toLatin1();
const char *data = validateSingleType(ba.constData());
return data && *data == '\0';
}
} // namespace QDBusUtil
QT_END_NAMESPACE
#endif // QT_NO_DBUS

149
src/dbus/qdbusutil_p.h Normal file
View File

@ -0,0 +1,149 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#ifndef QDBUSUTIL_P_H
#define QDBUSUTIL_P_H
#include <QtDBus/private/qtdbusglobal_p.h>
#include <QtDBus/qdbuserror.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
#include "qdbus_symbols_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
#define Q_DBUS_NO_EXPORT // force syncqt looking into this namespace
namespace Q_DBUS_NO_EXPORT QDBusUtil
{
Q_DBUS_EXPORT bool isValidInterfaceName(const QString &ifaceName);
Q_DBUS_EXPORT bool isValidUniqueConnectionName(QStringView busName);
Q_DBUS_EXPORT bool isValidBusName(const QString &busName);
Q_DBUS_EXPORT bool isValidMemberName(QStringView memberName);
Q_DBUS_EXPORT bool isValidErrorName(const QString &errorName);
Q_DBUS_EXPORT bool isValidPartOfObjectPath(QStringView path);
Q_DBUS_EXPORT bool isValidObjectPath(const QString &path);
Q_DBUS_EXPORT bool isValidFixedType(int c);
Q_DBUS_EXPORT bool isValidBasicType(int c);
Q_DBUS_EXPORT bool isValidSignature(const QString &signature);
Q_DBUS_EXPORT bool isValidSingleSignature(const QString &signature);
Q_DBUS_EXPORT QString argumentToString(const QVariant &variant);
enum AllowEmptyFlag {
EmptyAllowed,
EmptyNotAllowed
};
inline bool checkInterfaceName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
{
if (name.isEmpty()) {
if (empty == EmptyAllowed) return true;
*error = QDBusError(QDBusError::InvalidInterface, QLatin1StringView("Interface name cannot be empty"));
return false;
}
if (isValidInterfaceName(name)) return true;
*error = QDBusError(QDBusError::InvalidInterface, QLatin1StringView("Invalid interface class: %1").arg(name));
return false;
}
inline bool checkBusName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
{
if (name.isEmpty()) {
if (empty == EmptyAllowed) return true;
*error = QDBusError(QDBusError::InvalidService, QLatin1StringView("Service name cannot be empty"));
return false;
}
if (isValidBusName(name)) return true;
*error = QDBusError(QDBusError::InvalidService, QLatin1StringView("Invalid service name: %1").arg(name));
return false;
}
inline bool checkObjectPath(const QString &path, AllowEmptyFlag empty, QDBusError *error)
{
if (path.isEmpty()) {
if (empty == EmptyAllowed) return true;
*error = QDBusError(QDBusError::InvalidObjectPath, QLatin1StringView("Object path cannot be empty"));
return false;
}
if (isValidObjectPath(path)) return true;
*error = QDBusError(QDBusError::InvalidObjectPath, QLatin1StringView("Invalid object path: %1").arg(path));
return false;
}
inline bool checkMemberName(const QString &name, AllowEmptyFlag empty, QDBusError *error, const char *nameType = nullptr)
{
if (!nameType) nameType = "member";
if (name.isEmpty()) {
if (empty == EmptyAllowed) return true;
*error = QDBusError(QDBusError::InvalidMember, QLatin1StringView(nameType) + QLatin1StringView(" name cannot be empty"));
return false;
}
if (isValidMemberName(name)) return true;
*error = QDBusError(QDBusError::InvalidMember, QLatin1StringView("Invalid %1 name: %2")
.arg(QLatin1StringView(nameType), name));
return false;
}
inline bool checkErrorName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
{
if (name.isEmpty()) {
if (empty == EmptyAllowed) return true;
*error = QDBusError(QDBusError::InvalidInterface, QLatin1StringView("Error name cannot be empty"));
return false;
}
if (isValidErrorName(name)) return true;
*error = QDBusError(QDBusError::InvalidInterface, QLatin1StringView("Invalid error name: %1").arg(name));
return false;
}
inline QString dbusService()
{ return QStringLiteral(DBUS_SERVICE_DBUS); }
inline QString dbusPath()
{ return QStringLiteral(DBUS_PATH_DBUS); }
inline QString dbusPathLocal()
{ return QStringLiteral(DBUS_PATH_LOCAL); }
inline QString dbusInterface()
{
// it's the same string, but just be sure
Q_ASSERT(dbusService() == QLatin1StringView(DBUS_INTERFACE_DBUS));
return dbusService();
}
inline QString dbusInterfaceProperties()
{ return QStringLiteral(DBUS_INTERFACE_PROPERTIES); }
inline QString dbusInterfaceIntrospectable()
{ return QStringLiteral(DBUS_INTERFACE_INTROSPECTABLE); }
inline QString nameOwnerChanged()
{ return QStringLiteral("NameOwnerChanged"); }
inline QString disconnectedErrorMessage()
{ return QStringLiteral("Not connected to D-Bus server"); }
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,64 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusvirtualobject.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
/*!
Constructs a QDBusVirtualObject with \a parent.
*/
QDBusVirtualObject::QDBusVirtualObject(QObject *parent) :
QObject(parent)
{
}
/*!
Destroys the object, deleting all of its child objects.
*/
QDBusVirtualObject::~QDBusVirtualObject()
{
}
QT_END_NAMESPACE
#include "moc_qdbusvirtualobject.cpp"
/*!
\class QDBusVirtualObject
\inmodule QtDBus
\since 5.1
\brief The QDBusVirtualObject class is used to handle several DBus paths with one class.
*/
/*!
\fn bool QDBusVirtualObject::handleMessage(const QDBusMessage &message, const QDBusConnection &connection) = 0
This function needs to handle all messages to the path of the
virtual object, when the SubPath option is specified.
The service, path, interface and methods are all part of the \a message.
Parameter \a connection is the connection handle.
Must return \c true when the message is handled, otherwise \c false (will generate dbus error message).
*/
/*!
\fn QString QDBusVirtualObject::introspect(const QString &path) const
This function needs to handle the introspection of the
virtual object on \a path. It must return xml of the form:
\code
<interface name="org.qtproject.QtDBus.MyObject" >
<property access="readwrite" type="i" name="prop1" />
</interface>
\endcode
If you pass the SubPath option, this introspection has to include all child nodes.
Otherwise QDBus handles the introspection of the child nodes.
*/
#endif // QT_NO_DBUS

View File

@ -0,0 +1,36 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSVIRTUALOBJECT_H
#define QDBUSVIRTUALOBJECT_H
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qobject.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
class QDBusMessage;
class QDBusConnection;
class Q_DBUS_EXPORT QDBusVirtualObject : public QObject
{
Q_OBJECT
public:
explicit QDBusVirtualObject(QObject *parent = nullptr);
virtual ~QDBusVirtualObject();
virtual QString introspect(const QString &path) const = 0;
virtual bool handleMessage(const QDBusMessage &message, const QDBusConnection &connection) = 0;
private:
Q_DISABLE_COPY(QDBusVirtualObject)
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,284 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qmetaobject.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
#include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT
#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
#include "qdbusconnection_p.h" // for the flags
#include "qdbusmetatype_p.h"
#include "qdbusmetatype.h"
#include "qdbusutil_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
extern Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
const QMetaObject *base, int flags);
static inline QString typeNameToXml(const char *typeName)
{
// ### copied from qtextdocument.cpp
// ### move this into Qt Core at some point
const QLatin1StringView plain(typeName);
QString rich;
rich.reserve(int(plain.size() * 1.1));
for (int i = 0; i < plain.size(); ++i) {
if (plain.at(i) == u'<')
rich += "&lt;"_L1;
else if (plain.at(i) == u'>')
rich += "&gt;"_L1;
else if (plain.at(i) == u'&')
rich += "&amp;"_L1;
else
rich += plain.at(i);
}
return rich;
}
static inline QLatin1StringView accessAsString(bool read, bool write)
{
if (read)
return write ? "readwrite"_L1 : "read"_L1 ;
else
return write ? "write"_L1 : ""_L1 ;
}
// implement the D-Bus org.freedesktop.DBus.Introspectable interface
// we do that by analysing the metaObject of all the adaptor interfaces
static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset)
{
QString retval;
// start with properties:
if (flags & (QDBusConnection::ExportScriptableProperties |
QDBusConnection::ExportNonScriptableProperties)) {
for (int i = propOffset; i < mo->propertyCount(); ++i) {
QMetaProperty mp = mo->property(i);
if (!((mp.isScriptable() && (flags & QDBusConnection::ExportScriptableProperties)) ||
(!mp.isScriptable() && (flags & QDBusConnection::ExportNonScriptableProperties))))
continue;
QMetaType type = mp.metaType();
if (!type.isValid())
continue;
const char *signature = QDBusMetaType::typeToSignature(type);
if (!signature)
continue;
retval += " <property name=\"%1\" type=\"%2\" access=\"%3\""_L1
.arg(QLatin1StringView(mp.name()),
QLatin1StringView(signature),
accessAsString(mp.isReadable(), mp.isWritable()));
if (!QDBusMetaType::signatureToMetaType(signature).isValid()) {
const char *typeName = type.name();
retval += ">\n <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n"_L1
.arg(typeNameToXml(typeName));
} else {
retval += "/>\n"_L1;
}
}
}
// now add methods:
for (int i = methodOffset; i < mo->methodCount(); ++i) {
QMetaMethod mm = mo->method(i);
bool isSignal = false;
bool isSlot = false;
if (mm.methodType() == QMetaMethod::Signal)
// adding a signal
isSignal = true;
else if (mm.access() == QMetaMethod::Public && mm.methodType() == QMetaMethod::Slot)
isSlot = true;
else if (mm.access() == QMetaMethod::Public && mm.methodType() == QMetaMethod::Method)
; // invokable, neither signal nor slot
else
continue; // neither signal nor public method/slot
if (isSignal && !(flags & (QDBusConnection::ExportScriptableSignals |
QDBusConnection::ExportNonScriptableSignals)))
continue; // we're not exporting any signals
if (!isSignal && (!(flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) &&
!(flags & (QDBusConnection::ExportScriptableInvokables | QDBusConnection::ExportNonScriptableInvokables))))
continue; // we're not exporting any slots or invokables
// we want to skip non-scriptable stuff as early as possible to avoid bogus warning
// for methods that are not being exported at all
bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
if (!isScriptable && !(flags & (isSignal ? QDBusConnection::ExportNonScriptableSignals : QDBusConnection::ExportNonScriptableInvokables | QDBusConnection::ExportNonScriptableSlots)))
continue;
QString xml = QString::asprintf(" <%s name=\"%s\">\n",
isSignal ? "signal" : "method", mm.name().constData());
// check the return type first
QMetaType typeId = mm.returnMetaType();
if (typeId.isValid() && typeId.id() != QMetaType::Void) {
const char *typeName = QDBusMetaType::typeToSignature(typeId);
if (typeName) {
xml += " <arg type=\"%1\" direction=\"out\"/>\n"_L1
.arg(typeNameToXml(typeName));
// do we need to describe this argument?
if (!QDBusMetaType::signatureToMetaType(typeName).isValid())
xml += " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n"_L1
.arg(typeNameToXml(QMetaType(typeId).name()));
} else {
qWarning() << "Unsupported return type" << typeId.id() << typeId.name() << "in method" << mm.name();
continue;
}
}
else if (!typeId.isValid()) {
qWarning() << "Invalid return type in method" << mm.name();
continue; // wasn't a valid type
}
QList<QByteArray> names = mm.parameterNames();
QList<QMetaType> types;
QString errorMsg;
int inputCount = qDBusParametersForMethod(mm, types, errorMsg);
if (inputCount == -1) {
qWarning() << "Skipped method" << mm.name() << ":" << qPrintable(errorMsg);
continue; // invalid form
}
if (isSignal && inputCount + 1 != types.size())
continue; // signal with output arguments?
if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message())
continue; // signal with QDBusMessage argument?
if (isSignal && mm.attributes() & QMetaMethod::Cloned)
continue; // cloned signal?
int j;
for (j = 1; j < types.size(); ++j) {
// input parameter for a slot or output for a signal
if (types.at(j) == QDBusMetaTypeId::message()) {
isScriptable = true;
continue;
}
QString name;
if (!names.at(j - 1).isEmpty())
name = "name=\"%1\" "_L1.arg(QLatin1StringView(names.at(j - 1)));
bool isOutput = isSignal || j > inputCount;
const char *signature = QDBusMetaType::typeToSignature(types.at(j));
xml += QString::asprintf(" <arg %lstype=\"%s\" direction=\"%s\"/>\n",
qUtf16Printable(name), signature, isOutput ? "out" : "in");
// do we need to describe this argument?
if (!QDBusMetaType::signatureToMetaType(signature).isValid()) {
const char *typeName = QMetaType(types.at(j)).name();
xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
.arg(isOutput ? "Out"_L1 : "In"_L1)
.arg(isOutput && !isSignal ? j - inputCount : j - 1)
.arg(typeNameToXml(typeName));
}
}
int wantedMask;
if (isScriptable)
wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals
: isSlot ? QDBusConnection::ExportScriptableSlots
: QDBusConnection::ExportScriptableInvokables;
else
wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals
: isSlot ? QDBusConnection::ExportNonScriptableSlots
: QDBusConnection::ExportNonScriptableInvokables;
if ((flags & wantedMask) != wantedMask)
continue;
if (qDBusCheckAsyncTag(mm.tag()))
// add the no-reply annotation
xml += " <annotation name=\"" ANNOTATION_NO_WAIT "\" value=\"true\"/>\n"_L1;
retval += xml;
retval += " </%1>\n"_L1.arg(isSignal ? "signal"_L1 : "method"_L1);
}
return retval;
}
QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
const QMetaObject *base, int flags)
{
if (interface.isEmpty())
// generate the interface name from the meta object
interface = qDBusInterfaceFromMetaObject(mo);
QString xml;
int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
if (idx >= mo->classInfoOffset())
return QString::fromUtf8(mo->classInfo(idx).value());
else
xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
if (xml.isEmpty())
return QString(); // don't add an empty interface
return " <interface name=\"%1\">\n%2 </interface>\n"_L1
.arg(interface, xml);
}
#if 0
QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
int flags)
{
if (interface.isEmpty()) {
// generate the interface name from the meta object
int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
if (idx >= mo->classInfoOffset()) {
interface = QLatin1StringView(mo->classInfo(idx).value());
} else {
interface = QLatin1StringView(mo->className());
interface.replace("::"_L1, "."_L1);
if (interface.startsWith("QDBus"_L1)) {
interface.prepend("org.qtproject.QtDBus."_L1);
} else if (interface.startsWith(u'Q') &&
interface.length() >= 2 && interface.at(1).isUpper()) {
// assume it's Qt
interface.prepend("org.qtproject.Qt."_L1);
} else if (!QCoreApplication::instance()||
QCoreApplication::instance()->applicationName().isEmpty()) {
interface.prepend("local."_L1);
} else {
interface.prepend(u'.').prepend(QCoreApplication::instance()->applicationName());
QStringList domainName =
QCoreApplication::instance()->organizationDomain().split(u'.',
Qt::SkipEmptyParts);
if (domainName.isEmpty())
interface.prepend("local."_L1);
else
for (int i = 0; i < domainName.count(); ++i)
interface.prepend(u'.').prepend(domainName.at(i));
}
}
}
QString xml;
int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
if (idx >= mo->classInfoOffset())
return QString::fromUtf8(mo->classInfo(idx).value());
else
xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
if (xml.isEmpty())
return QString(); // don't add an empty interface
return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
.arg(interface, xml);
}
#endif
QT_END_NAMESPACE
#endif // QT_NO_DBUS

371
src/dbus/qdbusxmlparser.cpp Normal file
View File

@ -0,0 +1,371 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdbusxmlparser_p.h"
#include "qdbusutil_p.h"
#include <QtCore/qmap.h>
#include <QtCore/qvariant.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qxmlstream.h>
#include <QtCore/qdebug.h>
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(dbusParser, "dbus.parser", QtWarningMsg)
#define qDBusParserError(...) qCDebug(dbusParser, ##__VA_ARGS__)
static bool parseArg(const QXmlStreamAttributes &attributes, QDBusIntrospection::Argument &argData,
QDBusIntrospection::Interface *ifaceData)
{
const QString argType = attributes.value("type"_L1).toString();
bool ok = QDBusUtil::isValidSingleSignature(argType);
if (!ok) {
qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
qPrintable(argType));
}
argData.name = attributes.value("name"_L1).toString();
argData.type = argType;
ifaceData->introspection += " <arg"_L1;
if (attributes.hasAttribute("direction"_L1)) {
const QString direction = attributes.value("direction"_L1).toString();
ifaceData->introspection += " direction=\""_L1 + direction + u'"';
}
ifaceData->introspection += " type=\""_L1 + argData.type + u'"';
if (!argData.name.isEmpty())
ifaceData->introspection += " name=\""_L1 + argData.name + u'"';
ifaceData->introspection += "/>\n"_L1;
return ok;
}
static bool parseAnnotation(const QXmlStreamReader &xml, QDBusIntrospection::Annotations &annotations,
QDBusIntrospection::Interface *ifaceData, bool interfaceAnnotation = false)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "annotation"_L1);
const QXmlStreamAttributes attributes = xml.attributes();
const QString name = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidInterfaceName(name)) {
qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
qPrintable(name));
return false;
}
const QString value = attributes.value("value"_L1).toString();
annotations.insert(name, value);
if (!interfaceAnnotation)
ifaceData->introspection += " "_L1;
ifaceData->introspection += " <annotation value=\""_L1 + value.toHtmlEscaped() + "\" name=\""_L1 + name + "\"/>\n"_L1;
return true;
}
static bool parseProperty(QXmlStreamReader &xml, QDBusIntrospection::Property &propertyData,
QDBusIntrospection::Interface *ifaceData)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "property"_L1);
QXmlStreamAttributes attributes = xml.attributes();
const QString propertyName = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidMemberName(propertyName)) {
qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
qPrintable(propertyName), qPrintable(ifaceData->name));
xml.skipCurrentElement();
return false;
}
// parse data
propertyData.name = propertyName;
propertyData.type = attributes.value("type"_L1).toString();
if (!QDBusUtil::isValidSingleSignature(propertyData.type)) {
// cannot be!
qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection",
qPrintable(propertyData.type), qPrintable(ifaceData->name),
qPrintable(propertyName));
}
const QString access = attributes.value("access"_L1).toString();
if (access == "read"_L1)
propertyData.access = QDBusIntrospection::Property::Read;
else if (access == "write"_L1)
propertyData.access = QDBusIntrospection::Property::Write;
else if (access == "readwrite"_L1)
propertyData.access = QDBusIntrospection::Property::ReadWrite;
else {
qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection",
qPrintable(access), qPrintable(ifaceData->name),
qPrintable(propertyName));
return false; // invalid one!
}
ifaceData->introspection += " <property access=\""_L1 + access + "\" type=\""_L1 + propertyData.type + "\" name=\""_L1 + propertyName + u'"';
if (!xml.readNextStartElement()) {
ifaceData->introspection += "/>\n"_L1;
} else {
ifaceData->introspection += ">\n"_L1;
do {
if (xml.name() == "annotation"_L1) {
parseAnnotation(xml, propertyData.annotations, ifaceData);
} else if (xml.prefix().isEmpty()) {
qDBusParserError() << "Unknown element" << xml.name() << "while checking for annotations";
}
xml.skipCurrentElement();
} while (xml.readNextStartElement());
ifaceData->introspection += " </property>\n"_L1;
}
if (!xml.isEndElement() || xml.name() != "property"_L1) {
qDBusParserError() << "Invalid property specification" << xml.tokenString() << xml.name();
return false;
}
return true;
}
static bool parseMethod(QXmlStreamReader &xml, QDBusIntrospection::Method &methodData,
QDBusIntrospection::Interface *ifaceData)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "method"_L1);
const QXmlStreamAttributes attributes = xml.attributes();
const QString methodName = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidMemberName(methodName)) {
qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
qPrintable(methodName), qPrintable(ifaceData->name));
return false;
}
methodData.name = methodName;
ifaceData->introspection += " <method name=\""_L1 + methodName + u'"';
QDBusIntrospection::Arguments outArguments;
QDBusIntrospection::Arguments inArguments;
QDBusIntrospection::Annotations annotations;
if (!xml.readNextStartElement()) {
ifaceData->introspection += "/>\n"_L1;
} else {
ifaceData->introspection += ">\n"_L1;
do {
if (xml.name() == "annotation"_L1) {
parseAnnotation(xml, annotations, ifaceData);
} else if (xml.name() == "arg"_L1) {
const QXmlStreamAttributes attributes = xml.attributes();
const QString direction = attributes.value("direction"_L1).toString();
QDBusIntrospection::Argument argument;
if (!attributes.hasAttribute("direction"_L1) || direction == "in"_L1) {
parseArg(attributes, argument, ifaceData);
inArguments << argument;
} else if (direction == "out"_L1) {
parseArg(attributes, argument, ifaceData);
outArguments << argument;
}
} else if (xml.prefix().isEmpty()) {
qDBusParserError() << "Unknown element" << xml.name() << "while checking for method arguments";
}
xml.skipCurrentElement();
} while (xml.readNextStartElement());
ifaceData->introspection += " </method>\n"_L1;
}
methodData.inputArgs = inArguments;
methodData.outputArgs = outArguments;
methodData.annotations = annotations;
return true;
}
static bool parseSignal(QXmlStreamReader &xml, QDBusIntrospection::Signal &signalData,
QDBusIntrospection::Interface *ifaceData)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "signal"_L1);
const QXmlStreamAttributes attributes = xml.attributes();
const QString signalName = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidMemberName(signalName)) {
qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
qPrintable(signalName), qPrintable(ifaceData->name));
return false;
}
signalData.name = signalName;
ifaceData->introspection += " <signal name=\""_L1 + signalName + u'"';
QDBusIntrospection::Arguments arguments;
QDBusIntrospection::Annotations annotations;
if (!xml.readNextStartElement()) {
ifaceData->introspection += "/>\n"_L1;
} else {
ifaceData->introspection += ">\n"_L1;
do {
if (xml.name() == "annotation"_L1) {
parseAnnotation(xml, annotations, ifaceData);
} else if (xml.name() == "arg"_L1) {
const QXmlStreamAttributes attributes = xml.attributes();
QDBusIntrospection::Argument argument;
if (!attributes.hasAttribute("direction"_L1) ||
attributes.value("direction"_L1) == "out"_L1) {
parseArg(attributes, argument, ifaceData);
arguments << argument;
}
} else {
qDBusParserError() << "Unknown element" << xml.name() << "while checking for signal arguments";
}
xml.skipCurrentElement();
} while (xml.readNextStartElement());
ifaceData->introspection += " </signal>\n"_L1;
}
signalData.outputArgs = arguments;
signalData.annotations = annotations;
return true;
}
static void readInterface(QXmlStreamReader &xml, QDBusIntrospection::Object *objData,
QDBusIntrospection::Interfaces *interfaces)
{
const QString ifaceName = xml.attributes().value("name"_L1).toString();
if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
qPrintable(ifaceName));
return;
}
objData->interfaces.append(ifaceName);
QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
ifaceData->name = ifaceName;
ifaceData->introspection += " <interface name=\""_L1 + ifaceName + "\">\n"_L1;
while (xml.readNextStartElement()) {
if (xml.name() == "method"_L1) {
QDBusIntrospection::Method methodData;
if (parseMethod(xml, methodData, ifaceData))
ifaceData->methods.insert(methodData.name, methodData);
} else if (xml.name() == "signal"_L1) {
QDBusIntrospection::Signal signalData;
if (parseSignal(xml, signalData, ifaceData))
ifaceData->signals_.insert(signalData.name, signalData);
} else if (xml.name() == "property"_L1) {
QDBusIntrospection::Property propertyData;
if (parseProperty(xml, propertyData, ifaceData))
ifaceData->properties.insert(propertyData.name, propertyData);
} else if (xml.name() == "annotation"_L1) {
parseAnnotation(xml, ifaceData->annotations, ifaceData, true);
xml.skipCurrentElement(); // skip over annotation object
} else {
if (xml.prefix().isEmpty()) {
qDBusParserError() << "Unknown element while parsing interface" << xml.name();
}
xml.skipCurrentElement();
}
}
ifaceData->introspection += " </interface>"_L1;
interfaces->insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
if (!xml.isEndElement() || xml.name() != "interface"_L1) {
qDBusParserError() << "Invalid Interface specification";
}
}
static void readNode(const QXmlStreamReader &xml, QDBusIntrospection::Object *objData, int nodeLevel)
{
const QString objName = xml.attributes().value("name"_L1).toString();
const QString fullName = objData->path.endsWith(u'/')
? (objData->path + objName)
: QString(objData->path + u'/' + objName);
if (!QDBusUtil::isValidObjectPath(fullName)) {
qDBusParserError("Invalid D-BUS object path '%s' found while parsing introspection",
qPrintable(fullName));
return;
}
if (nodeLevel > 0)
objData->childObjects.append(objName);
}
QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
const QString& xmlData)
: m_service(service), m_path(path), m_object(new QDBusIntrospection::Object)
{
// qDBusParserError() << "parsing" << xmlData;
m_object->service = m_service;
m_object->path = m_path;
QXmlStreamReader xml(xmlData);
int nodeLevel = -1;
while (!xml.atEnd()) {
xml.readNext();
switch (xml.tokenType()) {
case QXmlStreamReader::StartElement:
if (xml.name() == "node"_L1) {
readNode(xml, m_object, ++nodeLevel);
} else if (xml.name() == "interface"_L1) {
readInterface(xml, m_object, &m_interfaces);
} else {
if (xml.prefix().isEmpty()) {
qDBusParserError() << "skipping unknown element" << xml.name();
}
xml.skipCurrentElement();
}
break;
case QXmlStreamReader::EndElement:
if (xml.name() == "node"_L1) {
--nodeLevel;
} else {
qDBusParserError() << "Invalid Node declaration" << xml.name();
}
break;
case QXmlStreamReader::StartDocument:
case QXmlStreamReader::EndDocument:
case QXmlStreamReader::DTD:
// not interested
break;
case QXmlStreamReader::Comment:
// ignore comments and processing instructions
break;
case QXmlStreamReader::Characters:
// ignore whitespace
if (xml.isWhitespace())
break;
Q_FALLTHROUGH();
default:
qDBusParserError() << "unknown token" << xml.name() << xml.tokenString();
break;
}
}
if (xml.hasError()) {
qDBusParserError() << "xml error" << xml.errorString() << "doc" << xmlData;
}
}
QT_END_NAMESPACE
#endif // QT_NO_DBUS

View File

@ -0,0 +1,50 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDBUSXMLPARSER_P_H
#define QDBUSXMLPARSER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QLibrary class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/private/qtdbusglobal_p.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmap.h>
#include "qdbusintrospection_p.h"
#ifndef QT_NO_DBUS
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(dbusParser)
/*!
\internal
*/
class QDBusXmlParser
{
QString m_service;
QString m_path;
QSharedDataPointer<QDBusIntrospection::Object> m_object;
QDBusIntrospection::Interfaces m_interfaces;
public:
QDBusXmlParser(const QString& service, const QString& path,
const QString& xmlData);
inline QDBusIntrospection::Interfaces interfaces() const { return m_interfaces; }
inline QSharedDataPointer<QDBusIntrospection::Object> object() const { return m_object; }
};
QT_END_NAMESPACE
#endif // QT_NO_DBUS
#endif

View File

@ -0,0 +1,18 @@
{
"Id": "libdbus-1-headers",
"Name": "libdus-1 headers",
"QDocModule": "qtdbus",
"QtUsage": "Qt D-Bus uses constants and typedefs from libdbus-1 headers.",
"Description": "D-Bus is a message bus system, a simple way for applications to talk to one another.",
"Homepage": "https://www.freedesktop.org/wiki/Software/dbus/",
"Version": "Minimal supported is 1.2, compatible up to ...",
"Version": "dbus-1.13.12",
"LicenseId": "AFL-2.1 OR GPL-2.0-or-later",
"License": "Academic Free License v2.1, or GNU General Public License v2.0 or later",
"LicenseFile": "LIBDBUS-1-LICENSE.txt",
"Comment": "Fragments from various upstream files, see comments in ...",
"Files": "dbus_minimal_p.h",
"Copyright": "Copyright (C) 2002, 2003 CodeFactory AB
Copyright (C) 2004, 2005 Red Hat, Inc."
}

28
src/dbus/qtdbusglobal.h Normal file
View File

@ -0,0 +1,28 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTDBUSGLOBAL_H
#define QTDBUSGLOBAL_H
#if 0
#pragma qt_deprecates(qdbusmacros.h)
#endif
#include <QtCore/qglobal.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qvariant.h>
#ifndef Q_MOC_RUN
# define Q_NOREPLY
#endif
#ifdef Q_CC_MSVC
#include <QtCore/qlist.h>
#include <QtCore/qset.h>
#endif
#ifndef QT_NO_DBUS
#include <QtDBus/qtdbusexports.h>
#endif // QT_NO_DBUS
#endif

21
src/dbus/qtdbusglobal_p.h Normal file
View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTDBUSGLOBAL_P_H
#define QTDBUSGLOBAL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/private/qglobal_p.h>
#endif // QTDBUSGLOBAL_P_H