init
commit
1516be627a
@ -0,0 +1,54 @@
|
||||
# C++ objects and libs
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.a
|
||||
*.la
|
||||
*.lai
|
||||
*.so
|
||||
*.so.*
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
# Qt-es
|
||||
object_script.*.Release
|
||||
object_script.*.Debug
|
||||
*_plugin_import.cpp
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
*.qbs.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
*.qmlc
|
||||
*.jsc
|
||||
Makefile*
|
||||
*build-*
|
||||
*.qm
|
||||
*.prl
|
||||
|
||||
# Qt unit tests
|
||||
target_wrapper.*
|
||||
|
||||
# QtCreator
|
||||
*.autosave
|
||||
|
||||
# QtCreator Qml
|
||||
*.qmlproject.user
|
||||
*.qmlproject.user.*
|
||||
|
||||
# QtCreator CMake
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# QtCreator 4.8< compilation database
|
||||
compile_commands.json
|
||||
|
||||
# QtCreator local machine specific files for imported projects
|
||||
*creator.user*
|
||||
|
||||
build/*
|
||||
@ -0,0 +1,58 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(libcutefish)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(QT Core Gui Quick QuickControls2 DBus Xml Concurrent)
|
||||
find_package(Qt5 REQUIRED ${QT})
|
||||
|
||||
# Get the installation directory from qmake
|
||||
get_target_property(QT_QMAKE_EXECUTABLE ${Qt5Core_QMAKE_EXECUTABLE} IMPORTED_LOCATION)
|
||||
if(NOT QT_QMAKE_EXECUTABLE)
|
||||
message(FATAL_ERROR "qmake is not found.")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_QML
|
||||
OUTPUT_VARIABLE INSTALL_QMLDIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(INSTALL_QMLDIR)
|
||||
message(STATUS "qml directory:" "${INSTALL_QMLDIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "qml directory cannot be detected.")
|
||||
endif()
|
||||
# -------------------------------------------
|
||||
|
||||
add_subdirectory(accounts)
|
||||
add_subdirectory(mpris)
|
||||
add_subdirectory(networkmanagement)
|
||||
add_subdirectory(screen)
|
||||
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 a brief idea of what it does.>
|
||||
Copyright (C) <year> <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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@ -0,0 +1,21 @@
|
||||
# System Library
|
||||
|
||||
## Dependencies
|
||||
|
||||
```shell
|
||||
sudo pacman -S gcc cmake qt5-base qt5-quickcontrols2 networkmanager-qt modemmanager-qt
|
||||
```
|
||||
|
||||
## Build and Install
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project has been licensed by GPLv3.
|
||||
@ -0,0 +1,33 @@
|
||||
set(ACCOUNTS_SRCS
|
||||
accountsmanager.cpp
|
||||
accountsmanager.h
|
||||
accountsmanager_p.h
|
||||
useraccount.cpp
|
||||
useraccount.h
|
||||
useraccount_p.h
|
||||
usersmodel.cpp
|
||||
usersmodel.h
|
||||
usersmodel_p.h
|
||||
qmlplugins.cpp
|
||||
)
|
||||
|
||||
qt5_add_dbus_interface(ACCOUNTS_SRCS
|
||||
org.freedesktop.Accounts.User.xml
|
||||
user_interface)
|
||||
qt5_add_dbus_interface(ACCOUNTS_SRCS
|
||||
org.freedesktop.Accounts.xml
|
||||
accounts_interface)
|
||||
|
||||
# set_source_files_properties(${ACCOUNTS_SRCS} PROPERTIES SKIP_AUTOGEN ON)
|
||||
|
||||
add_library(cutefishaccounts_qmlplugins SHARED ${ACCOUNTS_SRCS})
|
||||
|
||||
target_link_libraries (cutefishaccounts_qmlplugins
|
||||
Qt5::Core
|
||||
Qt5::DBus
|
||||
Qt5::Quick
|
||||
Qt5::Gui
|
||||
)
|
||||
|
||||
install(TARGETS cutefishaccounts_qmlplugins DESTINATION ${INSTALL_QMLDIR}/Cutefish/Accounts)
|
||||
install(FILES qmldir DESTINATION ${INSTALL_QMLDIR}/Cutefish/Accounts)
|
||||
@ -0,0 +1,419 @@
|
||||
/****************************************************************************
|
||||
* This file is part of Qt AccountsService.
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtDBus/QDBusPendingCallWatcher>
|
||||
|
||||
#include "accountsmanager.h"
|
||||
#include "accountsmanager_p.h"
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
/*
|
||||
* AccountsManagerPrivate
|
||||
*/
|
||||
|
||||
AccountsManagerPrivate::AccountsManagerPrivate(const QDBusConnection &bus)
|
||||
{
|
||||
interface =
|
||||
new OrgFreedesktopAccountsInterface(QStringLiteral("org.freedesktop.Accounts"),
|
||||
QStringLiteral("/org/freedesktop/Accounts"), bus);
|
||||
}
|
||||
|
||||
AccountsManagerPrivate::~AccountsManagerPrivate()
|
||||
{
|
||||
qDeleteAll(usersCache);
|
||||
delete interface;
|
||||
}
|
||||
|
||||
void AccountsManagerPrivate::_q_userAdded(const QDBusObjectPath &path)
|
||||
{
|
||||
Q_Q(AccountsManager);
|
||||
|
||||
if (usersCache.contains(path.path())) {
|
||||
Q_EMIT q->userAdded(usersCache[path.path()]);
|
||||
return;
|
||||
}
|
||||
|
||||
UserAccount *account = new UserAccount(path.path(), interface->connection());
|
||||
usersCache[path.path()] = account;
|
||||
Q_EMIT q->userAdded(account);
|
||||
}
|
||||
|
||||
void AccountsManagerPrivate::_q_userDeleted(const QDBusObjectPath &path)
|
||||
{
|
||||
Q_Q(AccountsManager);
|
||||
|
||||
UserAccount *account = usersCache.value(path.path(), nullptr);
|
||||
if (!account)
|
||||
account = new UserAccount(path.path());
|
||||
usersCache.remove(path.path());
|
||||
Q_EMIT q->userDeleted(account->userId());
|
||||
account->deleteLater();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class AccountsManager
|
||||
\brief AccountsManager provides the backend for user management.
|
||||
|
||||
The AccountsManager class allows for querying and manipiulating user
|
||||
account information.
|
||||
|
||||
\author Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a AccountsManager object.
|
||||
*/
|
||||
AccountsManager::AccountsManager(const QDBusConnection &bus, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d_ptr(new AccountsManagerPrivate(bus))
|
||||
{
|
||||
qRegisterMetaType<UserAccount::AccountType>("UserAccount::AccountType");
|
||||
qRegisterMetaType<UserAccount *>("UserAccount*");
|
||||
|
||||
d_ptr->q_ptr = this;
|
||||
|
||||
connect(d_ptr->interface, SIGNAL(UserAdded(QDBusObjectPath)), // clazy:exclude=old-style-connect
|
||||
this, SLOT(_q_userAdded(QDBusObjectPath)));
|
||||
connect(d_ptr->interface,
|
||||
SIGNAL(UserDeleted(QDBusObjectPath)), // clazy:exclude=old-style-connect
|
||||
this, SLOT(_q_userDeleted(QDBusObjectPath)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroy a AccountsManager object.
|
||||
*/
|
||||
AccountsManager::~AccountsManager()
|
||||
{
|
||||
delete d_ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
Caches a user account, so that it shows up in listCachedUsers() output.
|
||||
The user name may be a remote user, but the system must be able to lookup
|
||||
the user name and resolve the user information.
|
||||
|
||||
A userCached() signal with a UserAccount pointer will be emitted as soon
|
||||
as the user account has been cached by AccountsService.
|
||||
|
||||
\param userName The user name for the user.
|
||||
*/
|
||||
void AccountsManager::cacheUser(const QString &userName)
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingCall call = d->interface->CacheUser(userName);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](QDBusPendingCallWatcher *w) {
|
||||
QDBusPendingReply<QDBusObjectPath> reply = *w;
|
||||
w->deleteLater();
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't cache user %s: %s", userName.toUtf8().constData(),
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
} else {
|
||||
QDBusObjectPath path = reply.argumentAt<0>();
|
||||
if (path.path().isEmpty())
|
||||
return;
|
||||
|
||||
UserAccount *account = d->usersCache.value(path.path(), nullptr);
|
||||
if (!account) {
|
||||
account = new UserAccount(path.path(), d->interface->connection());
|
||||
d->usersCache[path.path()] = account;
|
||||
}
|
||||
Q_EMIT userCached(userName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*!
|
||||
Releases all metadata about a user account, including icon, language and session.
|
||||
If the user account is from a remote server and the user has never logged in
|
||||
before, then that account will no longer show up in listCachedUsers() output.
|
||||
|
||||
Emits userUncached() when done.
|
||||
|
||||
\param userName The user name for the user.
|
||||
*/
|
||||
void AccountsManager::uncacheUser(const QString &userName)
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingCall call = d->interface->UncacheUser(userName);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](QDBusPendingCallWatcher *w) {
|
||||
QDBusPendingReply<QDBusObjectPath> reply = *w;
|
||||
w->deleteLater();
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't uncache user %s: %s", userName.toUtf8().constData(),
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
} else {
|
||||
QMap<QString, UserAccount *>::iterator it = d->usersCache.begin();
|
||||
while (it != d->usersCache.end()) {
|
||||
auto account = it.value();
|
||||
if (account->userName() == userName) {
|
||||
d->usersCache.erase(++it);
|
||||
account->deleteLater();
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
Q_EMIT userUncached(userName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*!
|
||||
List cache users asynchronously.
|
||||
When the list is ready, \c listCachedUsersFinished will be emitted.
|
||||
*/
|
||||
void AccountsManager::listCachedUsers()
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingCall call = d->interface->ListCachedUsers();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](QDBusPendingCallWatcher *w) {
|
||||
QDBusPendingReply<QList<QDBusObjectPath>> reply = *w;
|
||||
w->deleteLater();
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't list cached users: %s",
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
} else {
|
||||
UserAccountList userList;
|
||||
|
||||
QList<QDBusObjectPath> value = reply.argumentAt<0>();
|
||||
userList.reserve(value.size());
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
const QString path = value.at(i).path();
|
||||
UserAccount *account = d->usersCache.value(path, nullptr);
|
||||
if (!account) {
|
||||
account = new UserAccount(path, d->interface->connection());
|
||||
d->usersCache[path] = account;
|
||||
}
|
||||
userList.append(account);
|
||||
}
|
||||
Q_EMIT listCachedUsersFinished(userList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a list of user accounts.
|
||||
|
||||
This method is synchronous and may take some time.
|
||||
|
||||
\param systemUsers If true, returns also system users.
|
||||
*/
|
||||
UserAccountList AccountsManager::listCachedUsersSync()
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
UserAccountList list;
|
||||
|
||||
QDBusPendingReply<QList<QDBusObjectPath>> reply = d->interface->ListCachedUsers();
|
||||
reply.waitForFinished();
|
||||
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't list cached users: %s",
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
return list;
|
||||
}
|
||||
|
||||
QList<QDBusObjectPath> value = reply.argumentAt<0>();
|
||||
list.reserve(value.size());
|
||||
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
const QString path = value.at(i).path();
|
||||
UserAccount *account = d->usersCache.value(path, nullptr);
|
||||
if (!account) {
|
||||
account = new UserAccount(path, d->interface->connection());
|
||||
d->usersCache[path] = account;
|
||||
}
|
||||
list.append(account);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user with name \a userName from the list of cached users
|
||||
created by \l listCachedUsers().
|
||||
|
||||
\param userName The user name to look up.
|
||||
\return the corresponding UserAccount object.
|
||||
*/
|
||||
UserAccount *AccountsManager::cachedUser(const QString &userName) const
|
||||
{
|
||||
Q_D(const AccountsManager);
|
||||
|
||||
QMap<QString, UserAccount *>::const_iterator it = d->usersCache.constBegin();
|
||||
while (it != d->usersCache.constEnd()) {
|
||||
auto account = it.value();
|
||||
if (account->userName() == userName)
|
||||
return account;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
Finds a user by \a uid.
|
||||
|
||||
This method is synchronous and may take some time.
|
||||
|
||||
\param uid The uid to look up.
|
||||
\return the corresponding UserAccount object.
|
||||
*/
|
||||
UserAccount *AccountsManager::findUserById(qlonglong uid)
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = d->interface->FindUserById(uid);
|
||||
reply.waitForFinished();
|
||||
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't find user by uid %lld: %s", uid,
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QDBusObjectPath path = reply.argumentAt<0>();
|
||||
if (path.path().isEmpty())
|
||||
return nullptr;
|
||||
|
||||
UserAccount *account = d->usersCache.value(path.path(), nullptr);
|
||||
if (!account) {
|
||||
account = new UserAccount(path.path(), d->interface->connection());
|
||||
d->usersCache[path.path()] = account;
|
||||
}
|
||||
return account;
|
||||
}
|
||||
|
||||
/*!
|
||||
Finds a user by user \a userName.
|
||||
|
||||
This method is synchronous and may take some time.
|
||||
|
||||
\param uid The user name to look up.
|
||||
\return the corresponding UserAccount object.
|
||||
*/
|
||||
UserAccount *AccountsManager::findUserByName(const QString &userName)
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = d->interface->FindUserByName(userName);
|
||||
reply.waitForFinished();
|
||||
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't find user by user name %s: %s", userName.toUtf8().constData(),
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QDBusObjectPath path = reply.argumentAt<0>();
|
||||
if (path.path().isEmpty())
|
||||
return nullptr;
|
||||
|
||||
UserAccount *account = d->usersCache.value(path.path(), nullptr);
|
||||
if (!account) {
|
||||
account = new UserAccount(path.path(), d->interface->connection());
|
||||
d->usersCache[path.path()] = account;
|
||||
}
|
||||
return account;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new \a accountType type user account whose name is \a userName,
|
||||
real name is \a fullName.
|
||||
|
||||
This method is synchronous and may take some time.
|
||||
|
||||
\param userName The name of the new user to be created.
|
||||
\param fullName First name and last name.
|
||||
\param accountType The account type.
|
||||
\return whether the user was created successfully.
|
||||
*/
|
||||
bool AccountsManager::createUser(const QString &userName, const QString &fullName,
|
||||
UserAccount::AccountType accountType)
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply =
|
||||
d->interface->CreateUser(userName, fullName, accountType);
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't create user %s: %s", userName.toUtf8().constData(),
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Deletes the user designated by \a uid.
|
||||
|
||||
This method is synchronous and may take some time.
|
||||
|
||||
\param uid The user identifier.
|
||||
\param removeFiles If true all files owned by the user will be removed.
|
||||
\return whether the user was deleted successfully.
|
||||
*/
|
||||
bool AccountsManager::deleteUser(qlonglong uid, bool removeFiles)
|
||||
{
|
||||
Q_D(AccountsManager);
|
||||
|
||||
QDBusPendingReply<> reply = d->interface->DeleteUser(uid, removeFiles);
|
||||
if (reply.isError()) {
|
||||
QDBusError error = reply.error();
|
||||
qWarning("Couldn't delete user %lld: %s", uid,
|
||||
error.errorString(error.type()).toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Deletes the specified \a account.
|
||||
|
||||
This method is synchronous and may take some time.
|
||||
|
||||
\param account The account to remove.
|
||||
\param removeFiles If true all files owned by the user will be removed.
|
||||
\return whether the user was deleted successfully.
|
||||
*/
|
||||
bool AccountsManager::deleteUser(UserAccount *account, bool removeFiles)
|
||||
{
|
||||
return deleteUser(account->userId(), removeFiles);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_accountsmanager.cpp"
|
||||
@ -0,0 +1,80 @@
|
||||
/****************************************************************************
|
||||
* This file is part of Qt AccountsService.
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QTACCOUNTSSERVICE_ACCOUNTSMANAGER_H
|
||||
#define QTACCOUNTSSERVICE_ACCOUNTSMANAGER_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
|
||||
#include "useraccount.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QDBusObjectPath)
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
class AccountsManagerPrivate;
|
||||
|
||||
class AccountsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AccountsManager(const QDBusConnection &bus = QDBusConnection::systemBus(),
|
||||
QObject *parent = nullptr);
|
||||
~AccountsManager();
|
||||
|
||||
Q_INVOKABLE void cacheUser(const QString &userName);
|
||||
Q_INVOKABLE void uncacheUser(const QString &userName);
|
||||
|
||||
Q_INVOKABLE void listCachedUsers();
|
||||
UserAccountList listCachedUsersSync();
|
||||
|
||||
Q_INVOKABLE QtAccountsService::UserAccount *cachedUser(const QString &userName) const;
|
||||
|
||||
Q_INVOKABLE QtAccountsService::UserAccount *findUserById(qlonglong uid);
|
||||
Q_INVOKABLE QtAccountsService::UserAccount *findUserByName(const QString &userName);
|
||||
|
||||
Q_INVOKABLE bool createUser(const QString &userName, const QString &fullName,
|
||||
UserAccount::AccountType accountType);
|
||||
|
||||
Q_INVOKABLE bool deleteUser(qlonglong uid, bool removeFiles);
|
||||
bool deleteUser(UserAccount *account, bool removeFiles);
|
||||
|
||||
Q_SIGNALS:
|
||||
void userAdded(QtAccountsService::UserAccount *account);
|
||||
void userDeleted(qlonglong uid);
|
||||
void userCached(const QString &userName);
|
||||
void userUncached(const QString &userName);
|
||||
void listCachedUsersFinished(const QtAccountsService::UserAccountList &userList);
|
||||
|
||||
protected:
|
||||
AccountsManagerPrivate *d_ptr;
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(AccountsManager)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_userAdded(const QDBusObjectPath &path))
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_userDeleted(const QDBusObjectPath &path))
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QTACCOUNTSSERVICE_ACCOUNTSMANAGER_H
|
||||
@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
* This file is part of Qt AccountsService.
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QTACCOUNTSSERVICE_ACCOUNTSMANAGER_P_H
|
||||
#define QTACCOUNTSSERVICE_ACCOUNTSMANAGER_P_H
|
||||
|
||||
#include "accounts_interface.h"
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt AccountsService 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.
|
||||
//
|
||||
|
||||
class OrgFreedesktopAccountsInterface;
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
class AccountsManager;
|
||||
|
||||
class AccountsManagerPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(AccountsManager)
|
||||
public:
|
||||
AccountsManagerPrivate(const QDBusConnection &bus);
|
||||
~AccountsManagerPrivate();
|
||||
|
||||
AccountsManager *q_ptr;
|
||||
OrgFreedesktopAccountsInterface *interface;
|
||||
QMap<QString, UserAccount *> usersCache;
|
||||
|
||||
void _q_userAdded(const QDBusObjectPath &path);
|
||||
void _q_userDeleted(const QDBusObjectPath &path);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QTACCOUNTSSERVICE_ACCOUNTSMANAGER_P_H
|
||||
@ -0,0 +1,817 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" >
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<interface name="org.freedesktop.Accounts.User">
|
||||
|
||||
<method name="SetUserName">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="name" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new username.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users username. Note that it is usually not allowed
|
||||
to have multiple users with the same username.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the username of any user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetRealName">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="name" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new name, typically in the form "Firstname Lastname".
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users real name.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own name</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the name of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetEmail">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="email" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new email address.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users email address.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Note that setting an email address in the AccountsService is
|
||||
not the same as configuring a mail client. Mail clients might
|
||||
default to email address that is configured here, though.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own email address</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the email address of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetLanguage">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="language" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new language, as a locale specification like "de_DE.UTF-8".
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users language.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
The expectation is that display managers will start the
|
||||
users session with this locale.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own language</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the language of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetXSession">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="user_set_x_session"/>
|
||||
<arg name="x_session" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new xsession to start (e.g. "gnome")
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users x session.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
The expectation is that display managers will log the user in to this
|
||||
specified session, if available.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own language</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the language of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetLocation">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="location" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new location as a freeform string.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users location.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own location</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the location of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetHomeDirectory">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="homedir" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new homedir as an absolute path.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users home directory.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Note that changing the users home directory moves all the content
|
||||
from the old location to the new one, and is potentially an
|
||||
expensive operation.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the home directory of a user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetShell">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="shell" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new user shell.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users shell.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Note that setting the shell to a non-allowed program may
|
||||
prevent the user from logging in.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the shell of a user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetIconFile">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="filename" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The absolute filename of a png file to use as the users icon.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users icon.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own icon</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the icon of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetLocked">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="locked" direction="in" type="b">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
Whether to lock or unlock the users account.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Locks or unlocks a users account.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Locking an account prevents the user from logging in.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To lock or unlock user accounts</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetAccountType">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="accountType" direction="in" type="i">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new account type, encoded as an integer:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>0</doc:term>
|
||||
<doc:definition>Standard user</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>1</doc:term>
|
||||
<doc:definition>Administrator</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Changes the users account type.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change an account type</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetPasswordMode">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="mode" direction="in" type="i">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The new password mode, encoded as an integer:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>0</doc:term>
|
||||
<doc:definition>Regular password</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>1</doc:term>
|
||||
<doc:definition>Password must be set at next login</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>2</doc:term>
|
||||
<doc:definition>No password</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Changes the users password mode.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Note that changing the password mode has the side-effect of
|
||||
unlocking the account.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change a users password mode</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetPassword">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="password" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The crypted password.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<arg name="hint" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The password hint.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets a new password for this user.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Note that setting a password has the side-effect of
|
||||
unlocking the account.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the password of a user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetPasswordHint">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="hint" direction="in" type="s">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
The password hint.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Sets the users password hint.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
|
||||
<doc:definition>To change his own language</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
|
||||
<doc:definition>To change the language of another user</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="SetAutomaticLogin">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="enabled" direction="in" type="b">
|
||||
<doc:doc>
|
||||
<doc:summary>
|
||||
Whether to enable automatic login for this user.
|
||||
</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Enables or disables automatic login for a user.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Note that usually only one user can have automatic login
|
||||
enabled, so turning it on for a user will disable it for
|
||||
the previously configured autologin user.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs one of the following PolicyKit authorizations:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>org.freedesktop.accounts.set-login-option</doc:term>
|
||||
<doc:definition>To change the login screen configuration</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<property name="Uid" type="t" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The uid of the user.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="UserName" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The username of the user.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="RealName" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users real name.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="AccountType" type="i" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users account type, encoded as an integer:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>0</doc:term>
|
||||
<doc:definition>Standard user</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>1</doc:term>
|
||||
<doc:definition>Administrator</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="HomeDirectory" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users home directory.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="Shell" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users shell.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="Email" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The email address.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="Language" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users language, as a locale specification like "de_DE.UTF-8".
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="XSession" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users x session.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="Location" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The users location.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="LoginFrequency" type="t" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
How often the user has logged in.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="LoginTime" type="x" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The last login time.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
<property name="LoginHistory" type="a(xxa{sv})" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The login history for this user.
|
||||
Each entry in the array represents a login session. The first two
|
||||
members are the login time and logout time, as timestamps (seconds since the epoch). If the session is still running, the logout time
|
||||
is 0.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
The a{sv} member is a dictionary containing additional information
|
||||
about the session. Possible members include 'type' (with values like ':0', 'tty0', 'pts/0' etc).
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
-->
|
||||
|
||||
<property name="IconFile" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The filename of a png file containing the users icon.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="Locked" type="b" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Whether the users account is locked.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="PasswordMode" type="i" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The password mode for the user account, encoded as an integer:
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>0</doc:term>
|
||||
<doc:definition>Regular password</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>1</doc:term>
|
||||
<doc:definition>Password must be set at next login</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>2</doc:term>
|
||||
<doc:definition>No password</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="PasswordHint" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The password hint for the user.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="AutomaticLogin" type="b" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Whether automatic login is enabled for the user.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="SystemAccount" type="b" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Whether this is a 'system' account, like 'root' or 'nobody'.
|
||||
System accounts should normally not appear in lists of
|
||||
users, and ListCachedUsers will not include such accounts.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<property name="LocalAccount" type="b" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Whether the user is a local account or not.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
<signal name="Changed">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Emitted when the user is changed.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</signal>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,228 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" >
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<interface name="org.freedesktop.Accounts">
|
||||
|
||||
<!-- ************************************************************ -->
|
||||
|
||||
<method name="ListCachedUsers">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="users" direction="out" type="ao">
|
||||
<doc:doc><doc:summary>Object paths of cached users</doc:summary></doc:doc>
|
||||
</arg>
|
||||
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Lists users which have logged into the system locally before.
|
||||
This is not meant to return an exhaustive list of all users.
|
||||
It is possible for <doc:ref type="method" to="Accounts.FindUserByName">FindUserByName()</doc:ref>
|
||||
to return a user that's not on the list.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="FindUserById">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="id" direction="in" type="x">
|
||||
<doc:doc><doc:summary>The uid to look up</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<arg name="user" direction="out" type="o">
|
||||
<doc:doc><doc:summary>Object path of user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Finds a user by uid.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if no user with the given uid exists</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="FindUserByName">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="name" direction="in" type="s">
|
||||
<doc:doc><doc:summary>The username to look up</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<arg name="user" direction="out" type="o">
|
||||
<doc:doc><doc:summary>Object path of user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Finds a user by its username.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if no user with the given username exists</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="CreateUser">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="name" direction="in" type="s">
|
||||
<doc:doc><doc:summary>The username for the new user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="fullname" direction="in" type="s">
|
||||
<doc:doc><doc:summary>The real name for the new user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<arg name="user" direction="out" type="o">
|
||||
<doc:doc><doc:summary>Object path of the new user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<arg name="accountType" direction="in" type="i">
|
||||
<doc:doc>
|
||||
<doc:summary>The account type, encoded as an integer</doc:summary>
|
||||
</doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Creates a new user account.
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
The accountType argument can take the following values:
|
||||
</doc:para>
|
||||
<doc:list>
|
||||
<doc:item>
|
||||
<doc:term>0</doc:term>
|
||||
<doc:definition>Standard user</doc:definition>
|
||||
</doc:item>
|
||||
<doc:item>
|
||||
<doc:term>1</doc:term>
|
||||
<doc:definition>Administrator</doc:definition>
|
||||
</doc:item>
|
||||
</doc:list>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization.
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="CacheUser">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="name" direction="in" type="s">
|
||||
<doc:doc><doc:summary>The username for the user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<arg name="user" direction="out" type="o">
|
||||
<doc:doc><doc:summary>Object path of user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Caches a user account, so that it shows up in ListCachedUsers() output.
|
||||
The user name may be a remote user, but the system must be able to lookup
|
||||
the user name and resolve the user information.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization.
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.UserDoesNotExist">if the user name cannot be resolved</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="UncacheUser">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="name" direction="in" type="s">
|
||||
<doc:doc><doc:summary>The username for the user</doc:summary></doc:doc>
|
||||
</arg>
|
||||
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Releases all metadata about a user account, including icon, language and session. If the user account is
|
||||
from a remote server and the user has never logged in before, then that account will no longer show up
|
||||
in ListCachedUsers() output.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization.
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.UserDoesNotExist">if the user name cannot be resolved</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<method name="DeleteUser">
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="id" direction="in" type="x">
|
||||
<doc:doc><doc:summary>The uid to delete</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<arg name="removeFiles" direction="in" type="b">
|
||||
<doc:doc><doc:summary>Whether to remove the users files</doc:summary></doc:doc>
|
||||
</arg>
|
||||
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Deletes a user account.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
<doc:permission>
|
||||
The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization.
|
||||
</doc:permission>
|
||||
<doc:errors>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
||||
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
|
||||
</doc:errors>
|
||||
</doc:doc>
|
||||
</method>
|
||||
|
||||
<signal name="UserAdded">
|
||||
<arg name="user" type="o">
|
||||
<doc:doc><doc:summary>Object path of the user that was added.</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Emitted when a user is added.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</signal>
|
||||
|
||||
<signal name="UserDeleted">
|
||||
<arg name="user" type="o">
|
||||
<doc:doc><doc:summary>Object path of the user that was deleted.</doc:summary></doc:doc>
|
||||
</arg>
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
Emitted when a user is deleted.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</signal>
|
||||
|
||||
<property name="DaemonVersion" type="s" access="read">
|
||||
<doc:doc>
|
||||
<doc:description>
|
||||
<doc:para>
|
||||
The version of the running daemon.
|
||||
</doc:para>
|
||||
</doc:description>
|
||||
</doc:doc>
|
||||
</property>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,2 @@
|
||||
module Cutefish.Accounts
|
||||
plugin cutefishaccounts_qmlplugins
|
||||
@ -0,0 +1,21 @@
|
||||
#include <QQmlExtensionPlugin>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "accountsmanager.h"
|
||||
#include "useraccount.h"
|
||||
#include "usersmodel.h"
|
||||
|
||||
class QmlPlugins : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
|
||||
|
||||
public:
|
||||
void registerTypes(const char * uri) override {
|
||||
qmlRegisterType<QtAccountsService::AccountsManager>(uri, 1, 0, "AccountsManager");
|
||||
qmlRegisterType<QtAccountsService::UserAccount>(uri, 1, 0, "UserAccount");
|
||||
qmlRegisterType<QtAccountsService::UsersModel>(uri, 1, 0, "UsersModel");
|
||||
}
|
||||
};
|
||||
|
||||
#include "qmlplugins.moc"
|
||||
@ -0,0 +1,680 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#include "useraccount.h"
|
||||
#include "useraccount_p.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
/*
|
||||
* UserAccountPrivate
|
||||
*/
|
||||
|
||||
UserAccountPrivate::UserAccountPrivate(UserAccount *q)
|
||||
: bus(QDBusConnection::systemBus())
|
||||
, user(nullptr)
|
||||
, accountType(UserAccount::StandardAccountType)
|
||||
, locked(false)
|
||||
, automaticLogin(false)
|
||||
, passwordMode(UserAccount::NonePasswordMode)
|
||||
, q_ptr(q)
|
||||
{
|
||||
}
|
||||
|
||||
void UserAccountPrivate::initialize(const QDBusConnection &connection, const QString &objectPath)
|
||||
{
|
||||
Q_Q(UserAccount);
|
||||
|
||||
bus = connection;
|
||||
|
||||
if (user) {
|
||||
q->disconnect(user, &OrgFreedesktopAccountsUserInterface::Changed, q,
|
||||
&UserAccount::handleAccountChanged);
|
||||
user = nullptr;
|
||||
}
|
||||
|
||||
user = new OrgFreedesktopAccountsUserInterface(QStringLiteral("org.freedesktop.Accounts"),
|
||||
objectPath, bus, q);
|
||||
q->connect(user, &OrgFreedesktopAccountsUserInterface::Changed, q,
|
||||
&UserAccount::handleAccountChanged);
|
||||
|
||||
emitSignals();
|
||||
}
|
||||
|
||||
void UserAccountPrivate::emitSignals()
|
||||
{
|
||||
Q_Q(UserAccount);
|
||||
|
||||
Q_EMIT q->userIdChanged();
|
||||
Q_EMIT q->groupIdChanged();
|
||||
Q_EMIT q->accountTypeChanged();
|
||||
Q_EMIT q->lockedChanged();
|
||||
Q_EMIT q->automaticLoginChanged();
|
||||
Q_EMIT q->passwordModeChanged();
|
||||
Q_EMIT q->userNameChanged();
|
||||
Q_EMIT q->realNameChanged();
|
||||
Q_EMIT q->displayNameChanged();
|
||||
Q_EMIT q->homeDirectoryChanged();
|
||||
Q_EMIT q->shellChanged();
|
||||
Q_EMIT q->iconFileNameChanged();
|
||||
Q_EMIT q->emailChanged();
|
||||
Q_EMIT q->languageChanged();
|
||||
Q_EMIT q->locationChanged();
|
||||
Q_EMIT q->xsessionChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class UserAcccount
|
||||
\brief The UserAccount class describes user accounts.
|
||||
|
||||
This class describes user accounts retrieved with AccountsManager.
|
||||
|
||||
\author Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
|
||||
\sa AccountsManager
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a UserAccount object for the currently logged in user.
|
||||
*/
|
||||
UserAccount::UserAccount(const QDBusConnection &bus, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d_ptr(new UserAccountPrivate(this))
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
QString objectPath =
|
||||
QStringLiteral("/org/freedesktop/Accounts/User") + QString::number(getuid());
|
||||
d->initialize(bus, objectPath);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
Constructs a UserAccount object from a specific objectPath in the form of
|
||||
/org/freedesktop/Accounts/UserUID where UID is user's uid.
|
||||
|
||||
\param objectPath Accounts Service object path for the user account.
|
||||
*/
|
||||
UserAccount::UserAccount(const QString &objectPath, const QDBusConnection &bus, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d_ptr(new UserAccountPrivate(this))
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
d->initialize(bus, objectPath);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the user identifier.
|
||||
*/
|
||||
qlonglong UserAccount::userId() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->uid();
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the user identifier to \c uid.
|
||||
The object will hold information for the requested user identifier.
|
||||
*/
|
||||
void UserAccount::setUserId(qlonglong uid)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
QString objectPath = QStringLiteral("/org/freedesktop/Accounts/User") + QString::number(uid);
|
||||
d->initialize(d->bus, objectPath);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns group identifier.
|
||||
*/
|
||||
qlonglong UserAccount::groupId() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
|
||||
size_t bufSize = 0;
|
||||
long sizeMax = ::sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
if (sizeMax <= 0)
|
||||
bufSize = 16384;
|
||||
else
|
||||
bufSize = static_cast<size_t>(sizeMax);
|
||||
char *buf = static_cast<char *>(::malloc(bufSize));
|
||||
if (!buf)
|
||||
qFatal("Cannot allocate %lu bytes: %s", static_cast<long>(bufSize), strerror(errno));
|
||||
|
||||
struct passwd pwd;
|
||||
struct passwd *result;
|
||||
int s = ::getpwuid_r(d->user->uid(), &pwd, buf, bufSize, &result);
|
||||
if (!result) {
|
||||
if (s == 0)
|
||||
qCritical("User with uid %lld not found", d->user->uid());
|
||||
else
|
||||
qCritical("Failed to get group information: %s", strerror(s));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pwd.pw_gid;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the account type.
|
||||
*/
|
||||
UserAccount::AccountType UserAccount::accountType() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return static_cast<UserAccount::AccountType>(d->user->accountType());
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the account type to \a type.
|
||||
|
||||
\param type Account type.
|
||||
*/
|
||||
void UserAccount::setAccountType(AccountType type)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (type == accountType())
|
||||
return;
|
||||
|
||||
d->accountType = type;
|
||||
d->user->SetAccountType(static_cast<int>(type));
|
||||
Q_EMIT accountTypeChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether this account is locked or not.
|
||||
*/
|
||||
bool UserAccount::isLocked() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->locked();
|
||||
}
|
||||
|
||||
/*!
|
||||
Locks or unlocks the user account.
|
||||
Locking an account prevents the user from logging in.
|
||||
|
||||
\param locked Whether to lock or unlock the user account.
|
||||
*/
|
||||
void UserAccount::setLocked(bool locked)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (isLocked() == locked)
|
||||
return;
|
||||
|
||||
d->locked = locked;
|
||||
d->user->SetLocked(locked);
|
||||
Q_EMIT lockedChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the user account will automatically log in when the
|
||||
system starts up.
|
||||
*/
|
||||
bool UserAccount::automaticLogin() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->automaticLogin();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the user account will automatically log in when
|
||||
the system starts up.
|
||||
|
||||
\param automaticLogin Whether automatic login is enabled for the user.
|
||||
*/
|
||||
void UserAccount::setAutomaticLogin(bool automaticLogin)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->automaticLogin() == automaticLogin)
|
||||
return;
|
||||
|
||||
d->automaticLogin = automaticLogin;
|
||||
d->user->SetAutomaticLogin(automaticLogin);
|
||||
Q_EMIT automaticLoginChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns how often the user has logged in.
|
||||
*/
|
||||
qlonglong UserAccount::loginFrequency() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->loginFrequency();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the last login time.
|
||||
*/
|
||||
qlonglong UserAccount::loginTime() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->loginTime();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the password mode for the user account.
|
||||
*/
|
||||
UserAccount::PasswordMode UserAccount::passwordMode() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return static_cast<UserAccount::PasswordMode>(d->user->passwordMode());
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the password mode for the user account.
|
||||
|
||||
\param mode Password mode.
|
||||
*/
|
||||
void UserAccount::setPasswordMode(UserAccount::PasswordMode mode)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (passwordMode() == mode)
|
||||
return;
|
||||
|
||||
d->passwordMode = mode;
|
||||
d->user->SetPasswordMode(static_cast<int>(mode));
|
||||
Q_EMIT passwordModeChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the password hint for the user.
|
||||
*/
|
||||
QString UserAccount::passwordHint() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->passwordHint();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the user is a local account or not.
|
||||
*/
|
||||
bool UserAccount::isLocalAccount() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->localAccount();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the user is a system account or not.
|
||||
*/
|
||||
bool UserAccount::isSystemAccount() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->systemAccount();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the user name.
|
||||
*/
|
||||
QString UserAccount::userName() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->userName();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the user name to \a userName.
|
||||
|
||||
\param userName The new user name.
|
||||
*/
|
||||
void UserAccount::setUserName(const QString &userName)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->userName() == userName)
|
||||
return;
|
||||
|
||||
d->userName = userName;
|
||||
d->user->SetUserName(userName);
|
||||
Q_EMIT userNameChanged();
|
||||
Q_EMIT displayNameChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user's real name.
|
||||
*/
|
||||
QString UserAccount::realName() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->realName();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the user's real name to \a realName.
|
||||
|
||||
\param realName Real name.
|
||||
*/
|
||||
void UserAccount::setRealName(const QString &realName)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->realName() == realName)
|
||||
return;
|
||||
|
||||
d->realName = realName;
|
||||
d->user->SetRealName(realName);
|
||||
Q_EMIT realNameChanged();
|
||||
Q_EMIT displayNameChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user's real name if not empty, otherwise the user name.
|
||||
*/
|
||||
QString UserAccount::displayName() const
|
||||
{
|
||||
if (realName().isEmpty())
|
||||
return userName();
|
||||
return realName();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the home directory absolute path.
|
||||
*/
|
||||
QString UserAccount::homeDirectory() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->homeDirectory();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the home directory to \a homeDirectory.
|
||||
|
||||
\param homeDirectory Home directory.
|
||||
*/
|
||||
void UserAccount::setHomeDirectory(const QString &homeDirectory)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->homeDirectory() == homeDirectory)
|
||||
return;
|
||||
|
||||
d->user->SetHomeDirectory(homeDirectory);
|
||||
Q_EMIT homeDirectoryChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the login shell absolute path.
|
||||
*/
|
||||
QString UserAccount::shell() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->shell();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the login shell to \a shell.
|
||||
|
||||
\param shell Login shell absolute path.
|
||||
*/
|
||||
void UserAccount::setShell(const QString &shell)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->shell() == shell)
|
||||
return;
|
||||
|
||||
d->shell = shell;
|
||||
d->user->SetShell(shell);
|
||||
Q_EMIT shellChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user's picture absoulte path.
|
||||
*/
|
||||
QString UserAccount::iconFileName() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return QFile::exists(d->user->iconFile()) ? d->user->iconFile() : QString();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets users' picture absolute path to \a fileName.
|
||||
|
||||
\param fileName Picture absolute path.
|
||||
*/
|
||||
void UserAccount::setIconFileName(const QString &fileName)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (iconFileName() == fileName)
|
||||
return;
|
||||
|
||||
d->iconFileName = fileName;
|
||||
d->user->SetIconFile(fileName);
|
||||
Q_EMIT iconFileNameChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user's email address.
|
||||
*/
|
||||
QString UserAccount::email() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->email();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets user's email address to \a email.
|
||||
|
||||
\param email Email address.
|
||||
*/
|
||||
void UserAccount::setEmail(const QString &email)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->email() == email)
|
||||
return;
|
||||
|
||||
d->email = email;
|
||||
d->user->SetEmail(email);
|
||||
Q_EMIT emailChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user language.
|
||||
*/
|
||||
QString UserAccount::language() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->language();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets user language to \a language.
|
||||
|
||||
\param language Language.
|
||||
*/
|
||||
void UserAccount::setLanguage(const QString &language)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->language() == language)
|
||||
return;
|
||||
|
||||
d->language = language;
|
||||
d->user->SetLanguage(language);
|
||||
Q_EMIT languageChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns user location.
|
||||
*/
|
||||
QString UserAccount::location() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->location();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets user \a location.
|
||||
|
||||
\param location Location.
|
||||
*/
|
||||
void UserAccount::setLocation(const QString &location)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (this->location() == location)
|
||||
return;
|
||||
|
||||
d->location = location;
|
||||
d->user->SetLocation(location);
|
||||
Q_EMIT locationChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the X11 session for the user account.
|
||||
*/
|
||||
QString UserAccount::xsession() const
|
||||
{
|
||||
Q_D(const UserAccount);
|
||||
return d->user->xSession();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the X11 session for the user account.
|
||||
|
||||
\param session X11 session name.
|
||||
*/
|
||||
void UserAccount::setXSession(const QString &session)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (xsession() == session)
|
||||
return;
|
||||
|
||||
d->xsession = session;
|
||||
d->user->SetXSession(session);
|
||||
Q_EMIT xsessionChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the password for the user account.
|
||||
|
||||
\param password.
|
||||
\param hint passwordHint.
|
||||
*/
|
||||
void UserAccount::setPassword(const QString &password, const QString &hint)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
d->user->SetPassword(password, hint);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the password hint for the user account.
|
||||
|
||||
\param hint Password hint.
|
||||
*/
|
||||
void UserAccount::setPasswordHint(const QString &hint)
|
||||
{
|
||||
Q_D(UserAccount);
|
||||
d->user->SetPasswordHint(hint);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void UserAccount::handleAccountChanged()
|
||||
{
|
||||
// Catch changes outside of this API
|
||||
|
||||
Q_D(UserAccount);
|
||||
|
||||
if (d->accountType != accountType()) {
|
||||
d->accountType = accountType();
|
||||
Q_EMIT accountTypeChanged();
|
||||
}
|
||||
|
||||
if (d->locked != isLocked()) {
|
||||
d->locked = isLocked();
|
||||
Q_EMIT lockedChanged();
|
||||
}
|
||||
|
||||
if (d->automaticLogin != automaticLogin()) {
|
||||
d->automaticLogin = automaticLogin();
|
||||
Q_EMIT automaticLoginChanged();
|
||||
}
|
||||
|
||||
if (d->passwordMode != passwordMode()) {
|
||||
d->passwordMode = passwordMode();
|
||||
Q_EMIT passwordModeChanged();
|
||||
}
|
||||
|
||||
if (d->userName != userName()) {
|
||||
d->userName = userName();
|
||||
Q_EMIT userNameChanged();
|
||||
Q_EMIT displayNameChanged();
|
||||
}
|
||||
|
||||
if (d->realName != realName()) {
|
||||
d->realName = realName();
|
||||
Q_EMIT realNameChanged();
|
||||
Q_EMIT displayNameChanged();
|
||||
}
|
||||
|
||||
if (d->homeDirectory != homeDirectory()) {
|
||||
d->homeDirectory = homeDirectory();
|
||||
Q_EMIT homeDirectoryChanged();
|
||||
}
|
||||
|
||||
if (d->shell != shell()) {
|
||||
d->shell = shell();
|
||||
Q_EMIT shellChanged();
|
||||
}
|
||||
|
||||
if (d->iconFileName != iconFileName()) {
|
||||
d->iconFileName = iconFileName();
|
||||
Q_EMIT iconFileNameChanged();
|
||||
}
|
||||
|
||||
if (d->email != email()) {
|
||||
d->email = email();
|
||||
Q_EMIT emailChanged();
|
||||
}
|
||||
|
||||
if (d->language != language()) {
|
||||
d->language = language();
|
||||
Q_EMIT languageChanged();
|
||||
}
|
||||
|
||||
if (d->location != location()) {
|
||||
d->location = location();
|
||||
Q_EMIT locationChanged();
|
||||
}
|
||||
|
||||
if (d->xsession != xsession()) {
|
||||
d->xsession = xsession();
|
||||
Q_EMIT xsessionChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_useraccount.cpp"
|
||||
@ -0,0 +1,171 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QTACCOUNTSSERVICE_USERACCOUNT_H
|
||||
#define QTACCOUNTSSERVICE_USERACCOUNT_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
class AccountsManager;
|
||||
class AccountsManagerPrivate;
|
||||
class UserAccountPrivate;
|
||||
|
||||
class UserAccount : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qlonglong userId READ userId WRITE setUserId NOTIFY userIdChanged)
|
||||
Q_PROPERTY(qlonglong groupId READ groupId NOTIFY groupIdChanged)
|
||||
Q_PROPERTY(
|
||||
AccountType accountType READ accountType WRITE setAccountType NOTIFY accountTypeChanged)
|
||||
Q_PROPERTY(bool locked READ isLocked WRITE setLocked NOTIFY lockedChanged)
|
||||
Q_PROPERTY(bool automaticLogin READ automaticLogin WRITE setAutomaticLogin NOTIFY
|
||||
automaticLoginChanged)
|
||||
Q_PROPERTY(qlonglong loginFrequency READ loginFrequency CONSTANT)
|
||||
Q_PROPERTY(qlonglong loginTime READ loginTime CONSTANT)
|
||||
Q_PROPERTY(PasswordMode passwordMode READ passwordMode WRITE setPasswordMode NOTIFY
|
||||
passwordModeChanged)
|
||||
Q_PROPERTY(QString passwordHint READ passwordHint CONSTANT)
|
||||
Q_PROPERTY(bool localAccount READ isLocalAccount CONSTANT)
|
||||
Q_PROPERTY(bool systemAccount READ isSystemAccount CONSTANT)
|
||||
Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
|
||||
Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged)
|
||||
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(
|
||||
QString homeDirectory READ homeDirectory WRITE setHomeDirectory NOTIFY homeDirectoryChanged)
|
||||
Q_PROPERTY(QString shell READ shell WRITE setShell NOTIFY shellChanged)
|
||||
Q_PROPERTY(
|
||||
QString iconFileName READ iconFileName WRITE setIconFileName NOTIFY iconFileNameChanged)
|
||||
Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
|
||||
Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged)
|
||||
Q_PROPERTY(QString location READ location WRITE setLocation NOTIFY locationChanged)
|
||||
Q_PROPERTY(QString xsession READ xsession WRITE setXSession NOTIFY xsessionChanged)
|
||||
Q_DECLARE_PRIVATE(UserAccount)
|
||||
public:
|
||||
enum AccountType { StandardAccountType = 0, AdministratorAccountType };
|
||||
Q_ENUM(AccountType)
|
||||
|
||||
enum PasswordMode { RegularPasswordMode = 0, SetAtLoginPasswordMode, NonePasswordMode };
|
||||
Q_ENUM(PasswordMode)
|
||||
|
||||
UserAccount(const QDBusConnection &bus = QDBusConnection::systemBus(),
|
||||
QObject *parent = nullptr);
|
||||
|
||||
qlonglong userId() const;
|
||||
void setUserId(qlonglong uid);
|
||||
|
||||
qlonglong groupId() const;
|
||||
|
||||
AccountType accountType() const;
|
||||
void setAccountType(AccountType type);
|
||||
|
||||
bool isLocked() const;
|
||||
void setLocked(bool locked);
|
||||
|
||||
bool automaticLogin() const;
|
||||
void setAutomaticLogin(bool automaticLogin);
|
||||
|
||||
qlonglong loginFrequency() const;
|
||||
|
||||
qlonglong loginTime() const;
|
||||
|
||||
PasswordMode passwordMode() const;
|
||||
void setPasswordMode(PasswordMode mode);
|
||||
|
||||
QString passwordHint() const;
|
||||
|
||||
bool isLocalAccount() const;
|
||||
|
||||
bool isSystemAccount() const;
|
||||
|
||||
QString userName() const;
|
||||
void setUserName(const QString &userName);
|
||||
|
||||
QString realName() const;
|
||||
void setRealName(const QString &realName);
|
||||
|
||||
QString displayName() const;
|
||||
|
||||
QString homeDirectory() const;
|
||||
void setHomeDirectory(const QString &homeDirectory);
|
||||
|
||||
QString shell() const;
|
||||
void setShell(const QString &shell);
|
||||
|
||||
QString iconFileName() const;
|
||||
void setIconFileName(const QString &fileName);
|
||||
|
||||
QString email() const;
|
||||
void setEmail(const QString &email);
|
||||
|
||||
QString language() const;
|
||||
void setLanguage(const QString &language);
|
||||
|
||||
QString location() const;
|
||||
void setLocation(const QString &location);
|
||||
|
||||
QString xsession() const;
|
||||
void setXSession(const QString &session);
|
||||
|
||||
Q_INVOKABLE void setPassword(const QString &password, const QString &hint = QString());
|
||||
Q_INVOKABLE void setPasswordHint(const QString &hint);
|
||||
|
||||
Q_SIGNALS:
|
||||
void accountChanged();
|
||||
void userIdChanged();
|
||||
void groupIdChanged();
|
||||
void accountTypeChanged();
|
||||
void lockedChanged();
|
||||
void automaticLoginChanged();
|
||||
void passwordModeChanged();
|
||||
void userNameChanged();
|
||||
void realNameChanged();
|
||||
void displayNameChanged();
|
||||
void homeDirectoryChanged();
|
||||
void shellChanged();
|
||||
void iconFileNameChanged();
|
||||
void emailChanged();
|
||||
void languageChanged();
|
||||
void locationChanged();
|
||||
void xsessionChanged();
|
||||
|
||||
private:
|
||||
friend class AccountsManager;
|
||||
friend class AccountsManagerPrivate;
|
||||
|
||||
UserAccountPrivate *const d_ptr;
|
||||
|
||||
UserAccount(const QString &objectPath,
|
||||
const QDBusConnection &bus = QDBusConnection::systemBus(),
|
||||
QObject *parent = nullptr);
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleAccountChanged();
|
||||
};
|
||||
|
||||
typedef QList<UserAccount *> UserAccountList;
|
||||
}
|
||||
|
||||
#endif // QTACCOUNTSSERVICE_USERACCOUNT_H
|
||||
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QTACCOUNTSSERVICE_USERACCOUNT_P_H
|
||||
#define QTACCOUNTSSERVICE_USERACCOUNT_P_H
|
||||
|
||||
#include "useraccount.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt AccountsService 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.
|
||||
//
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
class UserAccountPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(UserAccount)
|
||||
Q_DISABLE_COPY(UserAccountPrivate)
|
||||
public:
|
||||
explicit UserAccountPrivate(UserAccount *q);
|
||||
|
||||
void initialize(const QDBusConnection &connection, const QString &objectPath);
|
||||
void emitSignals();
|
||||
|
||||
QDBusConnection bus;
|
||||
OrgFreedesktopAccountsUserInterface *user;
|
||||
|
||||
UserAccount::AccountType accountType;
|
||||
bool locked;
|
||||
bool automaticLogin;
|
||||
UserAccount::PasswordMode passwordMode;
|
||||
QString userName;
|
||||
QString realName;
|
||||
QString homeDirectory;
|
||||
QString shell;
|
||||
QString iconFileName;
|
||||
QString email;
|
||||
QString language;
|
||||
QString location;
|
||||
QString xsession;
|
||||
|
||||
protected:
|
||||
UserAccount *q_ptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QTACCOUNTSSERVICE_USERACCOUNT_P_H
|
||||
@ -0,0 +1,237 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#include <QtGui/QPixmap>
|
||||
|
||||
#include "usersmodel.h"
|
||||
#include "usersmodel_p.h"
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
/*
|
||||
* UsersModelPrivate
|
||||
*/
|
||||
|
||||
UsersModelPrivate::UsersModelPrivate(UsersModel *q)
|
||||
: manager(new AccountsManager())
|
||||
, q_ptr(q)
|
||||
{
|
||||
}
|
||||
|
||||
UsersModelPrivate::~UsersModelPrivate()
|
||||
{
|
||||
delete manager;
|
||||
}
|
||||
|
||||
void UsersModelPrivate::_q_userAdded(UserAccount *account)
|
||||
{
|
||||
Q_Q(UsersModel);
|
||||
|
||||
q->connect(account, &UserAccount::accountChanged, q, [account, q, this]() {
|
||||
auto index = q->index(list.indexOf(account));
|
||||
if (index.isValid())
|
||||
Q_EMIT q->dataChanged(index, index);
|
||||
});
|
||||
|
||||
q->beginInsertRows(QModelIndex(), list.size(), list.size());
|
||||
list.append(account);
|
||||
q->endInsertRows();
|
||||
}
|
||||
|
||||
void UsersModelPrivate::_q_userDeleted(qlonglong uid)
|
||||
{
|
||||
Q_Q(UsersModel);
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
UserAccount *curAccount = list.at(i);
|
||||
|
||||
if (curAccount->userId() == uid) {
|
||||
q->beginRemoveRows(QModelIndex(), i, i);
|
||||
list.removeOne(curAccount);
|
||||
q->endRemoveRows();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* UsersModel
|
||||
*/
|
||||
|
||||
UsersModel::UsersModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, d_ptr(new UsersModelPrivate(this))
|
||||
{
|
||||
Q_D(UsersModel);
|
||||
|
||||
connect(d->manager, SIGNAL(userAdded(UserAccount *)), // clazy:exclude=old-style-connect
|
||||
this, SLOT(_q_userAdded(UserAccount *)));
|
||||
connect(d->manager, SIGNAL(userDeleted(qlonglong)), // clazy:exclude=old-style-connect
|
||||
this, SLOT(_q_userDeleted(qlonglong)));
|
||||
|
||||
connect(d->manager, &AccountsManager::listCachedUsersFinished,
|
||||
this, [d](const UserAccountList &list) {
|
||||
for (auto account : list)
|
||||
d->_q_userAdded(account);
|
||||
});
|
||||
d->manager->listCachedUsers();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> UsersModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[UserAccountRole] = "userAccount";
|
||||
roles[UserIdRole] = "userId";
|
||||
roles[AccountTypeRole] = "accountType";
|
||||
roles[LockedRole] = "locked";
|
||||
roles[AutomaticLoginRole] = "automaticLogin";
|
||||
roles[LoginFrequencyRole] = "loginFrequency";
|
||||
roles[LoginTimeRole] = "loginTime";
|
||||
roles[PasswordModeRole] = "passwordMode";
|
||||
roles[PasswordHintRole] = "passwordHint";
|
||||
roles[LocalAccount] = "localAccount";
|
||||
roles[SystemAccount] = "systemAccount";
|
||||
roles[UserNameRole] = "userName";
|
||||
roles[RealNameRole] = "realName";
|
||||
roles[DisplayNameRole] = "displayNameRole";
|
||||
roles[HomeDirectoryRole] = "homeDirectory";
|
||||
roles[ShellRole] = "shell";
|
||||
roles[IconFileNameRole] = "iconFileName";
|
||||
roles[LanguageRole] = "language";
|
||||
roles[EmailRole] = "email";
|
||||
roles[LocationRole] = "location";
|
||||
roles[XSessionRole] = "xsession";
|
||||
return roles;
|
||||
}
|
||||
|
||||
int UsersModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_D(const UsersModel);
|
||||
|
||||
if (parent == QModelIndex())
|
||||
return d->list.size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QVariant UsersModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
UserAccount *user = userAccount(index);
|
||||
if (!user)
|
||||
return QVariant();
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
case DisplayNameRole:
|
||||
return user->displayName();
|
||||
case Qt::DecorationRole:
|
||||
return QPixmap(user->iconFileName());
|
||||
case UserAccountRole:
|
||||
return QVariant::fromValue(user);
|
||||
case UserIdRole:
|
||||
return user->userId();
|
||||
case AccountTypeRole:
|
||||
return user->accountType();
|
||||
case LockedRole:
|
||||
return user->isLocked();
|
||||
case AutomaticLoginRole:
|
||||
return user->automaticLogin();
|
||||
case LoginFrequencyRole:
|
||||
return user->loginFrequency();
|
||||
case LoginTimeRole:
|
||||
return user->loginTime();
|
||||
case PasswordModeRole:
|
||||
return user->passwordMode();
|
||||
case PasswordHintRole:
|
||||
return user->passwordHint();
|
||||
case LocalAccount:
|
||||
return user->isLocalAccount();
|
||||
case SystemAccount:
|
||||
return user->isSystemAccount();
|
||||
case UserNameRole:
|
||||
return user->userName();
|
||||
case RealNameRole:
|
||||
return user->realName();
|
||||
case HomeDirectoryRole:
|
||||
return user->homeDirectory();
|
||||
case ShellRole:
|
||||
return user->shell();
|
||||
case IconFileNameRole:
|
||||
return user->iconFileName();
|
||||
case EmailRole:
|
||||
return user->email();
|
||||
case LanguageRole:
|
||||
return user->language();
|
||||
case LocationRole:
|
||||
return user->location();
|
||||
case XSessionRole:
|
||||
return user->xsession();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool UsersModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
UserAccount *user = userAccount(index);
|
||||
if (!user)
|
||||
return false;
|
||||
|
||||
switch (role) {
|
||||
case UsersModel::UserNameRole:
|
||||
user->setUserName(value.toString());
|
||||
break;
|
||||
case UsersModel::RealNameRole:
|
||||
user->setRealName(value.toString());
|
||||
break;
|
||||
case UsersModel::IconFileNameRole:
|
||||
user->setIconFileName(value.toString());
|
||||
break;
|
||||
case UsersModel::AccountTypeRole:
|
||||
user->setAccountType((UserAccount::AccountType)value.toInt());
|
||||
break;
|
||||
case UsersModel::LanguageRole:
|
||||
user->setLanguage(value.toString());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
UserAccount *UsersModel::userAccount(const QModelIndex &index) const
|
||||
{
|
||||
Q_D(const UsersModel);
|
||||
|
||||
if (!index.isValid())
|
||||
return nullptr;
|
||||
if (index.row() >= d->list.size())
|
||||
return nullptr;
|
||||
|
||||
return d->list[index.row()];
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_usersmodel.cpp"
|
||||
@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QTACCOUNTSSERVICE_USERSMODEL_H
|
||||
#define QTACCOUNTSSERVICE_USERSMODEL_H
|
||||
|
||||
#include <QtCore/QAbstractListModel>
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
class UserAccount;
|
||||
class UsersModelPrivate;
|
||||
|
||||
class UsersModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(UsersModel)
|
||||
public:
|
||||
enum Roles {
|
||||
UserAccountRole = Qt::UserRole + 1,
|
||||
UserIdRole,
|
||||
AccountTypeRole,
|
||||
LockedRole,
|
||||
AutomaticLoginRole,
|
||||
LoginFrequencyRole,
|
||||
LoginTimeRole,
|
||||
PasswordModeRole,
|
||||
PasswordHintRole,
|
||||
LocalAccount,
|
||||
SystemAccount,
|
||||
UserNameRole,
|
||||
RealNameRole,
|
||||
DisplayNameRole,
|
||||
HomeDirectoryRole,
|
||||
ShellRole,
|
||||
IconFileNameRole,
|
||||
EmailRole,
|
||||
LanguageRole,
|
||||
LocationRole,
|
||||
XSessionRole
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
explicit UsersModel(QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
|
||||
UserAccount *userAccount(const QModelIndex &index) const;
|
||||
|
||||
private:
|
||||
UsersModelPrivate *const d_ptr;
|
||||
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_userAdded(UserAccount *account))
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_userDeleted(qlonglong uid))
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QTACCOUNTSSERVICE_USERSMODEL_H
|
||||
@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QTACCOUNTSSERVICE_USERSMODEL_P_H
|
||||
#define QTACCOUNTSSERVICE_USERSMODEL_P_H
|
||||
|
||||
#include "accountsmanager.h"
|
||||
#include "useraccount.h"
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt AccountsService 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.
|
||||
//
|
||||
|
||||
namespace QtAccountsService {
|
||||
|
||||
class UsersModel;
|
||||
|
||||
class UsersModelPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(UsersModel)
|
||||
public:
|
||||
UsersModelPrivate(UsersModel *q);
|
||||
~UsersModelPrivate();
|
||||
|
||||
void populate();
|
||||
|
||||
AccountsManager *manager;
|
||||
UserAccountList list;
|
||||
|
||||
public Q_SLOTS:
|
||||
void _q_userAdded(UserAccount *account);
|
||||
void _q_userDeleted(qlonglong uid);
|
||||
|
||||
protected:
|
||||
UsersModel *q_ptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // QTACCOUNTSSERVICE_USERSMODEL_P_H
|
||||
@ -0,0 +1,35 @@
|
||||
set(NETWORKMGR_SRCS
|
||||
mpris.cpp
|
||||
mpris.h
|
||||
mpriscontroller_p.h
|
||||
mpriscontroller.cpp
|
||||
mpriscontroller.h
|
||||
mprismanager.cpp
|
||||
mprismanager.h
|
||||
mprisplayer.cpp
|
||||
mprisplayer.h
|
||||
mprisplayeradaptor.cpp
|
||||
mprisplayerinterface.cpp
|
||||
mprisqt.h
|
||||
mprisrootadaptor.cpp
|
||||
mprisrootinterface.cpp
|
||||
qmlplugins.cpp
|
||||
|
||||
qtdbusextended/dbusextended.h
|
||||
qtdbusextended/dbusextendedabstractinterface.cpp
|
||||
qtdbusextended/dbusextendedabstractinterface.h
|
||||
qtdbusextended/dbusextendedpendingcallwatcher_p.h
|
||||
qtdbusextended/dbusextendedpendingcallwatcher.cpp
|
||||
)
|
||||
|
||||
add_library(cutefishmpris_qmlplugins SHARED ${NETWORKMGR_SRCS})
|
||||
|
||||
target_link_libraries (cutefishmpris_qmlplugins
|
||||
Qt5::Core
|
||||
Qt5::Quick
|
||||
Qt5::Gui
|
||||
Qt5::DBus
|
||||
)
|
||||
|
||||
install(TARGETS cutefishmpris_qmlplugins DESTINATION ${INSTALL_QMLDIR}/Cutefish/Mpris)
|
||||
install(FILES qmldir DESTINATION ${INSTALL_QMLDIR}/Cutefish/Mpris)
|
||||
@ -0,0 +1,112 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mpris.h"
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QJSEngine>
|
||||
|
||||
static const char *playbackStatusStrings[] = { "Playing", "Paused", "Stopped" };
|
||||
static const char *loopStatusStrings[] = { "None", "Track", "Playlist" };
|
||||
static const char *metadataStrings[] = { "mpris:trackid", "mpris:length", "mpris:artUrl", "xesam:album", "xesam:albumArtist", "xesam:artist", "xesam:asText", "xesam:audioBPM", "xesam:autoRating", "xesam:comment", "xesam:composer", "xesam:contentCreated", "xesam:discNumber", "xesam:firstUsed", "xesam:genre", "xesam:lastUsed", "xesam:lyricist", "xesam:title", "xesam:trackNumber", "xesam:url", "xesam:useCount", "xesam:userRating" };
|
||||
|
||||
|
||||
Mpris::Mpris(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Mpris::~Mpris()
|
||||
{
|
||||
}
|
||||
|
||||
QObject *Mpris::api_factory(QQmlEngine *, QJSEngine *)
|
||||
{
|
||||
return new Mpris;
|
||||
}
|
||||
|
||||
QString Mpris::metadataToString(Mpris::Metadata metadata)
|
||||
{
|
||||
return enumerationToString(metadata);
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
|
||||
template <typename T> void Mpris::getEnumStringsAndSize(const char ***strings, int *size)
|
||||
{
|
||||
if (is_same<T, Mpris::LoopStatus>::value) {
|
||||
*strings = loopStatusStrings;
|
||||
*size = arraySize(loopStatusStrings);
|
||||
} else if (is_same<T, Mpris::PlaybackStatus>::value) {
|
||||
*strings = playbackStatusStrings;
|
||||
*size = arraySize(playbackStatusStrings);
|
||||
} else if (is_same<T, Mpris::Metadata>::value) {
|
||||
*strings = metadataStrings;
|
||||
*size = arraySize(metadataStrings);
|
||||
} else {
|
||||
*strings = 0;
|
||||
*size = 0;
|
||||
}
|
||||
}
|
||||
template void Mpris::getEnumStringsAndSize<Mpris::LoopStatus>(const char ***strings, int *size);
|
||||
template void Mpris::getEnumStringsAndSize<Mpris::PlaybackStatus>(const char ***strings, int *size);
|
||||
template void Mpris::getEnumStringsAndSize<Mpris::Metadata>(const char ***strings, int *size);
|
||||
|
||||
|
||||
template <typename T> QString Mpris::enumerationToString(T enumeration)
|
||||
{
|
||||
const char **strings;
|
||||
int size;
|
||||
|
||||
getEnumStringsAndSize<T>(&strings, &size);
|
||||
|
||||
return enumeration >= 0 && enumeration < size
|
||||
? QString(QLatin1String(strings[enumeration]))
|
||||
: QString();
|
||||
}
|
||||
template QString Mpris::enumerationToString<Mpris::LoopStatus>(Mpris::LoopStatus enumeration);
|
||||
template QString Mpris::enumerationToString<Mpris::PlaybackStatus>(Mpris::PlaybackStatus enumeration);
|
||||
template QString Mpris::enumerationToString<Mpris::Metadata>(Mpris::Metadata enumeration);
|
||||
|
||||
|
||||
template <typename T> T Mpris::enumerationFromString(const QString &string)
|
||||
{
|
||||
const char **strings;
|
||||
int size;
|
||||
|
||||
getEnumStringsAndSize<T>(&strings, &size);
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (string == QLatin1String(strings[i])) {
|
||||
return T(i);
|
||||
}
|
||||
}
|
||||
|
||||
return T(-1);
|
||||
}
|
||||
template Mpris::LoopStatus Mpris::enumerationFromString<Mpris::LoopStatus>(const QString &string);
|
||||
template Mpris::PlaybackStatus Mpris::enumerationFromString<Mpris::PlaybackStatus>(const QString &string);
|
||||
template Mpris::Metadata Mpris::enumerationFromString<Mpris::Metadata>(const QString &string);
|
||||
@ -0,0 +1,106 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MPRIS_H
|
||||
#define MPRIS_H
|
||||
|
||||
#include "mprisqt.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
|
||||
class QQmlEngine;
|
||||
class QJSEngine;
|
||||
|
||||
class MPRIS_QT_EXPORT Mpris : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS(PlaybackStatus LoopStatus Metadata)
|
||||
|
||||
public:
|
||||
|
||||
enum PlaybackStatus {
|
||||
InvalidPlaybackStatus = -1,
|
||||
Playing,
|
||||
Paused,
|
||||
Stopped
|
||||
};
|
||||
|
||||
enum LoopStatus {
|
||||
InvalidLoopStatus = -1,
|
||||
None,
|
||||
Track,
|
||||
Playlist
|
||||
};
|
||||
|
||||
enum Metadata {
|
||||
InvalidMetadata = -1,
|
||||
TrackId,
|
||||
Length,
|
||||
ArtUrl,
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Artist,
|
||||
AsText,
|
||||
AudioBPM,
|
||||
AutoRating,
|
||||
Comment,
|
||||
Composer,
|
||||
ContentCreated,
|
||||
DiscNumber,
|
||||
FirstUsed,
|
||||
Genre,
|
||||
LastUsed,
|
||||
Lyricist,
|
||||
Title,
|
||||
TrackNumber,
|
||||
Url,
|
||||
UseCount,
|
||||
UserRating
|
||||
};
|
||||
|
||||
Mpris(QObject *parent = 0);
|
||||
~Mpris();
|
||||
|
||||
static QObject *api_factory(QQmlEngine *, QJSEngine *);
|
||||
|
||||
Q_INVOKABLE static QString metadataToString(Metadata metadata);
|
||||
|
||||
private:
|
||||
template<class T, int N> static int arraySize(T (&)[N]) { return N; };
|
||||
template<typename T, typename U> struct is_same { static const bool value = false; };
|
||||
template<typename T> struct is_same<T,T> { static const bool value = true; };
|
||||
template<typename T> static void getEnumStringsAndSize(const char ***strings, int *size);
|
||||
template<typename T> static QString enumerationToString(T enumeration);
|
||||
template<typename T> static T enumerationFromString(const QString &string);
|
||||
|
||||
friend class MprisRootAdaptor;
|
||||
friend class MprisPlayerAdaptor;
|
||||
friend class MprisPlayer;
|
||||
friend class MprisController;
|
||||
};
|
||||
|
||||
#endif /* MPRIS_H */
|
||||
@ -0,0 +1,691 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mpriscontroller.h"
|
||||
|
||||
#include "mpriscontroller_p.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
|
||||
static const QString mprisObjectPath = QStringLiteral("/org/mpris/MediaPlayer2");
|
||||
|
||||
MprisController::MprisController(const QString &service, const QDBusConnection &connection, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_mprisRootInterface(new MprisRootInterface(service, mprisObjectPath, connection, this))
|
||||
, m_mprisPlayerInterface(new MprisPlayerInterface(service, mprisObjectPath, connection, this))
|
||||
, m_initedRootInterface(false)
|
||||
, m_initedPlayerInterface(false)
|
||||
, m_requestedPosition(false)
|
||||
, m_canControlReceived(false)
|
||||
{
|
||||
// Mpris Root Interface
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::asyncGetAllPropertiesFinished, this, &MprisController::onAsyncGetAllRootPropertiesFinished);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::canQuitChanged, this, &MprisController::canQuitChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::canRaiseChanged, this, &MprisController::canRaiseChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::canSetFullscreenChanged, this, &MprisController::canSetFullscreenChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::desktopEntryChanged, this, &MprisController::desktopEntryChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::fullscreenChanged, this, &MprisController::fullscreenChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::hasTrackListChanged, this, &MprisController::hasTrackListChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::identityChanged, this, &MprisController::identityChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::supportedMimeTypesChanged, this, &MprisController::supportedMimeTypesChanged);
|
||||
connect(m_mprisRootInterface, &MprisRootInterface::supportedUriSchemesChanged, this, &MprisController::supportedUriSchemesChanged);
|
||||
m_mprisRootInterface->setUseCache(true);
|
||||
|
||||
// Mpris Player Interface
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::asyncGetAllPropertiesFinished, this, &MprisController::onAsyncGetAllPlayerPropertiesFinished);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canControlChanged, this, &MprisController::onCanControlChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canGoNextChanged, this, &MprisController::canGoNextChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canGoPreviousChanged, this, &MprisController::canGoPreviousChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canPauseChanged, this, &MprisController::canPauseChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canPlayChanged, this, &MprisController::canPlayChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canSeekChanged, this, &MprisController::canSeekChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::canSeekChanged, this, &MprisController::canSeekChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::loopStatusChanged, this, &MprisController::loopStatusChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::maximumRateChanged, this, &MprisController::maximumRateChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::metadataChanged, this, &MprisController::metadataChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::minimumRateChanged, this, &MprisController::minimumRateChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::playbackStatusChanged, this, &MprisController::playbackStatusChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::positionChanged, this, &MprisController::onPositionChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::rateChanged, this, &MprisController::rateChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::shuffleChanged, this, &MprisController::shuffleChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::volumeChanged, this, &MprisController::volumeChanged);
|
||||
connect(m_mprisPlayerInterface, &MprisPlayerInterface::seeked, this, &MprisController::seeked);
|
||||
m_mprisPlayerInterface->setUseCache(true);
|
||||
|
||||
// This will initialize the properties, if needed
|
||||
isValid();
|
||||
}
|
||||
|
||||
MprisController::~MprisController()
|
||||
{
|
||||
}
|
||||
|
||||
bool MprisController::isValid() const
|
||||
{
|
||||
if (!m_mprisRootInterface->isValid() || !m_mprisPlayerInterface->isValid()) {
|
||||
m_initedRootInterface = false;
|
||||
m_initedPlayerInterface = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_initedRootInterface) {
|
||||
m_mprisRootInterface->getAllProperties();
|
||||
if (m_mprisRootInterface->lastExtendedError().isValid()) {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Error" << m_mprisRootInterface->lastExtendedError().name()
|
||||
<< "happened:" << m_mprisRootInterface->lastExtendedError().message();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_initedPlayerInterface) {
|
||||
m_mprisPlayerInterface->getAllProperties();
|
||||
if (m_mprisPlayerInterface->lastExtendedError().isValid()) {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Error" << m_mprisPlayerInterface->lastExtendedError().name()
|
||||
<< "happened:" << m_mprisPlayerInterface->lastExtendedError().message();
|
||||
}
|
||||
}
|
||||
|
||||
return m_initedRootInterface && m_initedPlayerInterface;
|
||||
}
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool MprisController::quit()
|
||||
{
|
||||
if (!canQuit()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisRootInterface->Quit();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::raise()
|
||||
{
|
||||
if (!canRaise()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisRootInterface->Raise();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool MprisController::next()
|
||||
{
|
||||
if (!canGoNext()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->Next();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::openUri(const QUrl &uri)
|
||||
{
|
||||
if (!canControl()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!uri.isValid()) {
|
||||
qDebug() << Q_FUNC_INFO << "The uri is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_mprisRootInterface->supportedUriSchemes().contains(uri.scheme())) {
|
||||
qDebug() << Q_FUNC_INFO << "The scheme is not supported";
|
||||
return false;
|
||||
}
|
||||
|
||||
QMimeDatabase db;
|
||||
QMimeType mime;
|
||||
if (uri.isLocalFile()) {
|
||||
mime = db.mimeTypeForFile(uri.toLocalFile());
|
||||
} else {
|
||||
mime = db.mimeTypeForFile(uri.fileName(), QMimeDatabase::MatchExtension);
|
||||
}
|
||||
QStringList mimeNames = mime.aliases();
|
||||
mimeNames.prepend(mime.name());
|
||||
for (int i = 0; i < mimeNames.size(); i++) {
|
||||
if (m_mprisRootInterface->supportedMimeTypes().contains(mimeNames[i])) {
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->OpenUri(uri.toString());
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "The mime type is not supported";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::pause()
|
||||
{
|
||||
if (!canPause()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->Pause();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::play()
|
||||
{
|
||||
if (!canPlay()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->Play();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::playPause()
|
||||
{
|
||||
if (!canPause()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->PlayPause();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::previous()
|
||||
{
|
||||
if (!canGoPrevious()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->Previous();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::seek(qlonglong offset)
|
||||
{
|
||||
if (!canSeek()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->Seek(offset);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::setPosition(qlonglong position)
|
||||
{
|
||||
if (!canSeek()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant trackId = m_mprisPlayerInterface->metadata()[Mpris::metadataToString(Mpris::TrackId)];
|
||||
if (!trackId.isValid()) {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown trackId in which to set the position";
|
||||
return false;
|
||||
}
|
||||
|
||||
return setPosition(trackId.value<QDBusObjectPath>().path(), position);
|
||||
}
|
||||
|
||||
bool MprisController::setPosition(const QString &aTrackId, qlonglong position)
|
||||
{
|
||||
if (!canSeek()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusObjectPath trackId(aTrackId);
|
||||
if (trackId.path().isEmpty()) {
|
||||
qDebug() << Q_FUNC_INFO << "trackId doesn't map to a valid DBus object path";
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant length = m_mprisPlayerInterface->metadata()[Mpris::metadataToString(Mpris::Length)];
|
||||
if (!length.isValid()) {
|
||||
qlonglong reportedLength = length.toLongLong();
|
||||
|
||||
if (position < 0 || position > reportedLength) {
|
||||
qDebug() << Q_FUNC_INFO << "Unknown trackId in which to set the position";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->SetPosition(trackId, position);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MprisController::stop()
|
||||
{
|
||||
if (!canControl()) {
|
||||
qDebug() << Q_FUNC_INFO << "The method is not allowed";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = m_mprisPlayerInterface->Stop();
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(onFinishedPendingCall(QDBusPendingCallWatcher*)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Slots
|
||||
|
||||
QString MprisController::service() const
|
||||
{
|
||||
return m_mprisRootInterface->service();
|
||||
}
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool MprisController::canQuit() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->canQuit();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canRaise() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->canRaise();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canSetFullscreen() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->canSetFullscreen();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString MprisController::desktopEntry() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->desktopEntry();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool MprisController::fullscreen() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->fullscreen();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MprisController::setFullscreen(bool fullscreen)
|
||||
{
|
||||
if (isValid()) {
|
||||
m_mprisRootInterface->setFullscreen(fullscreen);
|
||||
}
|
||||
}
|
||||
|
||||
bool MprisController::hasTrackList() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->hasTrackList();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString MprisController::identity() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->identity();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList MprisController::supportedUriSchemes() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->supportedUriSchemes();
|
||||
}
|
||||
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QStringList MprisController::supportedMimeTypes() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisRootInterface->supportedMimeTypes();
|
||||
}
|
||||
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool MprisController::canControl() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->canControl();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canGoNext() const
|
||||
{
|
||||
if (isValid() && canControl()) {
|
||||
return m_mprisPlayerInterface->canGoNext();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canGoPrevious() const
|
||||
{
|
||||
if (isValid() && canControl()) {
|
||||
return m_mprisPlayerInterface->canGoPrevious();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canPause() const
|
||||
{
|
||||
if (isValid() && canControl()) {
|
||||
return m_mprisPlayerInterface->canPause();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canPlay() const
|
||||
{
|
||||
if (isValid() && canControl()) {
|
||||
return m_mprisPlayerInterface->canPlay();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MprisController::canSeek() const
|
||||
{
|
||||
if (isValid() && canControl()) {
|
||||
return m_mprisPlayerInterface->canSeek();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Mpris::LoopStatus MprisController::loopStatus() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return Mpris::enumerationFromString<Mpris::LoopStatus>(m_mprisPlayerInterface->loopStatus());
|
||||
}
|
||||
|
||||
return Mpris::None;
|
||||
}
|
||||
|
||||
void MprisController::setLoopStatus(Mpris::LoopStatus loopStatus)
|
||||
{
|
||||
if (isValid()) {
|
||||
m_mprisPlayerInterface->setLoopStatus(Mpris::enumerationToString(loopStatus));
|
||||
}
|
||||
}
|
||||
|
||||
double MprisController::maximumRate() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->maximumRate();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariantMap MprisController::metadata() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->metadata();
|
||||
}
|
||||
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
double MprisController::minimumRate() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->minimumRate();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Mpris::PlaybackStatus MprisController::playbackStatus() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return Mpris::enumerationFromString<Mpris::PlaybackStatus>(m_mprisPlayerInterface->playbackStatus());
|
||||
}
|
||||
|
||||
return Mpris::Stopped;
|
||||
}
|
||||
|
||||
qlonglong MprisController::position() const
|
||||
{
|
||||
if (isValid()) {
|
||||
m_mprisPlayerInterface->setSync(true);
|
||||
m_mprisPlayerInterface->setUseCache(false);
|
||||
qlonglong result = m_mprisPlayerInterface->position();
|
||||
m_mprisPlayerInterface->setUseCache(true);
|
||||
m_mprisPlayerInterface->setSync(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MprisController::requestPosition() const
|
||||
{
|
||||
if (m_requestedPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isValid()) {
|
||||
m_mprisPlayerInterface->setUseCache(false);
|
||||
m_mprisPlayerInterface->position();
|
||||
m_mprisPlayerInterface->setUseCache(true);
|
||||
if (m_mprisPlayerInterface->lastExtendedError().isValid()) {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Failed requesting the current position in the MPRIS2 Player Interface!!!";
|
||||
return;
|
||||
}
|
||||
m_requestedPosition = true;
|
||||
}
|
||||
}
|
||||
|
||||
double MprisController::rate() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->rate();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MprisController::setRate(double rate)
|
||||
{
|
||||
if (isValid()) {
|
||||
m_mprisPlayerInterface->setRate(rate);
|
||||
}
|
||||
}
|
||||
|
||||
bool MprisController::shuffle() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->shuffle();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MprisController::setShuffle(bool shuffle)
|
||||
{
|
||||
if (isValid()) {
|
||||
m_mprisPlayerInterface->setShuffle(shuffle);
|
||||
}
|
||||
}
|
||||
|
||||
double MprisController::volume() const
|
||||
{
|
||||
if (isValid()) {
|
||||
return m_mprisPlayerInterface->volume();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MprisController::setVolume(double volume)
|
||||
{
|
||||
if (isValid()) {
|
||||
m_mprisPlayerInterface->setVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Protected
|
||||
|
||||
void MprisController::onAsyncGetAllRootPropertiesFinished()
|
||||
{
|
||||
if (m_mprisRootInterface->lastExtendedError().isValid()) {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Error" << m_mprisRootInterface->lastExtendedError().name()
|
||||
<< "happened:" << m_mprisRootInterface->lastExtendedError().message();
|
||||
return;
|
||||
}
|
||||
|
||||
m_initedRootInterface = true;
|
||||
}
|
||||
|
||||
void MprisController::onAsyncGetAllPlayerPropertiesFinished()
|
||||
{
|
||||
if (m_mprisPlayerInterface->lastExtendedError().isValid()) {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Error" << m_mprisPlayerInterface->lastExtendedError().name()
|
||||
<< "happened:" << m_mprisPlayerInterface->lastExtendedError().message();
|
||||
return;
|
||||
}
|
||||
|
||||
m_initedPlayerInterface = true;
|
||||
}
|
||||
|
||||
void MprisController::onCanControlChanged()
|
||||
{
|
||||
// On first reception, we are using a "GetAll" so we can skip this
|
||||
if (m_canControlReceived) {
|
||||
// I could disconnect and re-connect the signals so I avoid
|
||||
// double arriving signals but this really shouldn't happen
|
||||
// ever.
|
||||
Q_EMIT canGoNextChanged();
|
||||
Q_EMIT canGoPreviousChanged();
|
||||
Q_EMIT canPauseChanged();
|
||||
Q_EMIT canPlayChanged();
|
||||
Q_EMIT canSeekChanged();
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "CanControl is not supposed to change its value!";
|
||||
return;
|
||||
}
|
||||
|
||||
m_canControlReceived = true;
|
||||
}
|
||||
|
||||
void MprisController::onPositionChanged(qlonglong aPosition)
|
||||
{
|
||||
m_requestedPosition = false;
|
||||
Q_EMIT positionChanged(aPosition);
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
|
||||
void MprisController::onFinishedPendingCall(QDBusPendingCallWatcher *call)
|
||||
{
|
||||
QDBusPendingReply<> reply = *call;
|
||||
if (reply.isError()) {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Error" << reply.error().name()
|
||||
<< "happened:" << reply.error().message();
|
||||
}
|
||||
|
||||
call->deleteLater();
|
||||
}
|
||||
@ -0,0 +1,212 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MPRISCONTROLLER_H
|
||||
#define MPRISCONTROLLER_H
|
||||
|
||||
#include "mprisqt.h"
|
||||
#include "mpris.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusObjectPath>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
|
||||
class MprisRootInterface;
|
||||
class MprisPlayerInterface;
|
||||
class QDBusPendingCallWatcher;
|
||||
class MPRIS_QT_EXPORT MprisController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString service READ service)
|
||||
|
||||
// Mpris2 Root Interface
|
||||
Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged)
|
||||
Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged)
|
||||
Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged)
|
||||
Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged)
|
||||
Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
|
||||
Q_PROPERTY(bool hasTrackList READ hasTrackList NOTIFY hasTrackListChanged)
|
||||
Q_PROPERTY(QString identity READ identity NOTIFY identityChanged)
|
||||
Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged)
|
||||
Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged)
|
||||
|
||||
// Mpris2 Player Interface
|
||||
Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged)
|
||||
Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged)
|
||||
Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged)
|
||||
Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged)
|
||||
Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged)
|
||||
Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged)
|
||||
Q_PROPERTY(Mpris::LoopStatus loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged)
|
||||
Q_PROPERTY(double maximumRate READ maximumRate NOTIFY maximumRateChanged)
|
||||
Q_PROPERTY(QVariantMap metadata READ metadata NOTIFY metadataChanged)
|
||||
Q_PROPERTY(double minimumRate READ minimumRate NOTIFY minimumRateChanged)
|
||||
Q_PROPERTY(Mpris::PlaybackStatus playbackStatus READ playbackStatus NOTIFY playbackStatusChanged)
|
||||
Q_PROPERTY(qlonglong position READ position)
|
||||
Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged)
|
||||
Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged)
|
||||
Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
|
||||
public:
|
||||
|
||||
MprisController(const QString &service, const QDBusConnection &connection, QObject *parent = 0);
|
||||
~MprisController();
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool quit();
|
||||
bool raise();
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool next();
|
||||
bool openUri(const QUrl &uri);
|
||||
bool pause();
|
||||
bool play();
|
||||
bool playPause();
|
||||
bool previous();
|
||||
bool seek(qlonglong offset);
|
||||
bool setPosition(qlonglong position);
|
||||
bool setPosition(const QString &aTrackId, qlonglong position);
|
||||
bool stop();
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
QString service() const;
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool canQuit() const;
|
||||
|
||||
bool canRaise() const;
|
||||
|
||||
bool canSetFullscreen() const;
|
||||
|
||||
QString desktopEntry() const;
|
||||
|
||||
bool fullscreen() const;
|
||||
void setFullscreen(bool fullscreen);
|
||||
|
||||
bool hasTrackList() const;
|
||||
|
||||
QString identity() const;
|
||||
|
||||
QStringList supportedUriSchemes() const;
|
||||
|
||||
QStringList supportedMimeTypes() const;
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool canControl() const;
|
||||
|
||||
bool canGoNext() const;
|
||||
|
||||
bool canGoPrevious() const;
|
||||
|
||||
bool canPause() const;
|
||||
|
||||
bool canPlay() const;
|
||||
|
||||
bool canSeek() const;
|
||||
|
||||
Mpris::LoopStatus loopStatus() const;
|
||||
void setLoopStatus(Mpris::LoopStatus loopStatus);
|
||||
|
||||
double maximumRate() const;
|
||||
|
||||
QVariantMap metadata() const;
|
||||
|
||||
double minimumRate() const;
|
||||
|
||||
Mpris::PlaybackStatus playbackStatus() const;
|
||||
|
||||
qlonglong position() const;
|
||||
void requestPosition() const;
|
||||
|
||||
double rate() const;
|
||||
void setRate(double rate);
|
||||
|
||||
bool shuffle() const;
|
||||
void setShuffle(bool shuffle);
|
||||
|
||||
double volume() const;
|
||||
void setVolume(double volume);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
// Mpris2 Root Interface
|
||||
void canQuitChanged();
|
||||
void canRaiseChanged();
|
||||
void canSetFullscreenChanged();
|
||||
void desktopEntryChanged();
|
||||
void fullscreenChanged();
|
||||
void hasTrackListChanged();
|
||||
void identityChanged();
|
||||
void supportedUriSchemesChanged();
|
||||
void supportedMimeTypesChanged();
|
||||
|
||||
// Mpris2 Player Interface
|
||||
void canControlChanged();
|
||||
void canGoNextChanged();
|
||||
void canGoPreviousChanged();
|
||||
void canPauseChanged();
|
||||
void canPlayChanged();
|
||||
void canSeekChanged();
|
||||
void loopStatusChanged();
|
||||
void maximumRateChanged();
|
||||
void metadataChanged();
|
||||
void minimumRateChanged();
|
||||
void playbackStatusChanged();
|
||||
void positionChanged(qlonglong position);
|
||||
void rateChanged();
|
||||
void shuffleChanged();
|
||||
void volumeChanged();
|
||||
void seeked(qlonglong position);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onAsyncGetAllRootPropertiesFinished();
|
||||
void onAsyncGetAllPlayerPropertiesFinished();
|
||||
void onCanControlChanged();
|
||||
void onPositionChanged(qlonglong aPosition);
|
||||
void onFinishedPendingCall(QDBusPendingCallWatcher *call);
|
||||
|
||||
private:
|
||||
MprisRootInterface *m_mprisRootInterface;
|
||||
MprisPlayerInterface *m_mprisPlayerInterface;
|
||||
|
||||
mutable bool m_initedRootInterface;
|
||||
mutable bool m_initedPlayerInterface;
|
||||
mutable bool m_requestedPosition;
|
||||
bool m_canControlReceived;
|
||||
};
|
||||
|
||||
#endif /* MPRISCONTROLLER_H */
|
||||
@ -0,0 +1,336 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// 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 MPRISCONTROLLER_P_H
|
||||
#define MPRISCONTROLLER_P_H
|
||||
|
||||
#include "qtdbusextended/dbusextendedabstractinterface.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtDBus/QtDBus>
|
||||
|
||||
/*
|
||||
* Proxy class for interface org.mpris.MediaPlayer2
|
||||
*/
|
||||
class MprisRootInterface: public DBusExtendedAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static inline const char *staticInterfaceName()
|
||||
{ return "org.mpris.MediaPlayer2"; }
|
||||
|
||||
public:
|
||||
MprisRootInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
|
||||
|
||||
~MprisRootInterface();
|
||||
|
||||
Q_PROPERTY(bool CanQuit READ canQuit NOTIFY canQuitChanged)
|
||||
inline bool canQuit()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanQuit", &m_canQuit)); }
|
||||
|
||||
Q_PROPERTY(bool CanRaise READ canRaise NOTIFY canRaiseChanged)
|
||||
inline bool canRaise()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanRaise", &m_canRaise)); }
|
||||
|
||||
Q_PROPERTY(bool CanSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged)
|
||||
inline bool canSetFullscreen()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanSetFullscreen", &m_canSetFullscreen)); }
|
||||
|
||||
Q_PROPERTY(QString DesktopEntry READ desktopEntry NOTIFY desktopEntryChanged)
|
||||
inline QString desktopEntry()
|
||||
{ return qvariant_cast< QString >(internalPropGet("DesktopEntry", &m_desktopEntry)); }
|
||||
|
||||
Q_PROPERTY(bool Fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
|
||||
inline bool fullscreen()
|
||||
{ return qvariant_cast< bool >(internalPropGet("Fullscreen", &m_fullscreen)); }
|
||||
inline void setFullscreen(bool value)
|
||||
{ m_fullscreen = value; internalPropSet("Fullscreen", QVariant::fromValue(value), &m_fullscreen); }
|
||||
|
||||
Q_PROPERTY(bool HasTrackList READ hasTrackList NOTIFY hasTrackListChanged)
|
||||
inline bool hasTrackList()
|
||||
{ return qvariant_cast< bool >(internalPropGet("HasTrackList", &m_hasTrackList)); }
|
||||
|
||||
Q_PROPERTY(QString Identity READ identity NOTIFY identityChanged)
|
||||
inline QString identity()
|
||||
{ return qvariant_cast< QString >(internalPropGet("Identity", &m_identity)); }
|
||||
|
||||
Q_PROPERTY(QStringList SupportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged)
|
||||
inline QStringList supportedMimeTypes()
|
||||
{ return qvariant_cast< QStringList >(internalPropGet("SupportedMimeTypes", &m_supportedMimeTypes)); }
|
||||
|
||||
Q_PROPERTY(QStringList SupportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged)
|
||||
inline QStringList supportedUriSchemes()
|
||||
{ return qvariant_cast< QStringList >(internalPropGet("SupportedUriSchemes", &m_supportedUriSchemes)); }
|
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
inline QDBusPendingReply<> Quit()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Quit"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Raise()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Raise"), argumentList);
|
||||
}
|
||||
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void canQuitChanged(bool canQuit);
|
||||
void canRaiseChanged(bool canRaise);
|
||||
void canSetFullscreenChanged(bool canSetFullscreen);
|
||||
void desktopEntryChanged(const QString &desktopEntry);
|
||||
void fullscreenChanged(bool fullscreen);
|
||||
void hasTrackListChanged(bool hasTrackList);
|
||||
void identityChanged(const QString &identity);
|
||||
void supportedMimeTypesChanged(const QStringList &supportedMimeTypes);
|
||||
void supportedUriSchemesChanged(const QStringList &supportedUriSchemes);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPropertyChanged(const QString &propertyName, const QVariant &value);
|
||||
|
||||
private:
|
||||
bool m_canQuit;
|
||||
bool m_canRaise;
|
||||
bool m_canSetFullscreen;
|
||||
QString m_desktopEntry;
|
||||
bool m_fullscreen;
|
||||
bool m_hasTrackList;
|
||||
QString m_identity;
|
||||
QStringList m_supportedUriSchemes;
|
||||
QStringList m_supportedMimeTypes;
|
||||
};
|
||||
|
||||
namespace org {
|
||||
namespace mpris {
|
||||
typedef ::MprisRootInterface MediaPlayer2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Proxy class for interface org.mpris.MediaPlayer2
|
||||
*/
|
||||
class MprisPlayerInterface: public DBusExtendedAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static inline const char *staticInterfaceName()
|
||||
{ return "org.mpris.MediaPlayer2.Player"; }
|
||||
|
||||
public:
|
||||
MprisPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
|
||||
|
||||
~MprisPlayerInterface();
|
||||
|
||||
Q_PROPERTY(bool CanControl READ canControl NOTIFY canControlChanged)
|
||||
inline bool canControl()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanControl", &m_canControl)); }
|
||||
|
||||
Q_PROPERTY(bool CanGoNext READ canGoNext NOTIFY canGoNextChanged)
|
||||
inline bool canGoNext()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanGoNext", &m_canGoNext)); }
|
||||
|
||||
Q_PROPERTY(bool CanGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged)
|
||||
inline bool canGoPrevious()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanGoPrevious", &m_canGoPrevious)); }
|
||||
|
||||
Q_PROPERTY(bool CanPause READ canPause NOTIFY canPauseChanged)
|
||||
inline bool canPause()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanPause", &m_canPause)); }
|
||||
|
||||
Q_PROPERTY(bool CanPlay READ canPlay NOTIFY canPlayChanged)
|
||||
inline bool canPlay()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanPlay", &m_canPlay)); }
|
||||
|
||||
Q_PROPERTY(bool CanSeek READ canSeek NOTIFY canSeekChanged)
|
||||
inline bool canSeek()
|
||||
{ return qvariant_cast< bool >(internalPropGet("CanSeek", &m_canSeek)); }
|
||||
|
||||
Q_PROPERTY(QString LoopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged)
|
||||
inline QString loopStatus()
|
||||
{ return qvariant_cast< QString >(internalPropGet("LoopStatus", &m_loopStatus)); }
|
||||
inline void setLoopStatus(const QString &value)
|
||||
{ m_loopStatus = value; internalPropSet("LoopStatus", QVariant::fromValue(value), &m_loopStatus); }
|
||||
|
||||
Q_PROPERTY(double MaximumRate READ maximumRate NOTIFY maximumRateChanged)
|
||||
inline double maximumRate()
|
||||
{ return qvariant_cast< double >(internalPropGet("MaximumRate", &m_maximumRate)); }
|
||||
|
||||
Q_PROPERTY(QVariantMap Metadata READ metadata NOTIFY metadataChanged)
|
||||
inline QVariantMap metadata()
|
||||
{ return qvariant_cast< QVariantMap >(internalPropGet("Metadata", &m_metadata)); }
|
||||
|
||||
Q_PROPERTY(double MinimumRate READ minimumRate NOTIFY minimumRateChanged)
|
||||
inline double minimumRate()
|
||||
{ return qvariant_cast< double >(internalPropGet("MinimumRate", &m_minimumRate)); }
|
||||
|
||||
Q_PROPERTY(QString PlaybackStatus READ playbackStatus NOTIFY playbackStatusChanged)
|
||||
inline QString playbackStatus()
|
||||
{ return qvariant_cast< QString >(internalPropGet("PlaybackStatus", &m_playbackStatus)); }
|
||||
|
||||
Q_PROPERTY(qlonglong Position READ position NOTIFY positionChanged)
|
||||
inline qlonglong position()
|
||||
{ return qvariant_cast< qlonglong >(internalPropGet("Position", &m_position)); }
|
||||
|
||||
Q_PROPERTY(double Rate READ rate WRITE setRate NOTIFY rateChanged)
|
||||
inline double rate()
|
||||
{ return qvariant_cast< double >(internalPropGet("Rate", &m_rate)); }
|
||||
inline void setRate(double value)
|
||||
{ m_rate = value; internalPropSet("Rate", QVariant::fromValue(value), &m_rate); }
|
||||
|
||||
Q_PROPERTY(bool Shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged)
|
||||
inline bool shuffle()
|
||||
{ return qvariant_cast< bool >(internalPropGet("Shuffle", &m_shuffle)); }
|
||||
inline void setShuffle(bool value)
|
||||
{ m_shuffle = value; internalPropSet("Shuffle", QVariant::fromValue(value), &m_shuffle); }
|
||||
|
||||
Q_PROPERTY(double Volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
inline double volume()
|
||||
{ return qvariant_cast< double >(internalPropGet("Volume", &m_volume)); }
|
||||
inline void setVolume(double value)
|
||||
{ m_volume = value; internalPropSet("Volume", QVariant::fromValue(value), &m_volume); }
|
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
inline QDBusPendingReply<> Next()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Next"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> OpenUri(const QString &Uri)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(Uri);
|
||||
return asyncCallWithArgumentList(QLatin1String("OpenUri"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Pause()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Pause"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Play()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Play"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> PlayPause()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("PlayPause"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Previous()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Previous"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Seek(qlonglong Offset)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(Offset);
|
||||
return asyncCallWithArgumentList(QLatin1String("Seek"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> SetPosition(const QDBusObjectPath &TrackId, qlonglong Position)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(TrackId) << QVariant::fromValue(Position);
|
||||
return asyncCallWithArgumentList(QLatin1String("SetPosition"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Stop()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QLatin1String("Stop"), argumentList);
|
||||
}
|
||||
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void canControlChanged(bool canControl);
|
||||
void canGoNextChanged(bool canGoNext);
|
||||
void canGoPreviousChanged(bool canGoPrevious);
|
||||
void canPauseChanged(bool canPause);
|
||||
void canPlayChanged(bool canPlay);
|
||||
void canSeekChanged(bool canSeek);
|
||||
void loopStatusChanged(const QString &loopStatus);
|
||||
void maximumRateChanged(double maximumRate);
|
||||
void metadataChanged(const QVariantMap &metadata);
|
||||
void minimumRateChanged(double minimumRate);
|
||||
void playbackStatusChanged(const QString &playbackStatus);
|
||||
void positionChanged(qlonglong rate);
|
||||
void rateChanged(double rate);
|
||||
void shuffleChanged(bool shuffle);
|
||||
void volumeChanged(double volume);
|
||||
void seeked(qlonglong Position);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPropertyChanged(const QString &propertyName, const QVariant &value);
|
||||
|
||||
private:
|
||||
bool m_canControl;
|
||||
bool m_canGoNext;
|
||||
bool m_canGoPrevious;
|
||||
bool m_canPause;
|
||||
bool m_canPlay;
|
||||
bool m_canSeek;
|
||||
QString m_loopStatus;
|
||||
double m_maximumRate;
|
||||
QVariantMap m_metadata;
|
||||
double m_minimumRate;
|
||||
QString m_playbackStatus;
|
||||
qlonglong m_position;
|
||||
double m_rate;
|
||||
bool m_shuffle;
|
||||
double m_volume;
|
||||
};
|
||||
|
||||
namespace MediaPlayer2 {
|
||||
typedef ::MprisPlayerInterface Player;
|
||||
}
|
||||
|
||||
#endif /* MPRISROOTINTERFACE_P_H */
|
||||
@ -0,0 +1,606 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mprismanager.h"
|
||||
|
||||
#include "mpriscontroller.h"
|
||||
|
||||
#include <qqmlinfo.h>
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
#include <QtCore/QSignalMapper>
|
||||
|
||||
static const QString mprisNameSpace = QStringLiteral("org.mpris.MediaPlayer2.*");
|
||||
static const QString dBusService = QStringLiteral("org.freedesktop.DBus");
|
||||
static const QString dBusObjectPath = QStringLiteral("/org/freedesktop/DBus");
|
||||
static const QString dBusInterface = QStringLiteral("org.freedesktop.DBus");
|
||||
static const QString dBusNameOwnerChangedSignal = QStringLiteral("NameOwnerChanged");
|
||||
|
||||
static inline QDBusConnection getDBusConnection()
|
||||
{
|
||||
#ifdef USE_SYSTEM_DBUS
|
||||
return QDBusConnection::systemBus();
|
||||
#else
|
||||
return QDBusConnection::sessionBus();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
MprisManager::MprisManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_singleService(false)
|
||||
, m_playbackStatusMapper(new QSignalMapper(this))
|
||||
{
|
||||
QDBusConnection connection = getDBusConnection();
|
||||
|
||||
if (!connection.isConnected()) {
|
||||
qmlInfo(this) << "Failed attempting to connect to DBus";
|
||||
return;
|
||||
}
|
||||
|
||||
connection.connect(dBusService, dBusObjectPath, dBusInterface, dBusNameOwnerChangedSignal,
|
||||
QStringList(), QString(),
|
||||
this, SLOT(onNameOwnerChanged(QString, QString, QString)));
|
||||
|
||||
QStringList serviceNames = connection.interface()->registeredServiceNames();
|
||||
QStringList::const_iterator i = serviceNames.constBegin();
|
||||
while (i != serviceNames.constEnd()) {
|
||||
QRegExp rx(mprisNameSpace);
|
||||
rx.setPatternSyntax(QRegExp::Wildcard);
|
||||
if (rx.exactMatch(*i)) {
|
||||
onServiceAppeared(*i);
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
MprisManager::~MprisManager()
|
||||
{
|
||||
}
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool MprisManager::quit() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->quit();
|
||||
}
|
||||
|
||||
bool MprisManager::raise() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->raise();
|
||||
}
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool MprisManager::next() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->next();
|
||||
}
|
||||
|
||||
bool MprisManager::openUri(const QUrl &uri) const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->openUri(uri);
|
||||
}
|
||||
|
||||
bool MprisManager::pause() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->pause();
|
||||
}
|
||||
|
||||
bool MprisManager::play() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->play();
|
||||
}
|
||||
|
||||
bool MprisManager::playPause() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->playPause();
|
||||
}
|
||||
|
||||
bool MprisManager::previous() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->previous();
|
||||
}
|
||||
|
||||
bool MprisManager::seek(qlonglong offset) const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->seek(offset);
|
||||
}
|
||||
|
||||
bool MprisManager::setPosition(qlonglong position) const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->setPosition(position);
|
||||
}
|
||||
|
||||
bool MprisManager::setPosition(const QString &trackId, qlonglong position) const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->setPosition(trackId, position);
|
||||
}
|
||||
|
||||
bool MprisManager::stop() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->stop();
|
||||
}
|
||||
|
||||
|
||||
// Slots
|
||||
|
||||
bool MprisManager::singleService() const
|
||||
{
|
||||
return m_singleService;
|
||||
}
|
||||
|
||||
void MprisManager::setSingleService(bool single)
|
||||
{
|
||||
if (m_singleService == single) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_singleService = single;
|
||||
Q_EMIT singleServiceChanged();
|
||||
}
|
||||
|
||||
QString MprisManager::currentService() const
|
||||
{
|
||||
return m_currentController.isNull() ? QString() : m_currentController->service();
|
||||
}
|
||||
|
||||
void MprisManager::setCurrentService(const QString &service)
|
||||
{
|
||||
if (!m_currentController.isNull() && m_currentController->service() == service) {
|
||||
return;
|
||||
}
|
||||
|
||||
QRegExp rx(mprisNameSpace);
|
||||
rx.setPatternSyntax(QRegExp::Wildcard);
|
||||
if (!rx.exactMatch(service)) {
|
||||
qmlInfo(this) << service << "is not a proper Mpris2 service";
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<MprisController> controller = availableController(service);
|
||||
if (controller.isNull()) {
|
||||
controller = QSharedPointer<MprisController>(new MprisController(service, getDBusConnection(), this));
|
||||
} else {
|
||||
m_availableControllers.move(m_availableControllers.indexOf(controller), 0);
|
||||
}
|
||||
|
||||
setCurrentController(controller);
|
||||
}
|
||||
|
||||
QStringList MprisManager::availableServices() const
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
QList< QSharedPointer<MprisController> >::const_iterator i = m_availableControllers.constBegin();
|
||||
while (i != m_availableControllers.constEnd()) {
|
||||
const QSharedPointer<MprisController> controller = *i;
|
||||
result.append(controller->service());
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool MprisManager::canQuit() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canQuit();
|
||||
}
|
||||
|
||||
bool MprisManager::canRaise() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canRaise();
|
||||
}
|
||||
|
||||
bool MprisManager::canSetFullscreen() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canSetFullscreen();
|
||||
}
|
||||
|
||||
QString MprisManager::desktopEntry() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->desktopEntry() : QString();
|
||||
}
|
||||
|
||||
bool MprisManager::fullscreen() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->fullscreen();
|
||||
}
|
||||
|
||||
void MprisManager::setFullscreen(bool fullscreen)
|
||||
{
|
||||
if (checkController(Q_FUNC_INFO)) {
|
||||
m_currentController->setFullscreen(fullscreen);
|
||||
}
|
||||
}
|
||||
|
||||
bool MprisManager::hasTrackList() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->hasTrackList();
|
||||
}
|
||||
|
||||
QString MprisManager::identity() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->identity() : QString();
|
||||
}
|
||||
|
||||
QStringList MprisManager::supportedUriSchemes() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->supportedUriSchemes() : QStringList();
|
||||
}
|
||||
|
||||
QStringList MprisManager::supportedMimeTypes() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->supportedMimeTypes() : QStringList();
|
||||
}
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool MprisManager::canControl() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canControl();
|
||||
}
|
||||
|
||||
bool MprisManager::canGoNext() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canGoNext();
|
||||
}
|
||||
|
||||
bool MprisManager::canGoPrevious() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canGoPrevious();
|
||||
}
|
||||
|
||||
bool MprisManager::canPause() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canPause();
|
||||
}
|
||||
|
||||
bool MprisManager::canPlay() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canPlay();
|
||||
}
|
||||
|
||||
bool MprisManager::canSeek() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->canSeek();
|
||||
}
|
||||
|
||||
Mpris::LoopStatus MprisManager::loopStatus() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->loopStatus() : Mpris::None;
|
||||
}
|
||||
|
||||
void MprisManager::setLoopStatus(Mpris::LoopStatus loopStatus)
|
||||
{
|
||||
if (checkController(Q_FUNC_INFO)) {
|
||||
m_currentController->setLoopStatus(loopStatus);
|
||||
}
|
||||
}
|
||||
|
||||
double MprisManager::maximumRate() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->maximumRate() : 1;
|
||||
}
|
||||
|
||||
QVariantMap MprisManager::metadata() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->metadata() : QVariantMap();
|
||||
}
|
||||
|
||||
double MprisManager::minimumRate() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->minimumRate() : 1;
|
||||
}
|
||||
|
||||
Mpris::PlaybackStatus MprisManager::playbackStatus() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->playbackStatus() : Mpris::Stopped;
|
||||
}
|
||||
|
||||
qlonglong MprisManager::position() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->position() : 0;
|
||||
}
|
||||
|
||||
void MprisManager::requestPosition() const
|
||||
{
|
||||
if (checkController(Q_FUNC_INFO)) {
|
||||
m_currentController->requestPosition();
|
||||
}
|
||||
}
|
||||
|
||||
double MprisManager::rate() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->rate() : 1;
|
||||
}
|
||||
|
||||
void MprisManager::setRate(double rate)
|
||||
{
|
||||
if (checkController(Q_FUNC_INFO)) {
|
||||
m_currentController->setRate(rate);
|
||||
}
|
||||
}
|
||||
|
||||
bool MprisManager::shuffle() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) && m_currentController->shuffle();
|
||||
}
|
||||
|
||||
void MprisManager::setShuffle(bool shuffle)
|
||||
{
|
||||
if (checkController(Q_FUNC_INFO)) {
|
||||
m_currentController->setShuffle(shuffle);
|
||||
}
|
||||
}
|
||||
|
||||
double MprisManager::volume() const
|
||||
{
|
||||
return checkController(Q_FUNC_INFO) ? m_currentController->volume() : 0;
|
||||
}
|
||||
|
||||
void MprisManager::setVolume(double volume)
|
||||
{
|
||||
if (checkController(Q_FUNC_INFO)) {
|
||||
m_currentController->setVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
|
||||
void MprisManager::onNameOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
|
||||
{
|
||||
// Unfortunately, QDBus doesn't allow flexible signal watchers.
|
||||
// Would it allow them, we could pass the filter "arg0namespace='org.mpris.MediaPlayer2'"
|
||||
// Therefore, we will receive here all the name changes in the
|
||||
// bus, not just the ones for our name space of interest, and we
|
||||
// will have to filter on our own :(
|
||||
|
||||
QRegExp rx(mprisNameSpace);
|
||||
rx.setPatternSyntax(QRegExp::Wildcard);
|
||||
if (!rx.exactMatch(service)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldOwner.isEmpty()) {
|
||||
onServiceAppeared(service);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newOwner.isEmpty()) {
|
||||
onServiceVanished(service);
|
||||
return;
|
||||
}
|
||||
|
||||
// Service changed owner. Nothing to do ...
|
||||
}
|
||||
|
||||
void MprisManager::onServiceAppeared(const QString &service)
|
||||
{
|
||||
QSharedPointer<MprisController> controller = availableController(service);
|
||||
if (!controller.isNull()) {
|
||||
Q_ASSERT(m_availableControllers.contains(controller));
|
||||
m_availableControllers.removeOne(controller);
|
||||
m_otherPlayingControllers.removeOne(controller);
|
||||
} else {
|
||||
if (!m_currentController.isNull() && service == m_currentController->service()) {
|
||||
controller = m_currentController;
|
||||
} else {
|
||||
controller = QSharedPointer<MprisController>(new MprisController(service, getDBusConnection(), this));
|
||||
}
|
||||
|
||||
connect(controller.data(), SIGNAL(playbackStatusChanged()), m_playbackStatusMapper, SLOT(map()));
|
||||
m_playbackStatusMapper->setMapping(controller.data(), controller->service());
|
||||
connect(m_playbackStatusMapper, SIGNAL(mapped(QString)), this, SLOT(onAvailableControllerPlaybackStatusChanged(QString)));
|
||||
}
|
||||
|
||||
if (m_currentController.isNull()) {
|
||||
setCurrentController(controller);
|
||||
}
|
||||
|
||||
if (controller == m_currentController) {
|
||||
m_availableControllers.prepend(controller);
|
||||
Q_EMIT availableServicesChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_singleService
|
||||
&& m_currentController->playbackStatus() != Mpris::Playing) {
|
||||
m_availableControllers.prepend(controller);
|
||||
setCurrentController(controller);
|
||||
} else {
|
||||
m_availableControllers.insert(1, controller);
|
||||
if (controller->playbackStatus() == Mpris::Playing) {
|
||||
m_otherPlayingControllers.prepend(controller);
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT availableServicesChanged();
|
||||
}
|
||||
|
||||
void MprisManager::onServiceVanished(const QString &service)
|
||||
{
|
||||
QSharedPointer<MprisController> controller = availableController(service);
|
||||
if (!controller.isNull()) {
|
||||
Q_ASSERT(m_availableControllers.contains(controller));
|
||||
m_availableControllers.removeOne(controller);
|
||||
m_otherPlayingControllers.removeOne(controller);
|
||||
}
|
||||
|
||||
if (!m_currentController.isNull() && service == m_currentController->service()) {
|
||||
if (m_singleService) {
|
||||
Q_EMIT availableServicesChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_availableControllers.isEmpty()) {
|
||||
setCurrentController(m_availableControllers[0]);
|
||||
} else {
|
||||
setCurrentController(QSharedPointer<MprisController>());
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT availableServicesChanged();
|
||||
}
|
||||
|
||||
void MprisManager::onAvailableControllerPlaybackStatusChanged(const QString &service)
|
||||
{
|
||||
QSharedPointer<MprisController> controller = availableController(service);
|
||||
Q_ASSERT(!controller.isNull());
|
||||
|
||||
if (m_currentController == controller) {
|
||||
if (m_currentController->playbackStatus() == Mpris::Playing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_otherPlayingControllers.isEmpty()) {
|
||||
QSharedPointer<MprisController> currentController = m_otherPlayingControllers.takeFirst();
|
||||
m_availableControllers.move(m_availableControllers.indexOf(currentController), 0);
|
||||
setCurrentController(currentController);
|
||||
}
|
||||
} else {
|
||||
if (controller->playbackStatus() != Mpris::Playing) {
|
||||
m_otherPlayingControllers.removeOne(controller);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_singleService
|
||||
&& m_currentController->playbackStatus() != Mpris::Playing) {
|
||||
setCurrentController(controller);
|
||||
} else {
|
||||
m_availableControllers.move(m_availableControllers.indexOf(controller), 1);
|
||||
m_otherPlayingControllers.removeOne(controller); // Just in case, shouldn't be needed
|
||||
m_otherPlayingControllers.prepend(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<MprisController> MprisManager::availableController(const QString &service)
|
||||
{
|
||||
QList< QSharedPointer<MprisController> >::iterator i = m_availableControllers.begin();
|
||||
while (i != m_availableControllers.end()) {
|
||||
QSharedPointer<MprisController> controller = *i;
|
||||
if (!controller.isNull() && controller->service() == service) {
|
||||
return controller;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return QSharedPointer<MprisController>();
|
||||
}
|
||||
|
||||
void MprisManager::setCurrentController(QSharedPointer<MprisController> controller)
|
||||
{
|
||||
if (controller == m_currentController) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_currentController.isNull()) {
|
||||
// Mpris Root Interface
|
||||
disconnect(m_currentController.data(), &MprisController::canQuitChanged, this, &MprisManager::canQuitChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canRaiseChanged, this, &MprisManager::canRaiseChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canSetFullscreenChanged, this, &MprisManager::canSetFullscreenChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::desktopEntryChanged, this, &MprisManager::desktopEntryChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::fullscreenChanged, this, &MprisManager::fullscreenChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::hasTrackListChanged, this, &MprisManager::hasTrackListChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::identityChanged, this, &MprisManager::identityChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::supportedUriSchemesChanged, this, &MprisManager::supportedUriSchemesChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::supportedMimeTypesChanged, this, &MprisManager::supportedMimeTypesChanged);
|
||||
|
||||
// Mpris Player Interface
|
||||
disconnect(m_currentController.data(), &MprisController::canControlChanged, this, &MprisManager::canControlChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canGoNextChanged, this, &MprisManager::canGoNextChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canGoPreviousChanged, this, &MprisManager::canGoPreviousChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canPauseChanged, this, &MprisManager::canPauseChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canPlayChanged, this, &MprisManager::canPlayChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::canSeekChanged, this, &MprisManager::canSeekChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::loopStatusChanged, this, &MprisManager::loopStatusChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::maximumRateChanged, this, &MprisManager::maximumRateChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::metadataChanged, this, &MprisManager::metadataChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::minimumRateChanged, this, &MprisManager::minimumRateChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::playbackStatusChanged, this, &MprisManager::playbackStatusChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::positionChanged, this, &MprisManager::positionChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::rateChanged, this, &MprisManager::rateChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::shuffleChanged, this, &MprisManager::shuffleChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::volumeChanged, this, &MprisManager::volumeChanged);
|
||||
disconnect(m_currentController.data(), &MprisController::seeked, this, &MprisManager::seeked);
|
||||
|
||||
if (m_currentController->playbackStatus() == Mpris::Playing) {
|
||||
m_otherPlayingControllers.prepend(m_currentController);
|
||||
}
|
||||
}
|
||||
|
||||
m_currentController = controller;
|
||||
|
||||
if (!m_currentController.isNull()) {
|
||||
// Mpris Root Interface
|
||||
connect(m_currentController.data(), &MprisController::canQuitChanged, this, &MprisManager::canQuitChanged);
|
||||
connect(m_currentController.data(), &MprisController::canRaiseChanged, this, &MprisManager::canRaiseChanged);
|
||||
connect(m_currentController.data(), &MprisController::canSetFullscreenChanged, this, &MprisManager::canSetFullscreenChanged);
|
||||
connect(m_currentController.data(), &MprisController::desktopEntryChanged, this, &MprisManager::desktopEntryChanged);
|
||||
connect(m_currentController.data(), &MprisController::fullscreenChanged, this, &MprisManager::fullscreenChanged);
|
||||
connect(m_currentController.data(), &MprisController::hasTrackListChanged, this, &MprisManager::hasTrackListChanged);
|
||||
connect(m_currentController.data(), &MprisController::identityChanged, this, &MprisManager::identityChanged);
|
||||
connect(m_currentController.data(), &MprisController::supportedUriSchemesChanged, this, &MprisManager::supportedUriSchemesChanged);
|
||||
connect(m_currentController.data(), &MprisController::supportedMimeTypesChanged, this, &MprisManager::supportedMimeTypesChanged);
|
||||
connect(m_currentController.data(), &MprisController::canControlChanged, this, &MprisManager::canControlChanged);
|
||||
|
||||
// Mpris Player Interface
|
||||
connect(m_currentController.data(), &MprisController::canGoNextChanged, this, &MprisManager::canGoNextChanged);
|
||||
connect(m_currentController.data(), &MprisController::canGoPreviousChanged, this, &MprisManager::canGoPreviousChanged);
|
||||
connect(m_currentController.data(), &MprisController::canPauseChanged, this, &MprisManager::canPauseChanged);
|
||||
connect(m_currentController.data(), &MprisController::canPlayChanged, this, &MprisManager::canPlayChanged);
|
||||
connect(m_currentController.data(), &MprisController::canSeekChanged, this, &MprisManager::canSeekChanged);
|
||||
connect(m_currentController.data(), &MprisController::loopStatusChanged, this, &MprisManager::loopStatusChanged);
|
||||
connect(m_currentController.data(), &MprisController::maximumRateChanged, this, &MprisManager::maximumRateChanged);
|
||||
connect(m_currentController.data(), &MprisController::metadataChanged, this, &MprisManager::metadataChanged);
|
||||
connect(m_currentController.data(), &MprisController::minimumRateChanged, this, &MprisManager::minimumRateChanged);
|
||||
connect(m_currentController.data(), &MprisController::playbackStatusChanged, this, &MprisManager::playbackStatusChanged);
|
||||
connect(m_currentController.data(), &MprisController::rateChanged, this, &MprisManager::rateChanged);
|
||||
connect(m_currentController.data(), &MprisController::shuffleChanged, this, &MprisManager::shuffleChanged);
|
||||
connect(m_currentController.data(), &MprisController::volumeChanged, this, &MprisManager::volumeChanged);
|
||||
connect(m_currentController.data(), &MprisController::seeked, this, &MprisManager::seeked);
|
||||
|
||||
if (m_currentController->playbackStatus() == Mpris::Playing) {
|
||||
m_otherPlayingControllers.removeOne(m_currentController);
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT currentServiceChanged();
|
||||
}
|
||||
|
||||
bool MprisManager::checkController(const char *callerName) const
|
||||
{
|
||||
if (m_currentController.isNull()) {
|
||||
qWarning() << callerName << "None service available/selected";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -0,0 +1,221 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MPRISMANAGER_H
|
||||
#define MPRISMANAGER_H
|
||||
|
||||
#include "mprisqt.h"
|
||||
#include "mpris.h"
|
||||
#include "mpriscontroller.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusObjectPath>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
class QSignalMapper;
|
||||
class MPRIS_QT_EXPORT MprisManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool singleService READ singleService WRITE setSingleService NOTIFY singleServiceChanged)
|
||||
Q_PROPERTY(QString currentService READ currentService WRITE setCurrentService NOTIFY currentServiceChanged)
|
||||
Q_PROPERTY(QStringList availableServices READ availableServices NOTIFY availableServicesChanged)
|
||||
|
||||
// Mpris2 Root Interface
|
||||
Q_PROPERTY(bool canQuit READ canQuit NOTIFY canQuitChanged)
|
||||
Q_PROPERTY(bool canRaise READ canRaise NOTIFY canRaiseChanged)
|
||||
Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen NOTIFY canSetFullscreenChanged)
|
||||
Q_PROPERTY(QString desktopEntry READ desktopEntry NOTIFY desktopEntryChanged)
|
||||
Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
|
||||
Q_PROPERTY(bool hasTrackList READ hasTrackList NOTIFY hasTrackListChanged)
|
||||
Q_PROPERTY(QString identity READ identity NOTIFY identityChanged)
|
||||
Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes NOTIFY supportedUriSchemesChanged)
|
||||
Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY supportedMimeTypesChanged)
|
||||
|
||||
// Mpris2 Player Interface
|
||||
Q_PROPERTY(bool canControl READ canControl NOTIFY canControlChanged)
|
||||
Q_PROPERTY(bool canGoNext READ canGoNext NOTIFY canGoNextChanged)
|
||||
Q_PROPERTY(bool canGoPrevious READ canGoPrevious NOTIFY canGoPreviousChanged)
|
||||
Q_PROPERTY(bool canPause READ canPause NOTIFY canPauseChanged)
|
||||
Q_PROPERTY(bool canPlay READ canPlay NOTIFY canPlayChanged)
|
||||
Q_PROPERTY(bool canSeek READ canSeek NOTIFY canSeekChanged)
|
||||
Q_PROPERTY(Mpris::LoopStatus loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged)
|
||||
Q_PROPERTY(double maximumRate READ maximumRate NOTIFY maximumRateChanged)
|
||||
Q_PROPERTY(QVariantMap metadata READ metadata NOTIFY metadataChanged)
|
||||
Q_PROPERTY(double minimumRate READ minimumRate NOTIFY minimumRateChanged)
|
||||
Q_PROPERTY(Mpris::PlaybackStatus playbackStatus READ playbackStatus NOTIFY playbackStatusChanged)
|
||||
Q_PROPERTY(qlonglong position READ position)
|
||||
Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged)
|
||||
Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged)
|
||||
Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
|
||||
public:
|
||||
|
||||
MprisManager(QObject *parent = 0);
|
||||
~MprisManager();
|
||||
|
||||
// Mpris2 Root Interface
|
||||
Q_INVOKABLE bool quit() const;
|
||||
Q_INVOKABLE bool raise() const;
|
||||
|
||||
// Mpris2 Player Interface
|
||||
Q_INVOKABLE bool next() const;
|
||||
Q_INVOKABLE bool openUri(const QUrl &uri) const;
|
||||
Q_INVOKABLE bool pause() const;
|
||||
Q_INVOKABLE bool play() const;
|
||||
Q_INVOKABLE bool playPause() const;
|
||||
Q_INVOKABLE bool previous() const;
|
||||
Q_INVOKABLE bool seek(qlonglong offset) const;
|
||||
Q_INVOKABLE bool setPosition(qlonglong position) const;
|
||||
Q_INVOKABLE bool setPosition(const QString &trackId, qlonglong position) const;
|
||||
Q_INVOKABLE bool stop() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
bool singleService() const;
|
||||
void setSingleService(bool single);
|
||||
|
||||
QString currentService() const;
|
||||
void setCurrentService(const QString &service);
|
||||
|
||||
QStringList availableServices() const;
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool canQuit() const;
|
||||
|
||||
bool canRaise() const;
|
||||
|
||||
bool canSetFullscreen() const;
|
||||
|
||||
QString desktopEntry() const;
|
||||
|
||||
bool fullscreen() const;
|
||||
void setFullscreen(bool fullscreen);
|
||||
|
||||
bool hasTrackList() const;
|
||||
|
||||
QString identity() const;
|
||||
|
||||
QStringList supportedUriSchemes() const;
|
||||
|
||||
QStringList supportedMimeTypes() const;
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool canControl() const;
|
||||
|
||||
bool canGoNext() const;
|
||||
|
||||
bool canGoPrevious() const;
|
||||
|
||||
bool canPause() const;
|
||||
|
||||
bool canPlay() const;
|
||||
|
||||
bool canSeek() const;
|
||||
|
||||
Mpris::LoopStatus loopStatus() const;
|
||||
void setLoopStatus(Mpris::LoopStatus loopStatus);
|
||||
|
||||
double maximumRate() const;
|
||||
|
||||
QVariantMap metadata() const;
|
||||
|
||||
double minimumRate() const;
|
||||
|
||||
Mpris::PlaybackStatus playbackStatus() const;
|
||||
|
||||
qlonglong position() const;
|
||||
void requestPosition() const;
|
||||
|
||||
double rate() const;
|
||||
void setRate(double rate);
|
||||
|
||||
bool shuffle() const;
|
||||
void setShuffle(bool shuffle);
|
||||
|
||||
double volume() const;
|
||||
void setVolume(double volume);
|
||||
|
||||
Q_SIGNALS:
|
||||
void singleServiceChanged();
|
||||
void currentServiceChanged();
|
||||
void availableServicesChanged();
|
||||
|
||||
// Mpris2 Root Interface
|
||||
void canQuitChanged();
|
||||
void canRaiseChanged();
|
||||
void canSetFullscreenChanged();
|
||||
void desktopEntryChanged();
|
||||
void fullscreenChanged();
|
||||
void hasTrackListChanged();
|
||||
void identityChanged();
|
||||
void supportedUriSchemesChanged();
|
||||
void supportedMimeTypesChanged();
|
||||
|
||||
// Mpris2 Player Interface
|
||||
void canControlChanged();
|
||||
void canGoNextChanged();
|
||||
void canGoPreviousChanged();
|
||||
void canPauseChanged();
|
||||
void canPlayChanged();
|
||||
void canSeekChanged();
|
||||
void loopStatusChanged();
|
||||
void maximumRateChanged();
|
||||
void metadataChanged();
|
||||
void minimumRateChanged();
|
||||
void playbackStatusChanged();
|
||||
void positionChanged(qlonglong position);
|
||||
void rateChanged();
|
||||
void shuffleChanged();
|
||||
void volumeChanged();
|
||||
void seeked(qlonglong position);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onNameOwnerChanged(const QString &service, const QString &oldOwner, const QString& newOwner);
|
||||
void onServiceAppeared(const QString &service);
|
||||
void onServiceVanished(const QString &service);
|
||||
void onAvailableControllerPlaybackStatusChanged(const QString &service);
|
||||
|
||||
private:
|
||||
QSharedPointer<MprisController> availableController(const QString &service);
|
||||
void setCurrentController(QSharedPointer<MprisController> controller);
|
||||
bool checkController(const char *callerName) const;
|
||||
|
||||
bool m_singleService;
|
||||
QSharedPointer<MprisController> m_currentController;
|
||||
QList< QSharedPointer<MprisController> > m_availableControllers;
|
||||
QList< QSharedPointer<MprisController> > m_otherPlayingControllers;
|
||||
QSignalMapper *m_playbackStatusMapper;
|
||||
};
|
||||
|
||||
#endif /* MPRISMANAGER_H */
|
||||
@ -0,0 +1,590 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mprisplayer.h"
|
||||
|
||||
#include "mprisplayer_p.h"
|
||||
|
||||
#include <qqmlinfo.h>
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QDBusReply>
|
||||
|
||||
static const QString serviceNamePrefix = QStringLiteral("org.mpris.MediaPlayer2.");
|
||||
static const QString mprisObjectPath = QStringLiteral("/org/mpris/MediaPlayer2");
|
||||
static const QString dBusPropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties");
|
||||
static const QString dBusPropertiesChangedSignal = QStringLiteral("PropertiesChanged");
|
||||
|
||||
static inline QDBusConnection getDBusConnection()
|
||||
{
|
||||
#ifdef USE_SYSTEM_DBUS
|
||||
return QDBusConnection::systemBus();
|
||||
#else
|
||||
return QDBusConnection::sessionBus();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
MprisPlayer::MprisPlayer(QObject *parent)
|
||||
: QObject(parent)
|
||||
, QDBusContext()
|
||||
, m_mprisRootAdaptor(new MprisRootAdaptor(this))
|
||||
, m_mprisPlayerAdaptor(new MprisPlayerAdaptor(this))
|
||||
, m_canQuit(false)
|
||||
, m_canRaise(false)
|
||||
, m_canSetFullscreen(false)
|
||||
, m_fullscreen(false)
|
||||
, m_hasTrackList(false)
|
||||
, m_canControl(false)
|
||||
, m_canGoNext(false)
|
||||
, m_canGoPrevious(false)
|
||||
, m_canPause(false)
|
||||
, m_canPlay(false)
|
||||
, m_canSeek(false)
|
||||
, m_loopStatus(Mpris::None)
|
||||
, m_maximumRate(1)
|
||||
, m_minimumRate(1)
|
||||
, m_playbackStatus(Mpris::Stopped)
|
||||
, m_position(0)
|
||||
, m_rate(1)
|
||||
, m_shuffle(false)
|
||||
, m_volume(0)
|
||||
{
|
||||
QDBusConnection connection = getDBusConnection();
|
||||
|
||||
if (!connection.isConnected()) {
|
||||
qmlInfo(this) << "Failed attempting to connect to DBus";
|
||||
} else if (!connection.registerObject(mprisObjectPath, this)) {
|
||||
qmlInfo(this) << "Failed attempting to register object path. Already registered?";
|
||||
}
|
||||
}
|
||||
|
||||
MprisPlayer::~MprisPlayer()
|
||||
{
|
||||
unregisterService();
|
||||
}
|
||||
|
||||
QString MprisPlayer::serviceName() const
|
||||
{
|
||||
return m_serviceName;
|
||||
}
|
||||
|
||||
void MprisPlayer::setServiceName(const QString &serviceName)
|
||||
{
|
||||
if (m_serviceName == serviceName) {
|
||||
return;
|
||||
}
|
||||
|
||||
unregisterService();
|
||||
m_serviceName = serviceName;
|
||||
registerService();
|
||||
|
||||
Q_EMIT serviceNameChanged();
|
||||
}
|
||||
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool MprisPlayer::canQuit() const
|
||||
{
|
||||
return m_canQuit;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanQuit(bool canQuit)
|
||||
{
|
||||
if (m_canQuit == canQuit) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canQuit = canQuit;
|
||||
Q_EMIT canQuitChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canRaise() const
|
||||
{
|
||||
return m_canRaise;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanRaise(bool canRaise)
|
||||
{
|
||||
if (m_canRaise == canRaise) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canRaise = canRaise;
|
||||
Q_EMIT canRaiseChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canSetFullscreen() const
|
||||
{
|
||||
return m_canSetFullscreen;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanSetFullscreen(bool canSetFullscreen)
|
||||
{
|
||||
if (m_canSetFullscreen == canSetFullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canSetFullscreen = canSetFullscreen;
|
||||
Q_EMIT canSetFullscreenChanged();
|
||||
}
|
||||
|
||||
QString MprisPlayer::desktopEntry() const
|
||||
{
|
||||
return m_desktopEntry;
|
||||
}
|
||||
|
||||
void MprisPlayer::setDesktopEntry(const QString &desktopEntry)
|
||||
{
|
||||
if (m_desktopEntry == desktopEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_desktopEntry = desktopEntry;
|
||||
Q_EMIT desktopEntryChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::fullscreen() const
|
||||
{
|
||||
return m_fullscreen;
|
||||
}
|
||||
|
||||
void MprisPlayer::setFullscreen(bool fullscreen)
|
||||
{
|
||||
if (m_fullscreen == fullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_fullscreen = fullscreen;
|
||||
Q_EMIT fullscreenChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::hasTrackList() const
|
||||
{
|
||||
return m_hasTrackList;
|
||||
}
|
||||
|
||||
void MprisPlayer::setHasTrackList(bool hasTrackList)
|
||||
{
|
||||
if (m_hasTrackList == hasTrackList) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasTrackList = hasTrackList;
|
||||
Q_EMIT hasTrackListChanged();
|
||||
}
|
||||
|
||||
QString MprisPlayer::identity() const
|
||||
{
|
||||
return m_identity;
|
||||
}
|
||||
|
||||
void MprisPlayer::setIdentity(const QString &identity)
|
||||
{
|
||||
if (m_identity == identity) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_identity = identity;
|
||||
Q_EMIT identityChanged();
|
||||
}
|
||||
|
||||
QStringList MprisPlayer::supportedUriSchemes() const
|
||||
{
|
||||
return m_supportedUriSchemes;
|
||||
}
|
||||
|
||||
void MprisPlayer::setSupportedUriSchemes(const QStringList &supportedUriSchemes)
|
||||
{
|
||||
if (m_supportedUriSchemes == supportedUriSchemes) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_supportedUriSchemes = supportedUriSchemes;
|
||||
Q_EMIT supportedUriSchemesChanged();
|
||||
}
|
||||
|
||||
QStringList MprisPlayer::supportedMimeTypes() const
|
||||
{
|
||||
return m_supportedMimeTypes;
|
||||
}
|
||||
|
||||
void MprisPlayer::setSupportedMimeTypes(const QStringList &supportedMimeTypes)
|
||||
{
|
||||
if (m_supportedMimeTypes == supportedMimeTypes) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_supportedMimeTypes = supportedMimeTypes;
|
||||
Q_EMIT supportedMimeTypesChanged();
|
||||
}
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool MprisPlayer::canControl() const
|
||||
{
|
||||
return m_canControl;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanControl(bool canControl)
|
||||
{
|
||||
if (m_canControl == canControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canControl = canControl;
|
||||
Q_EMIT canControlChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canGoNext() const
|
||||
{
|
||||
return m_canGoNext;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanGoNext(bool canGoNext)
|
||||
{
|
||||
if (m_canGoNext == canGoNext) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canGoNext = canGoNext;
|
||||
Q_EMIT canGoNextChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canGoPrevious() const
|
||||
{
|
||||
return m_canGoPrevious;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanGoPrevious(bool canGoPrevious)
|
||||
{
|
||||
if (m_canGoPrevious == canGoPrevious) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canGoPrevious = canGoPrevious;
|
||||
Q_EMIT canGoPreviousChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canPause() const
|
||||
{
|
||||
return m_canPause;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanPause(bool canPause)
|
||||
{
|
||||
if (m_canPause == canPause) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canPause = canPause;
|
||||
Q_EMIT canPauseChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canPlay() const
|
||||
{
|
||||
return m_canPlay;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanPlay(bool canPlay)
|
||||
{
|
||||
if (m_canPlay == canPlay) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canPlay = canPlay;
|
||||
Q_EMIT canPlayChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::canSeek() const
|
||||
{
|
||||
return m_canSeek;
|
||||
}
|
||||
|
||||
void MprisPlayer::setCanSeek(bool canSeek)
|
||||
{
|
||||
if (m_canSeek == canSeek) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canSeek = canSeek;
|
||||
Q_EMIT canSeekChanged();
|
||||
}
|
||||
|
||||
Mpris::LoopStatus MprisPlayer::loopStatus() const
|
||||
{
|
||||
return m_loopStatus;
|
||||
}
|
||||
|
||||
void MprisPlayer::setLoopStatus(Mpris::LoopStatus loopStatus)
|
||||
{
|
||||
if (m_loopStatus == loopStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_loopStatus = loopStatus;
|
||||
Q_EMIT loopStatusChanged();
|
||||
}
|
||||
|
||||
double MprisPlayer::maximumRate() const
|
||||
{
|
||||
return m_maximumRate;
|
||||
}
|
||||
|
||||
void MprisPlayer::setMaximumRate(double maximumRate)
|
||||
{
|
||||
if (m_maximumRate == maximumRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_maximumRate = maximumRate;
|
||||
Q_EMIT maximumRateChanged();
|
||||
}
|
||||
|
||||
QVariantMap MprisPlayer::metadata() const
|
||||
{
|
||||
return m_typedMetadata;
|
||||
}
|
||||
|
||||
void MprisPlayer::setMetadata(const QVariantMap &metadata)
|
||||
{
|
||||
if (m_metadata == metadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_metadata = metadata;
|
||||
m_typedMetadata = typeMetadata(metadata);
|
||||
Q_EMIT metadataChanged();
|
||||
}
|
||||
|
||||
double MprisPlayer::minimumRate() const
|
||||
{
|
||||
return m_minimumRate;
|
||||
}
|
||||
|
||||
void MprisPlayer::setMinimumRate(double minimumRate)
|
||||
{
|
||||
if (m_minimumRate == minimumRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_minimumRate = minimumRate;
|
||||
Q_EMIT minimumRateChanged();
|
||||
}
|
||||
|
||||
Mpris::PlaybackStatus MprisPlayer::playbackStatus() const
|
||||
{
|
||||
return m_playbackStatus;
|
||||
}
|
||||
|
||||
void MprisPlayer::setPlaybackStatus(Mpris::PlaybackStatus playbackStatus)
|
||||
{
|
||||
if (m_playbackStatus == playbackStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_playbackStatus = playbackStatus;
|
||||
Q_EMIT playbackStatusChanged();
|
||||
}
|
||||
|
||||
qlonglong MprisPlayer::position() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
void MprisPlayer::setPosition(qlonglong position)
|
||||
{
|
||||
if (m_position == position) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_position = position;
|
||||
Q_EMIT positionChanged();
|
||||
}
|
||||
|
||||
double MprisPlayer::rate() const
|
||||
{
|
||||
return m_rate;
|
||||
}
|
||||
|
||||
void MprisPlayer::setRate(double rate)
|
||||
{
|
||||
if (m_rate == rate) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_rate = rate;
|
||||
Q_EMIT rateChanged();
|
||||
}
|
||||
|
||||
bool MprisPlayer::shuffle() const
|
||||
{
|
||||
return m_shuffle;
|
||||
}
|
||||
|
||||
void MprisPlayer::setShuffle(bool shuffle)
|
||||
{
|
||||
if (m_shuffle == shuffle) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shuffle= shuffle;
|
||||
Q_EMIT shuffleChanged();
|
||||
}
|
||||
|
||||
double MprisPlayer::volume() const
|
||||
{
|
||||
return m_volume;
|
||||
}
|
||||
|
||||
void MprisPlayer::setVolume(double volume)
|
||||
{
|
||||
if (m_volume == volume) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_volume = volume;
|
||||
Q_EMIT volumeChanged();
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
|
||||
QVariantMap MprisPlayer::typeMetadata(const QVariantMap &aMetadata)
|
||||
{
|
||||
QVariantMap metadata;
|
||||
QVariantMap::const_iterator i = aMetadata.constBegin();
|
||||
while (i != aMetadata.constEnd()) {
|
||||
switch (Mpris::enumerationFromString<Mpris::Metadata>(i.key())) {
|
||||
case Mpris::TrackId:
|
||||
metadata.insert(i.key(), QVariant::fromValue(QDBusObjectPath(i.value().toString())));
|
||||
break;
|
||||
case Mpris::Length:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toLongLong()));
|
||||
break;
|
||||
case Mpris::ArtUrl:
|
||||
case Mpris::Url:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toUrl().toString()));
|
||||
break;
|
||||
case Mpris::Album:
|
||||
case Mpris::AsText:
|
||||
case Mpris::Title:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toString()));
|
||||
break;
|
||||
case Mpris::AlbumArtist:
|
||||
case Mpris::Artist:
|
||||
case Mpris::Comment:
|
||||
case Mpris::Composer:
|
||||
case Mpris::Genre:
|
||||
case Mpris::Lyricist:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toStringList()));
|
||||
break;
|
||||
case Mpris::AudioBPM:
|
||||
case Mpris::DiscNumber:
|
||||
case Mpris::TrackNumber:
|
||||
case Mpris::UseCount:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toInt()));
|
||||
break;
|
||||
case Mpris::AutoRating:
|
||||
case Mpris::UserRating:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toFloat()));
|
||||
break;
|
||||
case Mpris::ContentCreated:
|
||||
case Mpris::FirstUsed:
|
||||
case Mpris::LastUsed:
|
||||
metadata.insert(i.key(), QVariant::fromValue(i.value().toDate().toString(Qt::ISODate)));
|
||||
break;
|
||||
case Mpris::InvalidMetadata:
|
||||
// Passing with the original type and hoping the user used
|
||||
// a type supported by DBus
|
||||
metadata.insert(i.key(), i.value());
|
||||
break;
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
void MprisPlayer::registerService()
|
||||
{
|
||||
if (m_serviceName.isEmpty()) {
|
||||
qmlInfo(this) << "Failed to register service: empty service name";
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusConnection connection = getDBusConnection();
|
||||
|
||||
if (!connection.isConnected()) {
|
||||
qmlInfo(this) << "Failed attempting to connect to DBus";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connection.registerService(QString(serviceNamePrefix).append(m_serviceName))) {
|
||||
qmlInfo(this) << "Failed attempting to register service: " << m_serviceName << " Already taken?";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void MprisPlayer::unregisterService()
|
||||
{
|
||||
if (!m_serviceName.isEmpty()) {
|
||||
QDBusConnection connection = getDBusConnection();
|
||||
connection.unregisterService(QString(serviceNamePrefix).append(m_serviceName));
|
||||
}
|
||||
}
|
||||
|
||||
void MprisPlayer::notifyPropertiesChanged(const QString& interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) const
|
||||
{
|
||||
if (m_serviceName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusConnection connection = getDBusConnection();
|
||||
|
||||
if (!connection.isConnected()) {
|
||||
qmlInfo(this) << "Failed attempting to connect to DBus";
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusMessage message = QDBusMessage::createSignal(mprisObjectPath,
|
||||
dBusPropertiesInterface,
|
||||
dBusPropertiesChangedSignal);
|
||||
|
||||
QList<QVariant> arguments;
|
||||
arguments << QVariant(interfaceName) << QVariant(changedProperties) << QVariant(invalidatedProperties);
|
||||
message.setArguments(arguments);
|
||||
|
||||
if (!connection.send(message)) {
|
||||
qmlInfo(this) << "Failed to send DBus property notification signal";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,250 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MPRISPLAYER_H
|
||||
#define MPRISPLAYER_H
|
||||
|
||||
#include "mprisqt.h"
|
||||
#include "mpris.h"
|
||||
|
||||
#include <QDBusContext>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QDBusObjectPath>
|
||||
|
||||
|
||||
class MprisRootAdaptor;
|
||||
class MprisPlayerAdaptor;
|
||||
class MPRIS_QT_EXPORT MprisPlayer : public QObject,
|
||||
protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString serviceName READ serviceName WRITE setServiceName NOTIFY serviceNameChanged)
|
||||
|
||||
// Mpris2 Root Interface
|
||||
Q_PROPERTY(bool canQuit READ canQuit WRITE setCanQuit NOTIFY canQuitChanged)
|
||||
Q_PROPERTY(bool canRaise READ canRaise WRITE setCanRaise NOTIFY canRaiseChanged)
|
||||
Q_PROPERTY(bool canSetFullscreen READ canSetFullscreen WRITE setCanSetFullscreen NOTIFY canSetFullscreenChanged)
|
||||
Q_PROPERTY(QString desktopEntry READ desktopEntry WRITE setDesktopEntry NOTIFY desktopEntryChanged)
|
||||
Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
|
||||
Q_PROPERTY(bool hasTrackList READ hasTrackList WRITE setHasTrackList NOTIFY hasTrackListChanged)
|
||||
Q_PROPERTY(QString identity READ identity WRITE setIdentity NOTIFY identityChanged)
|
||||
Q_PROPERTY(QStringList supportedUriSchemes READ supportedUriSchemes WRITE setSupportedUriSchemes NOTIFY supportedUriSchemesChanged)
|
||||
Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes WRITE setSupportedMimeTypes NOTIFY supportedMimeTypesChanged)
|
||||
|
||||
// Mpris2 Player Interface
|
||||
Q_PROPERTY(bool canControl READ canControl WRITE setCanControl NOTIFY canControlChanged)
|
||||
Q_PROPERTY(bool canGoNext READ canGoNext WRITE setCanGoNext NOTIFY canGoNextChanged)
|
||||
Q_PROPERTY(bool canGoPrevious READ canGoPrevious WRITE setCanGoPrevious NOTIFY canGoPreviousChanged)
|
||||
Q_PROPERTY(bool canPause READ canPause WRITE setCanPause NOTIFY canPauseChanged)
|
||||
Q_PROPERTY(bool canPlay READ canPlay WRITE setCanPlay NOTIFY canPlayChanged)
|
||||
Q_PROPERTY(bool canSeek READ canSeek WRITE setCanSeek NOTIFY canSeekChanged)
|
||||
Q_PROPERTY(Mpris::LoopStatus loopStatus READ loopStatus WRITE setLoopStatus NOTIFY loopStatusChanged)
|
||||
Q_PROPERTY(double maximumRate READ maximumRate WRITE setMaximumRate NOTIFY maximumRateChanged)
|
||||
Q_PROPERTY(QVariantMap metadata READ metadata WRITE setMetadata NOTIFY metadataChanged)
|
||||
Q_PROPERTY(double minimumRate READ minimumRate WRITE setMinimumRate NOTIFY minimumRateChanged)
|
||||
Q_PROPERTY(Mpris::PlaybackStatus playbackStatus READ playbackStatus WRITE setPlaybackStatus NOTIFY playbackStatusChanged)
|
||||
Q_PROPERTY(qlonglong position READ position WRITE setPosition NOTIFY positionChanged)
|
||||
Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged)
|
||||
Q_PROPERTY(bool shuffle READ shuffle WRITE setShuffle NOTIFY shuffleChanged)
|
||||
Q_PROPERTY(double volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
|
||||
public:
|
||||
|
||||
MprisPlayer(QObject *parent = 0);
|
||||
~MprisPlayer();
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
QString serviceName() const;
|
||||
void setServiceName(const QString &serviceName);
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool canQuit() const;
|
||||
void setCanQuit(bool canQuit);
|
||||
|
||||
bool canRaise() const;
|
||||
void setCanRaise(bool canRaise);
|
||||
|
||||
bool canSetFullscreen() const;
|
||||
void setCanSetFullscreen(bool canSetFullscreen);
|
||||
|
||||
QString desktopEntry() const;
|
||||
void setDesktopEntry(const QString &desktopEntry);
|
||||
|
||||
bool fullscreen() const;
|
||||
void setFullscreen(bool fullscreen);
|
||||
|
||||
bool hasTrackList() const;
|
||||
void setHasTrackList(bool hasTrackList);
|
||||
|
||||
QString identity() const;
|
||||
void setIdentity(const QString &identity);
|
||||
|
||||
QStringList supportedUriSchemes() const;
|
||||
void setSupportedUriSchemes(const QStringList &supportedUriSchemes);
|
||||
|
||||
QStringList supportedMimeTypes() const;
|
||||
void setSupportedMimeTypes(const QStringList &supportedMimeTypes);
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool canControl() const;
|
||||
void setCanControl(bool canControl);
|
||||
|
||||
bool canGoNext() const;
|
||||
void setCanGoNext(bool canGoNext);
|
||||
|
||||
bool canGoPrevious() const;
|
||||
void setCanGoPrevious(bool canGoPrevious);
|
||||
|
||||
bool canPause() const;
|
||||
void setCanPause(bool canPause);
|
||||
|
||||
bool canPlay() const;
|
||||
void setCanPlay(bool canPlay);
|
||||
|
||||
bool canSeek() const;
|
||||
void setCanSeek(bool canSeek);
|
||||
|
||||
Mpris::LoopStatus loopStatus() const;
|
||||
void setLoopStatus(Mpris::LoopStatus loopStatus);
|
||||
|
||||
double maximumRate() const;
|
||||
void setMaximumRate(double maximumRate);
|
||||
|
||||
QVariantMap metadata() const;
|
||||
void setMetadata(const QVariantMap &metadata);
|
||||
|
||||
double minimumRate() const;
|
||||
void setMinimumRate(double minimumRate);
|
||||
|
||||
Mpris::PlaybackStatus playbackStatus() const;
|
||||
void setPlaybackStatus(Mpris::PlaybackStatus playbackStatus);
|
||||
|
||||
qlonglong position() const;
|
||||
void setPosition(qlonglong position);
|
||||
|
||||
double rate() const;
|
||||
void setRate(double rate);
|
||||
|
||||
bool shuffle() const;
|
||||
void setShuffle(bool shuffle);
|
||||
|
||||
double volume() const;
|
||||
void setVolume(double volume);
|
||||
|
||||
Q_SIGNALS:
|
||||
void serviceNameChanged();
|
||||
|
||||
// Mpris2 Root Interface
|
||||
void canQuitChanged();
|
||||
void canRaiseChanged();
|
||||
void canSetFullscreenChanged();
|
||||
void desktopEntryChanged();
|
||||
void fullscreenChanged();
|
||||
void hasTrackListChanged();
|
||||
void identityChanged();
|
||||
void supportedUriSchemesChanged();
|
||||
void supportedMimeTypesChanged();
|
||||
void fullscreenRequested(bool fullscreen);
|
||||
void quitRequested();
|
||||
void raiseRequested();
|
||||
|
||||
// Mpris2 Player Interface
|
||||
void canControlChanged();
|
||||
void canGoNextChanged();
|
||||
void canGoPreviousChanged();
|
||||
void canPauseChanged();
|
||||
void canPlayChanged();
|
||||
void canSeekChanged();
|
||||
void loopStatusChanged();
|
||||
void maximumRateChanged();
|
||||
void metadataChanged();
|
||||
void minimumRateChanged();
|
||||
void playbackStatusChanged();
|
||||
void positionChanged();
|
||||
void rateChanged();
|
||||
void shuffleChanged();
|
||||
void volumeChanged();
|
||||
void loopStatusRequested(Mpris::LoopStatus loopStatus);
|
||||
void rateRequested(double rate);
|
||||
void shuffleRequested(bool shuffle);
|
||||
void volumeRequested(double volume);
|
||||
void nextRequested();
|
||||
void openUriRequested(const QUrl &url);
|
||||
void pauseRequested();
|
||||
void playRequested();
|
||||
void playPauseRequested();
|
||||
void previousRequested();
|
||||
void seekRequested(qlonglong offset);
|
||||
void seeked(qlonglong position);
|
||||
void setPositionRequested(const QDBusObjectPath &trackId, qlonglong position);
|
||||
void stopRequested();
|
||||
|
||||
private:
|
||||
static QVariantMap typeMetadata(const QVariantMap &aMetadata);
|
||||
|
||||
void registerService();
|
||||
void unregisterService();
|
||||
void notifyPropertiesChanged(const QString& interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) const;
|
||||
|
||||
MprisRootAdaptor *m_mprisRootAdaptor;
|
||||
MprisPlayerAdaptor *m_mprisPlayerAdaptor;
|
||||
|
||||
QString m_serviceName;
|
||||
|
||||
// Mpris2 Root Interface
|
||||
bool m_canQuit;
|
||||
bool m_canRaise;
|
||||
bool m_canSetFullscreen;
|
||||
QString m_desktopEntry;
|
||||
bool m_fullscreen;
|
||||
bool m_hasTrackList;
|
||||
QString m_identity;
|
||||
QStringList m_supportedUriSchemes;
|
||||
QStringList m_supportedMimeTypes;
|
||||
|
||||
// Mpris2 Player Interface
|
||||
bool m_canControl;
|
||||
bool m_canGoNext;
|
||||
bool m_canGoPrevious;
|
||||
bool m_canPause;
|
||||
bool m_canPlay;
|
||||
bool m_canSeek;
|
||||
Mpris::LoopStatus m_loopStatus;
|
||||
double m_maximumRate;
|
||||
QVariantMap m_metadata;
|
||||
QVariantMap m_typedMetadata;
|
||||
double m_minimumRate;
|
||||
Mpris::PlaybackStatus m_playbackStatus;
|
||||
qlonglong m_position;
|
||||
double m_rate;
|
||||
bool m_shuffle;
|
||||
double m_volume;
|
||||
|
||||
friend class MprisRootAdaptor;
|
||||
friend class MprisPlayerAdaptor;
|
||||
};
|
||||
|
||||
#endif /* MPRISPLAYER_H */
|
||||
@ -0,0 +1,264 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// 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 MPRISPLAYER_P_H
|
||||
#define MPRISPLAYER_P_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtDBus/QtDBus>
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QByteArray;
|
||||
template<class T> class QList;
|
||||
template<class Key, class Value> class QMap;
|
||||
class QString;
|
||||
class QStringList;
|
||||
class QVariant;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
||||
class MprisPlayer;
|
||||
|
||||
/*
|
||||
* Adaptor class for interface org.mpris.MediaPlayer2
|
||||
*/
|
||||
class MprisRootAdaptor: public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2")
|
||||
Q_CLASSINFO("D-Bus Introspection", ""
|
||||
" <interface name=\"org.mpris.MediaPlayer2\">\n"
|
||||
" <method name=\"Raise\"/>\n"
|
||||
" <method name=\"Quit\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanQuit\"/>\n"
|
||||
" <property access=\"readwrite\" type=\"b\" name=\"Fullscreen\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanSetFullscreen\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanRaise\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"HasTrackList\"/>\n"
|
||||
" <property access=\"read\" type=\"s\" name=\"Identity\"/>\n"
|
||||
" <property access=\"read\" type=\"s\" name=\"DesktopEntry\"/>\n"
|
||||
" <property access=\"read\" type=\"as\" name=\"SupportedUriSchemes\"/>\n"
|
||||
" <property access=\"read\" type=\"as\" name=\"SupportedMimeTypes\"/>\n"
|
||||
" </interface>\n"
|
||||
"")
|
||||
public:
|
||||
MprisRootAdaptor(MprisPlayer *parent);
|
||||
virtual ~MprisRootAdaptor();
|
||||
|
||||
public: // PROPERTIES
|
||||
Q_PROPERTY(bool CanQuit READ canQuit)
|
||||
bool canQuit() const;
|
||||
|
||||
Q_PROPERTY(bool CanRaise READ canRaise)
|
||||
bool canRaise() const;
|
||||
|
||||
Q_PROPERTY(bool CanSetFullscreen READ canSetFullscreen)
|
||||
bool canSetFullscreen() const;
|
||||
|
||||
Q_PROPERTY(QString DesktopEntry READ desktopEntry)
|
||||
QString desktopEntry() const;
|
||||
|
||||
Q_PROPERTY(bool Fullscreen READ fullscreen WRITE setFullscreen)
|
||||
bool fullscreen() const;
|
||||
void setFullscreen(bool value);
|
||||
|
||||
Q_PROPERTY(bool HasTrackList READ hasTrackList)
|
||||
bool hasTrackList() const;
|
||||
|
||||
Q_PROPERTY(QString Identity READ identity)
|
||||
QString identity() const;
|
||||
|
||||
Q_PROPERTY(QStringList SupportedMimeTypes READ supportedMimeTypes)
|
||||
QStringList supportedMimeTypes() const;
|
||||
|
||||
Q_PROPERTY(QStringList SupportedUriSchemes READ supportedUriSchemes)
|
||||
QStringList supportedUriSchemes() const;
|
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
void Quit();
|
||||
void Raise();
|
||||
Q_SIGNALS: // SIGNALS
|
||||
private Q_SLOTS:
|
||||
void onCanQuitChanged() const;
|
||||
void onCanRaiseChanged() const;
|
||||
void onCanSetFullscreenChanged() const;
|
||||
void onDesktopEntryChanged() const;
|
||||
void onFullscreenChanged() const;
|
||||
void onHasTrackListChanged() const;
|
||||
void onIdentityChanged() const;
|
||||
void onSupportedUriSchemesChanged() const;
|
||||
void onSupportedMimeTypesChanged() const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Adaptor class for interface org.mpris.MediaPlayer2.Player
|
||||
*/
|
||||
class MprisPlayerAdaptor: public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.mpris.MediaPlayer2.Player")
|
||||
Q_CLASSINFO("D-Bus Introspection", ""
|
||||
" <interface name=\"org.mpris.MediaPlayer2.Player\">\n"
|
||||
" <method name=\"Next\"/>\n"
|
||||
" <method name=\"Previous\"/>\n"
|
||||
" <method name=\"Pause\"/>\n"
|
||||
" <method name=\"PlayPause\"/>\n"
|
||||
" <method name=\"Stop\"/>\n"
|
||||
" <method name=\"Play\"/>\n"
|
||||
" <method name=\"Seek\">\n"
|
||||
" <arg direction=\"in\" type=\"x\" name=\"Offset\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"SetPosition\">\n"
|
||||
" <arg direction=\"in\" type=\"o\" name=\"TrackId\"/>\n"
|
||||
" <arg direction=\"in\" type=\"x\" name=\"Position\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"OpenUri\">\n"
|
||||
" <arg direction=\"in\" type=\"s\" name=\"Uri\"/>\n"
|
||||
" <annotation value=\"QUrl\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
|
||||
" </method>\n"
|
||||
" <signal name=\"Seeked\">\n"
|
||||
" <arg direction=\"out\" type=\"x\" name=\"Position\"/>\n"
|
||||
" </signal>\n"
|
||||
" <property access=\"read\" type=\"s\" name=\"PlaybackStatus\"/>\n"
|
||||
" <property access=\"readwrite\" type=\"s\" name=\"LoopStatus\"/>\n"
|
||||
" <property access=\"readwrite\" type=\"d\" name=\"Rate\"/>\n"
|
||||
" <property access=\"readwrite\" type=\"b\" name=\"Shuffle\"/>\n"
|
||||
" <property access=\"read\" type=\"a{sv}\" name=\"Metadata\">\n"
|
||||
" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
|
||||
" </property>\n"
|
||||
" <property access=\"readwrite\" type=\"d\" name=\"Volume\"/>\n"
|
||||
" <property access=\"read\" type=\"x\" name=\"Position\">\n"
|
||||
" <annotation value=\"false\" name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\"/>\n"
|
||||
" </property>\n"
|
||||
" <property access=\"read\" type=\"d\" name=\"MinimumRate\"/>\n"
|
||||
" <property access=\"read\" type=\"d\" name=\"MaximumRate\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanGoNext\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanGoPrevious\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanPlay\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanPause\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanSeek\"/>\n"
|
||||
" <property access=\"read\" type=\"b\" name=\"CanControl\">\n"
|
||||
" <annotation value=\"false\" name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\"/>\n"
|
||||
" </property>\n"
|
||||
" </interface>\n"
|
||||
"")
|
||||
|
||||
public:
|
||||
MprisPlayerAdaptor(MprisPlayer *parent);
|
||||
virtual ~MprisPlayerAdaptor();
|
||||
|
||||
public: // PROPERTIES
|
||||
Q_PROPERTY(bool CanControl READ canControl)
|
||||
bool canControl() const;
|
||||
|
||||
Q_PROPERTY(bool CanGoNext READ canGoNext)
|
||||
bool canGoNext() const;
|
||||
|
||||
Q_PROPERTY(bool CanGoPrevious READ canGoPrevious)
|
||||
bool canGoPrevious() const;
|
||||
|
||||
Q_PROPERTY(bool CanPause READ canPause)
|
||||
bool canPause() const;
|
||||
|
||||
Q_PROPERTY(bool CanPlay READ canPlay)
|
||||
bool canPlay() const;
|
||||
|
||||
Q_PROPERTY(bool CanSeek READ canSeek)
|
||||
bool canSeek() const;
|
||||
|
||||
Q_PROPERTY(QString LoopStatus READ loopStatus WRITE setLoopStatus)
|
||||
QString loopStatus() const;
|
||||
void setLoopStatus(const QString &value);
|
||||
|
||||
Q_PROPERTY(double MaximumRate READ maximumRate)
|
||||
double maximumRate() const;
|
||||
|
||||
Q_PROPERTY(QVariantMap Metadata READ metadata)
|
||||
QVariantMap metadata() const;
|
||||
|
||||
Q_PROPERTY(double MinimumRate READ minimumRate)
|
||||
double minimumRate() const;
|
||||
|
||||
Q_PROPERTY(QString PlaybackStatus READ playbackStatus)
|
||||
QString playbackStatus() const;
|
||||
|
||||
Q_PROPERTY(qlonglong Position READ position)
|
||||
qlonglong position() const;
|
||||
|
||||
Q_PROPERTY(double Rate READ rate WRITE setRate)
|
||||
double rate() const;
|
||||
void setRate(double value);
|
||||
|
||||
Q_PROPERTY(bool Shuffle READ shuffle WRITE setShuffle)
|
||||
bool shuffle() const;
|
||||
void setShuffle(bool value);
|
||||
|
||||
Q_PROPERTY(double Volume READ volume WRITE setVolume)
|
||||
double volume() const;
|
||||
void setVolume(double value);
|
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
void Next();
|
||||
void OpenUri(const QString &Uri);
|
||||
void Pause();
|
||||
void Play();
|
||||
void PlayPause();
|
||||
void Previous();
|
||||
void Seek(qlonglong Offset);
|
||||
void SetPosition(const QDBusObjectPath &TrackId, qlonglong Position);
|
||||
void Stop();
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void Seeked(qlonglong Position);
|
||||
private Q_SLOTS:
|
||||
void onCanControlChanged() const;
|
||||
void onCanGoNextChanged() const;
|
||||
void onCanGoPreviousChanged() const;
|
||||
void onCanPauseChanged() const;
|
||||
void onCanPlayChanged() const;
|
||||
void onCanSeekChanged() const;
|
||||
void onLoopStatusChanged() const;
|
||||
void onMaximumRateChanged() const;
|
||||
void onMetadataChanged() const;
|
||||
void onMinimumRateChanged() const;
|
||||
void onPlaybackStatusChanged() const;
|
||||
void onRateChanged() const;
|
||||
void onShuffleChanged() const;
|
||||
void onVolumeChanged() const;
|
||||
};
|
||||
|
||||
#endif /* MPRISPLAYER_P_H */
|
||||
@ -0,0 +1,644 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mprisplayer_p.h"
|
||||
|
||||
#include "mprisplayer.h"
|
||||
|
||||
#include <qqmlinfo.h>
|
||||
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
/*
|
||||
* Implementation of adaptor class MprisPlayerAdaptor
|
||||
*/
|
||||
|
||||
static const QString mprisPlayerInterface = QStringLiteral("org.mpris.MediaPlayer2.Player");
|
||||
|
||||
|
||||
MprisPlayerAdaptor::MprisPlayerAdaptor(MprisPlayer *parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{
|
||||
// constructor
|
||||
setAutoRelaySignals(false);
|
||||
|
||||
connect(parent, SIGNAL(canControlChanged()), this, SLOT(onCanControlChanged()));
|
||||
connect(parent, SIGNAL(canGoNextChanged()), this, SLOT(onCanGoNextChanged()));
|
||||
connect(parent, SIGNAL(canGoPreviousChanged()), this, SLOT(onCanGoPreviousChanged()));
|
||||
connect(parent, SIGNAL(canPauseChanged()), this, SLOT(onCanPauseChanged()));
|
||||
connect(parent, SIGNAL(canPlayChanged()), this, SLOT(onCanPlayChanged()));
|
||||
connect(parent, SIGNAL(canSeekChanged()), this, SLOT(onCanSeekChanged()));
|
||||
connect(parent, SIGNAL(loopStatusChanged()), this, SLOT(onLoopStatusChanged()));
|
||||
connect(parent, SIGNAL(maximumRateChanged()), this, SLOT(onMaximumRateChanged()));
|
||||
connect(parent, SIGNAL(metadataChanged()), this, SLOT(onMetadataChanged()));
|
||||
connect(parent, SIGNAL(minimumRateChanged()), this, SLOT(onMinimumRateChanged()));
|
||||
connect(parent, SIGNAL(playbackStatusChanged()), this, SLOT(onPlaybackStatusChanged()));
|
||||
// PositionChanged signal is not forwarded through DBus ...
|
||||
connect(parent, SIGNAL(rateChanged()), this, SLOT(onRateChanged()));
|
||||
connect(parent, SIGNAL(shuffleChanged()), this, SLOT(onShuffleChanged()));
|
||||
connect(parent, SIGNAL(volumeChanged()), this, SLOT(onVolumeChanged()));
|
||||
connect(parent, SIGNAL(seeked(qlonglong)), this, SIGNAL(Seeked(qlonglong)));
|
||||
}
|
||||
|
||||
MprisPlayerAdaptor::~MprisPlayerAdaptor()
|
||||
{
|
||||
// destructor
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::canControl() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->canControl();
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::canGoNext() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
return player->canControl() && player->canGoNext();
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::canGoPrevious() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
return player->canControl() && player->canGoPrevious();
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::canPause() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
return player->canControl() && player->canPause();
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::canPlay() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
return player->canControl() && player->canPlay();
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::canSeek() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
return player->canControl() && player->canSeek();
|
||||
}
|
||||
|
||||
QString MprisPlayerAdaptor::loopStatus() const
|
||||
{
|
||||
return Mpris::enumerationToString(static_cast<MprisPlayer *>(parent())->loopStatus());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::setLoopStatus(const QString &value)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (player->canControl()) {
|
||||
Q_EMIT player->loopStatusRequested(Mpris::enumerationFromString<Mpris::LoopStatus>(value));
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot send an error reply in a property setter so we just
|
||||
// complain here
|
||||
qDebug() << Q_FUNC_INFO << "Requested to modify the loop status but it is not supported.";
|
||||
}
|
||||
|
||||
double MprisPlayerAdaptor::maximumRate() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->maximumRate();
|
||||
}
|
||||
|
||||
QVariantMap MprisPlayerAdaptor::metadata() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->metadata();
|
||||
}
|
||||
|
||||
double MprisPlayerAdaptor::minimumRate() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->minimumRate();
|
||||
}
|
||||
|
||||
QString MprisPlayerAdaptor::playbackStatus() const
|
||||
{
|
||||
return Mpris::enumerationToString(static_cast<MprisPlayer *>(parent())->playbackStatus());
|
||||
}
|
||||
|
||||
qlonglong MprisPlayerAdaptor::position() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->position();
|
||||
}
|
||||
|
||||
double MprisPlayerAdaptor::rate() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->rate();
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::setRate(double value)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
QString errorMessage;
|
||||
|
||||
if (!player->canControl()) {
|
||||
errorMessage = QStringLiteral("Requested to modify the rate but it is not supported.");
|
||||
} else if (player->minimumRate() > value) {
|
||||
errorMessage = QStringLiteral("Requested to modify the rate under its minimum allowed value.");
|
||||
} else if (player->maximumRate() < value) {
|
||||
errorMessage = QStringLiteral("Requested to modify the rate over its maximum allowed value.");
|
||||
}
|
||||
|
||||
if (errorMessage.isEmpty()) {
|
||||
if (value == 0) {
|
||||
Q_EMIT player->pauseRequested();
|
||||
} else {
|
||||
Q_EMIT player->rateRequested(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot send an error reply in a property setter so we just
|
||||
// complain here
|
||||
qDebug() << Q_FUNC_INFO << errorMessage;
|
||||
}
|
||||
|
||||
bool MprisPlayerAdaptor::shuffle() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->shuffle();
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::setShuffle(bool value)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (player->canControl()) {
|
||||
Q_EMIT player->shuffleRequested(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot send an error reply in a property setter so we just
|
||||
// complain here
|
||||
qDebug() << Q_FUNC_INFO << "Requested to modify the shuffle but it is not supported.";
|
||||
}
|
||||
|
||||
double MprisPlayerAdaptor::volume() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->volume();
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::setVolume(double value)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (player->canControl()) {
|
||||
Q_EMIT player->volumeRequested(value < 0 ? 0 : value);
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot send an error reply in a property setter so we just
|
||||
// complain here
|
||||
qDebug() << Q_FUNC_INFO << "Requested to modify the volume but it is not supported.";
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::Next()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to move to next track but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->canGoNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT player->nextRequested();
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::OpenUri(const QString &Uri)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to open an url but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl url(Uri, QUrl::StrictMode);
|
||||
if (!url.isValid()) {
|
||||
player->sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Wanted to open an url but the url is invalid."));
|
||||
}
|
||||
|
||||
if (!player->supportedUriSchemes().contains(url.scheme())) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to open an url but the scheme is not supported."));
|
||||
}
|
||||
|
||||
QMimeDatabase db;
|
||||
QMimeType mime;
|
||||
if (url.isLocalFile()) {
|
||||
mime = db.mimeTypeForFile(url.toLocalFile());
|
||||
} else {
|
||||
mime = db.mimeTypeForFile(url.fileName(), QMimeDatabase::MatchExtension);
|
||||
}
|
||||
QStringList mimeNames = mime.aliases();
|
||||
mimeNames.prepend(mime.name());
|
||||
for (int i = 0; i < mimeNames.size(); i++) {
|
||||
if (player->supportedMimeTypes().contains(mimeNames[i])) {
|
||||
Q_EMIT player->openUriRequested(url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to open an url but the mime type is not supported."));
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::Pause()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to pause but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->canPause()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (player->playbackStatus()) {
|
||||
case Mpris::Playing:
|
||||
case Mpris::Stopped:
|
||||
Q_EMIT player->pauseRequested();
|
||||
break;
|
||||
case Mpris::Paused:
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::Play()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to play but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->canPlay()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (player->playbackStatus()) {
|
||||
case Mpris::Stopped:
|
||||
case Mpris::Paused:
|
||||
Q_EMIT player->playRequested();
|
||||
break;
|
||||
case Mpris::Playing:
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::PlayPause()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to play or pause but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (player->playbackStatus()) {
|
||||
case Mpris::Playing:
|
||||
if (!player->canPause()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to pause but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT player->pauseRequested();
|
||||
break;
|
||||
case Mpris::Stopped:
|
||||
case Mpris::Paused:
|
||||
if (!player->canPlay()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to play but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT player->playRequested();
|
||||
break;
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::Previous()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to move to previous track but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->canGoPrevious()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT player->previousRequested();
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::Seek(qlonglong Offset)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to seek but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->canSeek() || Offset == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Offset < 0) {
|
||||
Q_EMIT player->seekRequested(Offset);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap metadata = player->metadata();
|
||||
QVariant length = metadata[Mpris::metadataToString(Mpris::Length)];
|
||||
if (length.isValid() && (player->position() + Offset) > length.toLongLong()) {
|
||||
Q_EMIT player->nextRequested();
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT player->seekRequested(Offset);
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::SetPosition(const QDBusObjectPath &TrackId, qlonglong Position)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to move to position but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->canSeek()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap metadata = player->metadata();
|
||||
QVariant trackId = metadata[Mpris::metadataToString(Mpris::TrackId)];
|
||||
QVariant length = metadata[Mpris::metadataToString(Mpris::Length)];
|
||||
if (!trackId.isValid() || !length.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackId.value<QDBusObjectPath>() != TrackId) {
|
||||
player->sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Wanted to move to position but the TrackId is not the current one."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Position > length.toLongLong()) {
|
||||
player->sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Wanted to move to position but the position is off range."));
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT player->setPositionRequested(TrackId, Position);
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::Stop()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (!player->canControl()) {
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Wanted to stop but it is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (player->playbackStatus()) {
|
||||
case Mpris::Playing:
|
||||
case Mpris::Paused:
|
||||
Q_EMIT player->stopRequested();
|
||||
break;
|
||||
case Mpris::Stopped:
|
||||
default:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
void MprisPlayerAdaptor::onCanControlChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
// canControlChanged signal is not forwarded through DBus, but
|
||||
// we can notify about the rest of "Can*" properties
|
||||
|
||||
QVariantMap changedProperties;
|
||||
if (player->canGoNext()) {
|
||||
changedProperties[QStringLiteral("CanGoNext")] = QVariant(player->canControl());
|
||||
}
|
||||
if (player->canGoPrevious()) {
|
||||
changedProperties[QStringLiteral("CanGoPrevious")] = QVariant(player->canControl());
|
||||
}
|
||||
if (player->canPause()) {
|
||||
changedProperties[QStringLiteral("CanPause")] = QVariant(player->canControl());
|
||||
}
|
||||
if (player->canPlay()) {
|
||||
changedProperties[QStringLiteral("CanPlay")] = QVariant(player->canControl());
|
||||
}
|
||||
if (player->canSeek()) {
|
||||
changedProperties[QStringLiteral("CanSeek")] = QVariant(player->canControl());
|
||||
}
|
||||
|
||||
if (changedProperties.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onCanGoNextChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (!player->canControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanGoNext")] = QVariant(player->canGoNext());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onCanGoPreviousChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (!player->canControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanGoPrevious")] = QVariant(player->canGoPrevious());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onCanPauseChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (!player->canControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanPause")] = QVariant(player->canPause());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onCanPlayChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (!player->canControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanPlay")] = QVariant(player->canPlay());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onCanSeekChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (!player->canControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanSeek")] = QVariant(player->canSeek());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onLoopStatusChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("LoopStatus")] = QVariant(Mpris::enumerationToString(player->loopStatus()));
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onMaximumRateChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (player->maximumRate() < 1) {
|
||||
qmlInfo(this) << "Maximum rate should be equal or above 1";
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("MaximumRate")] = QVariant(player->maximumRate());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onMetadataChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("Metadata")] = QVariant(player->metadata());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onMinimumRateChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (player->minimumRate() > 1) {
|
||||
qmlInfo(this) << "Minimum rate should be equal or less than 1";
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("MinimumRate")] = QVariant(player->minimumRate() < 0 ? 0 : player->minimumRate());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onPlaybackStatusChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("PlaybackStatus")] = QVariant(Mpris::enumerationToString(player->playbackStatus()));
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onRateChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
if (player->rate() <= 0 || player->rate() < player->minimumRate() || player->rate() > player->maximumRate()) {
|
||||
qmlInfo(this) << "Rate should never be negative or out of the minimum and maximum limits";
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("Rate")] = QVariant(player->rate());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onShuffleChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("Shuffle")] = QVariant(player->shuffle());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisPlayerAdaptor::onVolumeChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("Volume")] = QVariant(player->volume() < 0 ? 0 : player->volume());
|
||||
|
||||
player->notifyPropertiesChanged(mprisPlayerInterface, changedProperties, QStringList());
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mpriscontroller_p.h"
|
||||
|
||||
#include "mpris.h"
|
||||
|
||||
#include <QtCore/QtDebug>
|
||||
|
||||
|
||||
/*
|
||||
* Implementation of interface class MprisPlayerInterface
|
||||
*/
|
||||
|
||||
MprisPlayerInterface::MprisPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
|
||||
: DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent)
|
||||
, m_canControl(false)
|
||||
, m_canGoNext(false)
|
||||
, m_canGoPrevious(false)
|
||||
, m_canPause(false)
|
||||
, m_canPlay(false)
|
||||
, m_canSeek(false)
|
||||
, m_loopStatus(Mpris::None)
|
||||
, m_maximumRate(1)
|
||||
, m_minimumRate(1)
|
||||
, m_playbackStatus(Mpris::Stopped)
|
||||
, m_position(0)
|
||||
, m_rate(1)
|
||||
, m_shuffle(false)
|
||||
, m_volume(0)
|
||||
{
|
||||
connect(this, SIGNAL(propertyChanged(QString, QVariant)), this, SLOT(onPropertyChanged(QString, QVariant)));
|
||||
}
|
||||
|
||||
MprisPlayerInterface::~MprisPlayerInterface()
|
||||
{
|
||||
}
|
||||
|
||||
void MprisPlayerInterface::onPropertyChanged(const QString &propertyName, const QVariant &value)
|
||||
{
|
||||
if (propertyName == QStringLiteral("CanControl")) {
|
||||
bool canControl = value.toBool();
|
||||
if (m_canControl != canControl) {
|
||||
m_canControl = canControl;
|
||||
Q_EMIT canControlChanged(m_canControl);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanGoNext")) {
|
||||
bool canGoNext = value.toBool();
|
||||
if (m_canGoNext != canGoNext) {
|
||||
m_canGoNext = canGoNext;
|
||||
Q_EMIT canGoNextChanged(m_canGoNext);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanGoPrevious")) {
|
||||
bool canGoPrevious = value.toBool();
|
||||
if (m_canGoPrevious != canGoPrevious) {
|
||||
m_canGoPrevious = canGoPrevious;
|
||||
Q_EMIT canGoPreviousChanged(m_canGoPrevious);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanPause")) {
|
||||
bool canPause = value.toBool();
|
||||
if (m_canPause != canPause) {
|
||||
m_canPause = canPause;
|
||||
Q_EMIT canPauseChanged(m_canPause);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanPlay")) {
|
||||
bool canPlay = value.toBool();
|
||||
if (m_canPlay != canPlay) {
|
||||
m_canPlay = canPlay;
|
||||
Q_EMIT canPlayChanged(m_canPlay);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanSeek")) {
|
||||
bool canSeek = value.toBool();
|
||||
if (m_canSeek != canSeek) {
|
||||
m_canSeek = canSeek;
|
||||
Q_EMIT canSeekChanged(m_canSeek);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("LoopStatus")) {
|
||||
QString loopStatus = value.toString();
|
||||
if (m_loopStatus != loopStatus) {
|
||||
m_loopStatus = loopStatus;
|
||||
Q_EMIT loopStatusChanged(m_loopStatus);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("MaximumRate")) {
|
||||
bool maximumRate = value.toDouble();
|
||||
if (m_maximumRate != maximumRate) {
|
||||
m_maximumRate = maximumRate;
|
||||
Q_EMIT maximumRateChanged(m_maximumRate);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Metadata")) {
|
||||
QVariantMap metadata = value.toMap();
|
||||
if (m_metadata != metadata) {
|
||||
m_metadata = metadata;
|
||||
Q_EMIT metadataChanged(m_metadata);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("MinimumRate")) {
|
||||
double minimumRate = value.toDouble();
|
||||
if (m_minimumRate != minimumRate) {
|
||||
m_minimumRate = minimumRate;
|
||||
Q_EMIT minimumRateChanged(m_minimumRate);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("PlaybackStatus")) {
|
||||
QString playbackStatus = value.toString();
|
||||
if (m_playbackStatus != playbackStatus) {
|
||||
m_playbackStatus = playbackStatus;
|
||||
Q_EMIT playbackStatusChanged(m_playbackStatus);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Position")) {
|
||||
qlonglong position = value.toLongLong();
|
||||
if (m_position != position) {
|
||||
m_position = position;
|
||||
Q_EMIT positionChanged(m_position);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Rate")) {
|
||||
double rate = value.toDouble();
|
||||
if (m_rate != rate) {
|
||||
m_rate = rate;
|
||||
Q_EMIT rateChanged(m_rate);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Shuffle")) {
|
||||
bool shuffle = value.toBool();
|
||||
if (m_shuffle != shuffle) {
|
||||
m_shuffle = shuffle;
|
||||
Q_EMIT shuffleChanged(m_shuffle);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Volume")) {
|
||||
double volume = value.toDouble();
|
||||
if (m_volume != volume) {
|
||||
m_volume = volume;
|
||||
Q_EMIT volumeChanged(m_volume);
|
||||
}
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Received PropertyChanged signal from unknown property: "
|
||||
<< propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MPRIS_QT_H
|
||||
#define MPRIS_QT_H
|
||||
|
||||
#if defined(MPRIS_QT_LIBRARY)
|
||||
# define MPRIS_QT_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define MPRIS_QT_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif /* MPRIS_QT_H */
|
||||
@ -0,0 +1,244 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mprisplayer_p.h"
|
||||
|
||||
#include "mprisplayer.h"
|
||||
|
||||
#include <qqmlinfo.h>
|
||||
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
/*
|
||||
* Implementation of adaptor class MprisRootAdaptor
|
||||
*/
|
||||
|
||||
static const QString mprisRootInterface = QStringLiteral("org.mpris.MediaPlayer2");
|
||||
|
||||
|
||||
MprisRootAdaptor::MprisRootAdaptor(MprisPlayer *parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{
|
||||
// constructor
|
||||
setAutoRelaySignals(false);
|
||||
|
||||
connect(parent, SIGNAL(canQuitChanged()), this, SLOT(onCanQuitChanged()));
|
||||
connect(parent, SIGNAL(canRaiseChanged()), this, SLOT(onCanRaiseChanged()));
|
||||
connect(parent, SIGNAL(canSetFullscreenChanged()), this, SLOT(onCanSetFullscreenChanged()));
|
||||
connect(parent, SIGNAL(desktopEntryChanged()), this, SLOT(onDesktopEntryChanged()));
|
||||
connect(parent, SIGNAL(fullscreenChanged()), this, SLOT(onFullscreenChanged()));
|
||||
connect(parent, SIGNAL(hasTrackListChanged()), this, SLOT(onHasTrackListChanged()));
|
||||
connect(parent, SIGNAL(identityChanged()), this, SLOT(onIdentityChanged()));
|
||||
connect(parent, SIGNAL(supportedUriSchemesChanged()), this, SLOT(onSupportedUriSchemesChanged()));
|
||||
connect(parent, SIGNAL(supportedMimeTypesChanged()), this, SLOT(onSupportedMimeTypesChanged()));
|
||||
}
|
||||
|
||||
MprisRootAdaptor::~MprisRootAdaptor()
|
||||
{
|
||||
// destructor
|
||||
}
|
||||
|
||||
bool MprisRootAdaptor::canQuit() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->canQuit();
|
||||
}
|
||||
|
||||
bool MprisRootAdaptor::canRaise() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->canRaise();
|
||||
}
|
||||
|
||||
bool MprisRootAdaptor::canSetFullscreen() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->canSetFullscreen();
|
||||
}
|
||||
|
||||
QString MprisRootAdaptor::desktopEntry() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->desktopEntry();
|
||||
}
|
||||
|
||||
bool MprisRootAdaptor::fullscreen() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->fullscreen();
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::setFullscreen(bool value)
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (player->canSetFullscreen()) {
|
||||
Q_EMIT player->fullscreenRequested(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot send an error reply in a property setter so we just
|
||||
// complain here
|
||||
if (value) {
|
||||
qDebug() << Q_FUNC_INFO << "Requested to fullscreen, but not supported";
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << "Requested to unfullscreen, but not supported";
|
||||
}
|
||||
}
|
||||
|
||||
bool MprisRootAdaptor::hasTrackList() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->hasTrackList();
|
||||
}
|
||||
|
||||
QString MprisRootAdaptor::identity() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->identity();
|
||||
}
|
||||
|
||||
QStringList MprisRootAdaptor::supportedMimeTypes() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->supportedMimeTypes();
|
||||
}
|
||||
|
||||
QStringList MprisRootAdaptor::supportedUriSchemes() const
|
||||
{
|
||||
return static_cast<MprisPlayer *>(parent())->supportedUriSchemes();
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::Quit()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (player->canQuit()) {
|
||||
Q_EMIT player->quitRequested();
|
||||
return;
|
||||
}
|
||||
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Quit requested but not supported."));
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::Raise()
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
if (player->canRaise()) {
|
||||
Q_EMIT player->raiseRequested();
|
||||
return;
|
||||
}
|
||||
|
||||
player->sendErrorReply(QDBusError::NotSupported, QStringLiteral("Raise requested but not supported."));
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
void MprisRootAdaptor::onCanQuitChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanQuit")] = QVariant(player->canQuit());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onCanRaiseChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanRaise")] = QVariant(player->canRaise());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onCanSetFullscreenChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("CanSetFullscreen")] = QVariant(player->canSetFullscreen());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onDesktopEntryChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("DesktopEntry")] = QVariant(player->desktopEntry());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onFullscreenChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("Fullscreen")] = QVariant(player->fullscreen());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onHasTrackListChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("HasTrackList")] = QVariant(player->hasTrackList());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onIdentityChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("Identity")] = QVariant(player->identity());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onSupportedUriSchemesChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("SupportedUriSchemes")] = QVariant(player->supportedUriSchemes());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
|
||||
void MprisRootAdaptor::onSupportedMimeTypesChanged() const
|
||||
{
|
||||
MprisPlayer * const player = static_cast<MprisPlayer *>(parent());
|
||||
|
||||
QVariantMap changedProperties;
|
||||
changedProperties[QStringLiteral("SupportedMimeTypes")] = QVariant(player->supportedMimeTypes());
|
||||
|
||||
player->notifyPropertiesChanged(mprisRootInterface, changedProperties, QStringList());
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "mpriscontroller_p.h"
|
||||
|
||||
#include <QtCore/QtDebug>
|
||||
|
||||
|
||||
/*
|
||||
* Implementation of interface class MprisRootInterface
|
||||
*/
|
||||
|
||||
MprisRootInterface::MprisRootInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
|
||||
: DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent)
|
||||
, m_canQuit(false)
|
||||
, m_canRaise(false)
|
||||
, m_canSetFullscreen(false)
|
||||
, m_fullscreen(false)
|
||||
, m_hasTrackList(false)
|
||||
{
|
||||
connect(this, SIGNAL(propertyChanged(QString, QVariant)), this, SLOT(onPropertyChanged(QString, QVariant)));
|
||||
}
|
||||
|
||||
MprisRootInterface::~MprisRootInterface()
|
||||
{
|
||||
}
|
||||
|
||||
void MprisRootInterface::onPropertyChanged(const QString &propertyName, const QVariant &value)
|
||||
{
|
||||
if (propertyName == QStringLiteral("CanQuit")) {
|
||||
bool canQuit = value.toBool();
|
||||
if (m_canQuit != canQuit) {
|
||||
m_canQuit = canQuit;
|
||||
Q_EMIT canQuitChanged(m_canQuit);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanRaise")) {
|
||||
bool canRaise = value.toBool();
|
||||
if (m_canRaise != canRaise) {
|
||||
m_canRaise = canRaise;
|
||||
Q_EMIT canRaiseChanged(m_canRaise);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("CanSetFullscreen")) {
|
||||
bool canSetFullscreen = value.toBool();
|
||||
if (m_canSetFullscreen != canSetFullscreen) {
|
||||
m_canSetFullscreen = canSetFullscreen;
|
||||
Q_EMIT canSetFullscreenChanged(m_canSetFullscreen);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("DesktopEntry")) {
|
||||
QString desktopEntry = value.toString();
|
||||
if (m_desktopEntry != desktopEntry) {
|
||||
m_desktopEntry = desktopEntry;
|
||||
Q_EMIT desktopEntryChanged(m_desktopEntry);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Fullscreen")) {
|
||||
bool fullscreen = value.toBool();
|
||||
if (m_fullscreen != fullscreen) {
|
||||
m_fullscreen = fullscreen;
|
||||
Q_EMIT fullscreenChanged(m_fullscreen);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("HasTrackList")) {
|
||||
bool hasTrackList = value.toBool();
|
||||
if (m_hasTrackList != hasTrackList) {
|
||||
m_hasTrackList = hasTrackList;
|
||||
Q_EMIT hasTrackListChanged(m_hasTrackList);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("Identity")) {
|
||||
QString identity= value.toString();
|
||||
if (m_identity != identity) {
|
||||
m_identity = identity;
|
||||
Q_EMIT identityChanged(m_identity);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("SupportedMimeTypes")) {
|
||||
QStringList supportedUriSchemes = value.toStringList();
|
||||
if (m_supportedUriSchemes != supportedUriSchemes) {
|
||||
m_supportedUriSchemes = supportedUriSchemes;
|
||||
Q_EMIT supportedMimeTypesChanged(m_supportedUriSchemes);
|
||||
}
|
||||
} else if (propertyName == QStringLiteral("SupportedUriSchemes")) {
|
||||
QStringList supportedMimeTypes = value.toStringList();
|
||||
if (m_supportedMimeTypes != supportedMimeTypes) {
|
||||
m_supportedMimeTypes = supportedMimeTypes;
|
||||
Q_EMIT supportedUriSchemesChanged(m_supportedMimeTypes);
|
||||
}
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO
|
||||
<< "Received PropertyChanged signal from unknown property: "
|
||||
<< propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,509 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||
<node>
|
||||
|
||||
<!--
|
||||
org.mpris.MediaPlayer2:
|
||||
@short_description: Media Player Remote Interfacing Specification
|
||||
|
||||
The Media Player Remote Interfacing Specification is a standard
|
||||
D-Bus interface which aims to provide a common programmatic API
|
||||
for controlling media players.
|
||||
|
||||
This interface implements the methods for querying and providing
|
||||
basic control over what is currently playing.
|
||||
-->
|
||||
<interface name="org.mpris.MediaPlayer2.Player">
|
||||
|
||||
<!--
|
||||
Next:
|
||||
|
||||
Skips to the next track in the tracklist.
|
||||
|
||||
If there is no next track (and endless playback and track repeat
|
||||
are both off), stop playback.
|
||||
|
||||
If playback is paused or stopped, it remains that way.
|
||||
|
||||
If CanGoNext is false, attempting to call this method should
|
||||
have no effect.
|
||||
-->
|
||||
<method name="Next"/>
|
||||
|
||||
<!--
|
||||
Previous:
|
||||
|
||||
Skips to the previous track in the tracklist.
|
||||
|
||||
If there is no previous track (and endless playback and track
|
||||
repeat are both off), stop playback.
|
||||
|
||||
If playback is paused or stopped, it remains that way.
|
||||
|
||||
If CanGoPrevious is false, attempting to call this method should
|
||||
have no effect.
|
||||
-->
|
||||
<method name="Previous"/>
|
||||
|
||||
<!--
|
||||
Pause:
|
||||
|
||||
Pauses playback.
|
||||
|
||||
If playback is already paused, this has no effect.
|
||||
|
||||
Calling Play after this should cause playback to start again
|
||||
from the same position.
|
||||
|
||||
If CanPause is false, attempting to call this method should have
|
||||
no effect.
|
||||
-->
|
||||
<method name="Pause"/>
|
||||
|
||||
<!--
|
||||
PlayPause:
|
||||
|
||||
Pauses playback.
|
||||
|
||||
If playback is already paused, resumes playback.
|
||||
|
||||
If playback is stopped, starts playback.
|
||||
|
||||
If CanPause is false, attempting to call this method should have
|
||||
no effect and raise an error.
|
||||
-->
|
||||
<method name="PlayPause"/>
|
||||
|
||||
<!--
|
||||
Stop:
|
||||
|
||||
Stops playback.
|
||||
|
||||
If playback is already stopped, this has no effect.
|
||||
|
||||
Calling Play after this should cause playback to start again
|
||||
from the beginning of the track.
|
||||
|
||||
If CanControl is false, attempting to call this method should
|
||||
have no effect and raise an error.
|
||||
-->
|
||||
<method name="Stop"/>
|
||||
|
||||
<!--
|
||||
Play:
|
||||
|
||||
Starts or resumes playback.
|
||||
|
||||
If already playing, this has no effect.
|
||||
|
||||
If paused, playback resumes from the current position.
|
||||
|
||||
If there is no track to play, this has no effect.
|
||||
|
||||
If CanPlay is false, attempting to call this method should have
|
||||
no effect.
|
||||
-->
|
||||
<method name="Play"/>
|
||||
|
||||
<!--
|
||||
Seek:
|
||||
@Offset: The number of microseconds to seek forward.
|
||||
|
||||
Seeks forward in the current track by the specified number of
|
||||
microseconds.
|
||||
|
||||
A negative value seeks back. If this would mean seeking back
|
||||
further than the start of the track, the position is set to 0.
|
||||
|
||||
If the value passed in would mean seeking beyond the end of the
|
||||
track, acts like a call to Next.
|
||||
|
||||
If the CanSeek property is false, this has no effect.
|
||||
-->
|
||||
<method name="Seek">
|
||||
<arg type="x" direction="in" name="Offset"/>
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="Time_In_Us"/ -->
|
||||
</method>
|
||||
|
||||
<!--
|
||||
SetPosition:
|
||||
@TrackId: The currently playing track's identifier.
|
||||
If this does not match the id of the currently-playing
|
||||
track, the call is ignored as "stale".
|
||||
/org/mpris/MediaPlayer2/TrackList/NoTrack is not a
|
||||
valid value for this argument.
|
||||
@Position: Track position in microseconds.
|
||||
This must be between 0 and <track_length>.
|
||||
|
||||
Seeks forward in the current track by the specified number of
|
||||
microseconds.
|
||||
|
||||
A negative value seeks back. If this would mean seeking back
|
||||
further than the start of the track, the position is set to 0.
|
||||
|
||||
If the value passed in would mean seeking beyond the end of the
|
||||
track, acts like a call to Next.
|
||||
|
||||
If the CanSeek property is false, this has no effect.
|
||||
-->
|
||||
<method name="SetPosition">
|
||||
<arg type="o" direction="in" name="TrackId"/>
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="Track_Id"/ -->
|
||||
<arg type="x" direction="in" name="Position"/>
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="Time_In_Us"/ -->
|
||||
</method>
|
||||
|
||||
<!--
|
||||
OpenUri:
|
||||
@TrackId: Uri of the track to load. Its uri scheme should be an
|
||||
element of the
|
||||
org.mpris.MediaPlayer2.SupportedUriSchemes property
|
||||
and the mime-type should match one of the elements of
|
||||
the org.mpris.MediaPlayer2.SupportedMimeTypes.
|
||||
|
||||
Opens the Uri given as an argument
|
||||
|
||||
If the playback is stopped, starts playing
|
||||
|
||||
If the uri scheme or the mime-type of the uri to open is not
|
||||
supported, this method does nothing and may raise an error. In
|
||||
particular, if the list of available uri schemes is empty, this
|
||||
method may not be implemented.
|
||||
|
||||
Clients should not assume that the Uri has been opened as soon
|
||||
as this method returns. They should wait until the mpris:trackid
|
||||
field in the Metadata property changes.
|
||||
|
||||
If the media player implements the TrackList interface, then the
|
||||
opened track should be made part of the tracklist, the
|
||||
org.mpris.MediaPlayer2.TrackList.TrackAdded or
|
||||
org.mpris.MediaPlayer2.TrackList.TrackListReplaced signal should
|
||||
be fired, as well as the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal on the
|
||||
tracklist interface.
|
||||
-->
|
||||
<method name="OpenUri">
|
||||
<arg type="s" direction="in" name="Uri"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QUrl"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Seeked:
|
||||
@Position: The new position, in microseconds.
|
||||
|
||||
Indicates that the track position has changed in a way that is
|
||||
inconsistant with the current playing state.
|
||||
|
||||
When this signal is not received, clients should assume that:
|
||||
* When playing, the position progresses according to the rate
|
||||
property.
|
||||
* When paused, it remains constant.
|
||||
|
||||
This signal does not need to be emitted when playback starts or
|
||||
when the track changes, unless the track is starting at an
|
||||
unexpected position. An expected position would be the last
|
||||
known one when going from Paused to Playing, and 0 when going
|
||||
from Stopped to Playing.
|
||||
-->
|
||||
<signal name="Seeked">
|
||||
<arg type="x" direction="out" name="Position"/>
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="Time_In_Us"/ -->
|
||||
</signal>
|
||||
|
||||
<!--
|
||||
PlaybackStatus:
|
||||
|
||||
The current playback status.
|
||||
|
||||
May be "Playing", "Paused" or "Stopped".
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="PlaybackStatus" type="s" access="read">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Playback_Status"/ -->
|
||||
</property>
|
||||
|
||||
<!--
|
||||
LoopStatus:
|
||||
|
||||
The current loop / repeat status
|
||||
|
||||
May be:
|
||||
* "None" if the playback will stop when there are no more
|
||||
tracks to play
|
||||
* "Track" if the current track will start again from the
|
||||
begining once it has finished playing
|
||||
* "Playlist" if the playback loops through a list of tracks
|
||||
|
||||
If CanControl is false, attempting to set this property should
|
||||
have no effect and raise an error.
|
||||
|
||||
This property is optional. Clients should handle its absence
|
||||
gracefully.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="LoopStatus" type="s" access="readwrite">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Loop_Status"/ -->
|
||||
</property>
|
||||
|
||||
<!--
|
||||
Rate:
|
||||
|
||||
The current playback rate.
|
||||
|
||||
The value must fall in the range described by MinimumRate and
|
||||
MaximumRate, and must not be 0.0. If playback is paused, the
|
||||
PlaybackStatus property should be used to indicate this. A value
|
||||
of 0.0 should not be set by the client. If it is, the media
|
||||
player should act as though Pause was called.
|
||||
|
||||
If the media player has no ability to play at speeds other than
|
||||
the normal playback rate, this must still be implemented, and
|
||||
must return 1.0. The MinimumRate and MaximumRate properties must
|
||||
also be set to 1.0.
|
||||
|
||||
Not all values may be accepted by the media player. It is left
|
||||
to media player implementations to decide how to deal with
|
||||
values they cannot use; they may either ignore them or pick a
|
||||
"best fit" value. Clients are recommended to only use sensible
|
||||
fractions or multiples of 1 (eg: 0.5, 0.25, 1.5, 2.0, etc).
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Rate" type="d" access="readwrite">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Playback_Rate"/ -->
|
||||
</property>
|
||||
|
||||
<!--
|
||||
Shuffle:
|
||||
|
||||
A value of false indicates that playback is progressing linearly
|
||||
through a playlist, while true means playback is progressing
|
||||
through a playlist in some other order.
|
||||
|
||||
If CanControl is false, attempting to set this property should
|
||||
have no effect and raise an error.
|
||||
|
||||
This property is optional. Clients should handle its absence
|
||||
gracefully.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Shuffle" type="b" access="readwrite"/>
|
||||
|
||||
<!--
|
||||
Metadata:
|
||||
|
||||
The metadata of the current element.
|
||||
|
||||
If there is a current track, this must have a "mpris:trackid"
|
||||
entry (of D-Bus type "o") at the very least, which contains a
|
||||
D-Bus path that uniquely identifies this track.
|
||||
|
||||
See the type documentation for more details.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Metadata" type="a{sv}" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
Volume:
|
||||
|
||||
The volume level.
|
||||
|
||||
When setting, if a negative value is passed, the volume should
|
||||
be set to 0.0.
|
||||
|
||||
If CanControl is false, attempting to set this property should
|
||||
have no effect and raise an error.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Volume" type="d" access="readwrite">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Volume"/ -->
|
||||
</property>
|
||||
|
||||
<!--
|
||||
Position:
|
||||
|
||||
The current track position in microseconds, between 0 and the
|
||||
'mpris:length' metadata entry (see Metadata).
|
||||
|
||||
Note: If the media player allows it, the current playback
|
||||
position can be changed either the SetPosition method or the
|
||||
Seek method on this interface.If this is not the case, the
|
||||
CanSeek property is false, and setting this property has no
|
||||
effect and can raise an error.
|
||||
|
||||
If the playback progresses in a way that is inconstistant with
|
||||
the Rate property, the Seeked signal is emited.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is not
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Position" type="x" access="read">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Time_In_Us"/ -->
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
MinimumRate:
|
||||
|
||||
The minimum value which the Rate property can take. Clients
|
||||
should not attempt to set the Rate property below this value.
|
||||
|
||||
Note that even if this value is 0.0 or negative, clients should
|
||||
not attempt to set the Rate property to 0.0.
|
||||
|
||||
This value should always be 1.0 or less.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="MinimumRate" type="d" access="read">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Playback_Rate"/ -->
|
||||
</property>
|
||||
|
||||
<!--
|
||||
MaximumRate:
|
||||
|
||||
The maximum value which the Rate property can take. Clients
|
||||
should not attempt to set the Rate property above this value.
|
||||
|
||||
This value should always be 1.0 or greater.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="MaximumRate" type="d" access="read">
|
||||
<!-- annotation name="org.qtproject.QtDBus.QtTypeName" value="Playback_Rate"/ -->
|
||||
</property>
|
||||
|
||||
<!--
|
||||
CanGoNext:
|
||||
|
||||
Whether the client can call the Next method on this interface
|
||||
and expect the current track to change.
|
||||
|
||||
If it is unknown whether a call to Next will be successful (for
|
||||
example, when streaming tracks), this property should be set to
|
||||
true.
|
||||
|
||||
If CanControl is false, this property should also be false.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanGoNext" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
CanGoPrevious:
|
||||
|
||||
Whether the client can call the Previous method on this
|
||||
interface and expect the current track to change.
|
||||
|
||||
If it is unknown whether a call to Previous will be successful
|
||||
(for example, when streaming tracks), this property should be
|
||||
set to true.
|
||||
|
||||
If CanControl is false, this property should also be false.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanGoPrevious" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
CanPlay:
|
||||
|
||||
Whether playback can be started using Play or PlayPause.
|
||||
|
||||
Note that this is related to whether there is a "current track":
|
||||
the value should not depend on whether the track is currently
|
||||
paused or playing. In fact, if a track is currently playing (and
|
||||
CanControl is true), this should be true.
|
||||
|
||||
If CanControl is false, this property should also be false.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanPlay" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
CanPause:
|
||||
|
||||
Whether playback can be paused using Pause or PlayPause.
|
||||
|
||||
Note that this is an intrinsic property of the current track:
|
||||
its value should not depend on whether the track is currently
|
||||
paused or playing. In fact, if playback is currently paused (and
|
||||
CanControl is true), this should be true.
|
||||
|
||||
If CanControl is false, this property should also be false.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanPause" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
CanSeek:
|
||||
|
||||
Whether the client can control the playback position using Seek
|
||||
and SetPosition. This may be different for different tracks.
|
||||
|
||||
If CanControl is false, this property should also be false.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanSeek" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
CanControl:
|
||||
|
||||
Whether the media player may be controlled over this interface.
|
||||
|
||||
This property is not expected to change, as it describes an
|
||||
intrinsic capability of the implementation.
|
||||
|
||||
If this is false, clients should assume that all properties on
|
||||
this interface are read-only (and will raise errors if writing
|
||||
to them is attempted), no methods are implemented and all other
|
||||
properties starting with "Can" are also false.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is not
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanControl" type="b" access="read">
|
||||
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||||
</property>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,207 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||
<node>
|
||||
|
||||
<!--
|
||||
org.mpris.MediaPlayer2:
|
||||
@short_description: Media Player Remote Interfacing Specification
|
||||
|
||||
The Media Player Remote Interfacing Specification is a standard
|
||||
D-Bus interface which aims to provide a common programmatic API
|
||||
for controlling media players.
|
||||
-->
|
||||
<interface name="org.mpris.MediaPlayer2">
|
||||
|
||||
<!--
|
||||
Raise:
|
||||
|
||||
Brings the media player's user interface to the front using any
|
||||
appropriate mechanism available.
|
||||
|
||||
The media player may be unable to control how its user interface
|
||||
is displayed, or it may not have a graphical user interface at
|
||||
all. In this case, the CanRaise property is false and this
|
||||
method does nothing.
|
||||
-->
|
||||
<method name="Raise"/>
|
||||
|
||||
<!--
|
||||
Quit:
|
||||
|
||||
Causes the media player to stop running.
|
||||
|
||||
The media player may refuse to allow clients to shut it down. In
|
||||
this case, the CanQuit property is false and this method does
|
||||
nothing.
|
||||
|
||||
Note: Media players which can be D-Bus activated, or for which
|
||||
there is no sensibly easy way to terminate a running instance
|
||||
(via the main interface or a notification area icon for example)
|
||||
should allow clients to use this method. Otherwise, it should
|
||||
not be needed.
|
||||
|
||||
If the media player does not have a UI, this should be
|
||||
implemented.
|
||||
-->
|
||||
<method name="Quit"/>
|
||||
|
||||
<!--
|
||||
CanQuit:
|
||||
|
||||
If false, calling Quit will have no effect, and may raise a
|
||||
NotSupported error. If true, calling Quit will cause the media
|
||||
application to attempt to quit (although it may still be
|
||||
prevented from quitting by the user, for example).
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanQuit" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
Fullscreen:
|
||||
|
||||
Whether the media player is occupying the fullscreen.
|
||||
|
||||
This is typically used for videos. A value of true indicates
|
||||
that the media player is taking up the full screen.
|
||||
|
||||
Media centre software may well have this value fixed to true
|
||||
|
||||
If CanSetFullscreen is true, clients may set this property to
|
||||
true to tell the media player to enter fullscreen mode, or to
|
||||
false to return to windowed mode.
|
||||
|
||||
If CanSetFullscreen is false, then attempting to set this
|
||||
property should have no effect, and may raise an error. However,
|
||||
even if it is true, the media player may still be unable to
|
||||
fulfil the request, in which case attempting to set this
|
||||
property will have no effect (but should not raise an error).
|
||||
|
||||
This property is optional. Clients should handle its absence
|
||||
gracefully.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Fullscreen" type="b" access="readwrite"/>
|
||||
|
||||
<!--
|
||||
CanSetFullscreen:
|
||||
|
||||
If false, attempting to set Fullscreen will have no effect, and
|
||||
may raise an error. If true, attempting to set Fullscreen will
|
||||
not raise an error, and (if it is different from the current
|
||||
value) will cause the media player to attempt to enter or exit
|
||||
fullscreen mode.
|
||||
|
||||
Note that the media player may be unable to fulfil the
|
||||
request. In this case, the value will not change. If the media
|
||||
player knows in advance that it will not be able to fulfil the
|
||||
request, however, this property should be false.
|
||||
|
||||
This property is optional. Clients should handle its absence
|
||||
gracefully.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanSetFullscreen" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
CanRaise:
|
||||
|
||||
If false, calling Raise will have no effect, and may raise a
|
||||
NotSupported error. If true, calling Raise will cause the media
|
||||
application to attempt to bring its user interface to the front,
|
||||
although it may be prevented from doing so (by the window
|
||||
manager, for example).
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="CanRaise" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
HasTrackList:
|
||||
|
||||
Indicates whether the /org/mpris/MediaPlayer2 object implements
|
||||
the org.mpris.MediaPlayer2.TrackList interface.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="HasTrackList" type="b" access="read"/>
|
||||
|
||||
<!--
|
||||
Identity:
|
||||
|
||||
A friendly name to identify the media player to users.
|
||||
|
||||
This should usually match the name found in .desktop files
|
||||
|
||||
(eg: "VLC media player").
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="Identity" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
DesktopEntry:
|
||||
|
||||
The basename of an installed .desktop file which complies with
|
||||
the Desktop entry specification, with the ".desktop" extension
|
||||
stripped.
|
||||
|
||||
Example: The desktop entry file is
|
||||
"/usr/share/applications/vlc.desktop", and this property
|
||||
contains "vlc"
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="DesktopEntry" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
SupportedUriSchemes:
|
||||
|
||||
The URI schemes supported by the media player.
|
||||
|
||||
This can be viewed as protocols supported by the player in
|
||||
almost all cases. Almost every media player will include support
|
||||
for the "file" scheme. Other common schemes are "http" and
|
||||
"rtsp".
|
||||
|
||||
Note that URI schemes should be lower-case.
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="SupportedUriSchemes" type="as" access="read"/>
|
||||
|
||||
<!--
|
||||
SupportedMimeTypes:
|
||||
|
||||
The mime-types supported by the media player.
|
||||
|
||||
Mime-types should be in the standard format (eg: audio/mpeg or
|
||||
application/ogg).
|
||||
|
||||
When this property changes, the
|
||||
org.freedesktop.DBus.Properties.PropertiesChanged signal is
|
||||
emitted with the new value.
|
||||
-->
|
||||
<property name="SupportedMimeTypes" type="as" access="read"/>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,2 @@
|
||||
module Cutefish.Mpris
|
||||
plugin cutefishmpris_qmlplugins
|
||||
@ -0,0 +1,21 @@
|
||||
#include <QQmlExtensionPlugin>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "mpris.h"
|
||||
#include "mprisplayer.h"
|
||||
#include "mprismanager.h"
|
||||
|
||||
class QmlPlugins : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
|
||||
|
||||
public:
|
||||
void registerTypes(const char * uri) override {
|
||||
qmlRegisterSingletonType<Mpris>(uri, 1, 0, "Mpris", Mpris::api_factory);
|
||||
qmlRegisterType<MprisPlayer>(uri, 1, 0, "MprisPlayer");
|
||||
qmlRegisterType<MprisManager>(uri, 1, 0, "MprisManager");
|
||||
}
|
||||
};
|
||||
|
||||
#include "qmlplugins.moc"
|
||||
@ -0,0 +1,35 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QT_DBUS_EXTENDED_H
|
||||
#define QT_DBUS_EXTENDED_H
|
||||
|
||||
#if defined(QT_DBUS_EXTENDED_LIBRARY)
|
||||
# define QT_DBUS_EXTENDED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define QT_DBUS_EXTENDED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif /* QT_DBUS_EXTENDED_H */
|
||||
@ -0,0 +1,439 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "dbusextendedpendingcallwatcher_p.h"
|
||||
|
||||
#include "dbusextendedabstractinterface.h"
|
||||
|
||||
#include <QtDBus/QDBusMetaType>
|
||||
#include <QtDBus/QDBusMessage>
|
||||
#include <QtDBus/QDBusPendingCall>
|
||||
#include <QtDBus/QDBusPendingCallWatcher>
|
||||
#include <QtDBus/QDBusPendingReply>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QMetaProperty>
|
||||
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusPropertiesInterface, ("org.freedesktop.DBus.Properties"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusPropertiesChangedSignal, ("PropertiesChanged"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, propertyChangedSignature, ("propertyChanged(QString,QVariant)"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, propertyInvalidatedSignature, ("propertyInvalidated(QString)"))
|
||||
|
||||
|
||||
DBusExtendedAbstractInterface::DBusExtendedAbstractInterface(const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent)
|
||||
: QDBusAbstractInterface(service, path, interface, connection, parent)
|
||||
, m_sync(false)
|
||||
, m_useCache(false)
|
||||
, m_getAllPendingCallWatcher(0)
|
||||
, m_propertiesChangedConnected(false)
|
||||
{
|
||||
}
|
||||
|
||||
DBusExtendedAbstractInterface::~DBusExtendedAbstractInterface()
|
||||
{
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::getAllProperties()
|
||||
{
|
||||
m_lastExtendedError = QDBusError();
|
||||
|
||||
if (!isValid()) {
|
||||
QString errorMessage = QStringLiteral("This Extended DBus interface is not valid yet.");
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qDebug() << Q_FUNC_INFO << errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_sync && m_getAllPendingCallWatcher) {
|
||||
// Call already in place, not repeating ...
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("GetAll"));
|
||||
msg << interface();
|
||||
|
||||
if (m_sync) {
|
||||
QDBusMessage reply = connection().call(msg);
|
||||
|
||||
if (reply.type() != QDBusMessage::ReplyMessage) {
|
||||
m_lastExtendedError = QDBusError(reply);
|
||||
qWarning() << Q_FUNC_INFO << m_lastExtendedError.message();
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply.signature() != QLatin1String("a{sv}")) {
|
||||
QString errorMessage = QStringLiteral("Invalid signature \"%1\" in return from call to %2")
|
||||
.arg(reply.signature(),
|
||||
QString(*dBusPropertiesInterface()));
|
||||
qWarning() << Q_FUNC_INFO << errorMessage;
|
||||
m_lastExtendedError = QDBusError(QDBusError::InvalidSignature, errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap value = reply.arguments().at(0).toMap();
|
||||
onPropertiesChanged(interface(), value, QStringList());
|
||||
} else {
|
||||
QDBusPendingReply<QVariantMap> async = connection().asyncCall(msg);
|
||||
m_getAllPendingCallWatcher = new QDBusPendingCallWatcher(async, this);
|
||||
|
||||
connect(m_getAllPendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher*)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::connectNotify(const QMetaMethod &signal)
|
||||
{
|
||||
if (signal.methodType() == QMetaMethod::Signal
|
||||
&& (signal.methodSignature() == *propertyChangedSignature()
|
||||
|| signal.methodSignature() == *propertyInvalidatedSignature())) {
|
||||
if (!m_propertiesChangedConnected) {
|
||||
QStringList argumentMatch;
|
||||
argumentMatch << interface();
|
||||
connection().connect(service(), path(), *dBusPropertiesInterface(), *dBusPropertiesChangedSignal(),
|
||||
argumentMatch, QString(),
|
||||
this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
|
||||
|
||||
m_propertiesChangedConnected = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
QDBusAbstractInterface::connectNotify(signal);
|
||||
}
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::disconnectNotify(const QMetaMethod &signal)
|
||||
{
|
||||
if (signal.methodType() == QMetaMethod::Signal
|
||||
&& (signal.methodSignature() == *propertyChangedSignature()
|
||||
|| signal.methodSignature() == *propertyInvalidatedSignature())) {
|
||||
if (m_propertiesChangedConnected
|
||||
&& 0 == receivers(propertyChangedSignature()->constData())
|
||||
&& 0 == receivers(propertyInvalidatedSignature()->constData())) {
|
||||
QStringList argumentMatch;
|
||||
argumentMatch << interface();
|
||||
connection().disconnect(service(), path(), *dBusPropertiesInterface(), *dBusPropertiesChangedSignal(),
|
||||
argumentMatch, QString(),
|
||||
this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
|
||||
|
||||
m_propertiesChangedConnected = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
QDBusAbstractInterface::disconnectNotify(signal);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant DBusExtendedAbstractInterface::internalPropGet(const char *propname, void *propertyPtr)
|
||||
{
|
||||
m_lastExtendedError = QDBusError();
|
||||
|
||||
if (m_useCache) {
|
||||
int propertyIndex = metaObject()->indexOfProperty(propname);
|
||||
QMetaProperty metaProperty = metaObject()->property(propertyIndex);
|
||||
return QVariant(metaProperty.type(), propertyPtr);
|
||||
}
|
||||
|
||||
if (m_sync) {
|
||||
return property(propname);
|
||||
} else {
|
||||
if (!isValid()) {
|
||||
QString errorMessage = QStringLiteral("This Extended DBus interface is not valid yet.");
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qDebug() << Q_FUNC_INFO << errorMessage;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int propertyIndex = metaObject()->indexOfProperty(propname);
|
||||
|
||||
if (-1 == propertyIndex) {
|
||||
QString errorMessage = QStringLiteral("Got unknown property \"%1\" to read")
|
||||
.arg(QString::fromLatin1(propname));
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qWarning() << Q_FUNC_INFO << errorMessage;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QMetaProperty metaProperty = metaObject()->property(propertyIndex);
|
||||
|
||||
if (!metaProperty.isReadable()) {
|
||||
QString errorMessage = QStringLiteral("Property \"%1\" is NOT readable")
|
||||
.arg(QString::fromLatin1(propname));
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qWarning() << Q_FUNC_INFO << errorMessage;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// is this metatype registered?
|
||||
const char *expectedSignature = "";
|
||||
if (int(metaProperty.type()) != QMetaType::QVariant) {
|
||||
expectedSignature = QDBusMetaType::typeToSignature(metaProperty.userType());
|
||||
if (0 == expectedSignature) {
|
||||
QString errorMessage =
|
||||
QStringLiteral("Type %1 must be registered with Qt D-Bus "
|
||||
"before it can be used to read property "
|
||||
"%2.%3")
|
||||
.arg(metaProperty.typeName(),
|
||||
interface(),
|
||||
propname);
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qWarning() << Q_FUNC_INFO << errorMessage;
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
asyncProperty(propname);
|
||||
return QVariant(metaProperty.type(), propertyPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::internalPropSet(const char *propname, const QVariant &value, void *propertyPtr)
|
||||
{
|
||||
m_lastExtendedError = QDBusError();
|
||||
|
||||
if (m_sync) {
|
||||
setProperty(propname, value);
|
||||
} else {
|
||||
if (!isValid()) {
|
||||
QString errorMessage = QStringLiteral("This interface is not yet valid");
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qDebug() << Q_FUNC_INFO << errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
int propertyIndex = metaObject()->indexOfProperty(propname);
|
||||
|
||||
if (-1 == propertyIndex) {
|
||||
QString errorMessage = QStringLiteral("Got unknown property \"%1\" to write")
|
||||
.arg(QString::fromLatin1(propname));
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qWarning() << Q_FUNC_INFO << errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
QMetaProperty metaProperty = metaObject()->property(propertyIndex);
|
||||
|
||||
if (!metaProperty.isWritable()) {
|
||||
QString errorMessage = QStringLiteral("Property \"%1\" is NOT writable")
|
||||
.arg(QString::fromLatin1(propname));
|
||||
m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage);
|
||||
qWarning() << Q_FUNC_INFO << errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
asyncSetProperty(propname, QVariant(metaProperty.type(), propertyPtr));
|
||||
}
|
||||
}
|
||||
|
||||
QVariant DBusExtendedAbstractInterface::asyncProperty(const QString &propertyName)
|
||||
{
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("Get"));
|
||||
msg << interface() << propertyName;
|
||||
QDBusPendingReply<QVariant> async = connection().asyncCall(msg);
|
||||
DBusExtendedPendingCallWatcher *watcher = new DBusExtendedPendingCallWatcher(async, propertyName, QVariant(), this);
|
||||
|
||||
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAsyncPropertyFinished(QDBusPendingCallWatcher*)));
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::asyncSetProperty(const QString &propertyName, const QVariant &value)
|
||||
{
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("Set"));
|
||||
msg << interface() << propertyName << value;
|
||||
QDBusPendingReply<QVariant> async = connection().asyncCall(msg);
|
||||
DBusExtendedPendingCallWatcher *watcher = new DBusExtendedPendingCallWatcher(async, propertyName, value, this);
|
||||
|
||||
connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAsyncSetPropertyFinished(QDBusPendingCallWatcher*)));
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::onAsyncPropertyFinished(DBusExtendedPendingCallWatcher *watcher)
|
||||
{
|
||||
QDBusPendingReply<QVariant> reply = *watcher;
|
||||
|
||||
if (reply.isError()) {
|
||||
m_lastExtendedError = reply.error();
|
||||
} else {
|
||||
int propertyIndex = metaObject()->indexOfProperty(watcher->asyncProperty().toLatin1().constData());
|
||||
QVariant value = demarshall(interface(),
|
||||
metaObject()->property(propertyIndex),
|
||||
reply.value(),
|
||||
&m_lastExtendedError);
|
||||
|
||||
if (m_lastExtendedError.isValid()) {
|
||||
emit propertyInvalidated(watcher->asyncProperty());
|
||||
} else {
|
||||
emit propertyChanged(watcher->asyncProperty(), value);
|
||||
}
|
||||
}
|
||||
|
||||
emit asyncPropertyFinished(watcher->asyncProperty());
|
||||
watcher->deleteLater();
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::onAsyncSetPropertyFinished(DBusExtendedPendingCallWatcher *watcher)
|
||||
{
|
||||
QDBusPendingReply<QVariant> reply = *watcher;
|
||||
|
||||
if (reply.isError()) {
|
||||
m_lastExtendedError = reply.error();
|
||||
} else {
|
||||
m_lastExtendedError = QDBusError();
|
||||
}
|
||||
|
||||
emit asyncSetPropertyFinished(watcher->asyncProperty());
|
||||
|
||||
// Resetting the property to its previous value after sending the
|
||||
// finished signal
|
||||
if (reply.isError()) {
|
||||
m_lastExtendedError = QDBusError();
|
||||
emit propertyChanged(watcher->asyncProperty(), watcher->previousValue());
|
||||
}
|
||||
|
||||
watcher->deleteLater();
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *watcher)
|
||||
{
|
||||
m_getAllPendingCallWatcher = 0;
|
||||
|
||||
QDBusPendingReply<QVariantMap> reply = *watcher;
|
||||
|
||||
if (reply.isError()) {
|
||||
m_lastExtendedError = reply.error();
|
||||
} else {
|
||||
m_lastExtendedError = QDBusError();
|
||||
}
|
||||
|
||||
emit asyncGetAllPropertiesFinished();
|
||||
|
||||
if (!reply.isError()) {
|
||||
onPropertiesChanged(interface(), reply.value(), QStringList());
|
||||
}
|
||||
|
||||
watcher->deleteLater();
|
||||
}
|
||||
|
||||
void DBusExtendedAbstractInterface::onPropertiesChanged(const QString& interfaceName,
|
||||
const QVariantMap& changedProperties,
|
||||
const QStringList& invalidatedProperties)
|
||||
{
|
||||
if (interfaceName == interface()) {
|
||||
QVariantMap::const_iterator i = changedProperties.constBegin();
|
||||
while (i != changedProperties.constEnd()) {
|
||||
int propertyIndex = metaObject()->indexOfProperty(i.key().toLatin1().constData());
|
||||
|
||||
if (-1 == propertyIndex) {
|
||||
qDebug() << Q_FUNC_INFO << "Got unknown changed property" << i.key();
|
||||
} else {
|
||||
QVariant value = demarshall(interface(), metaObject()->property(propertyIndex), i.value(), &m_lastExtendedError);
|
||||
|
||||
if (m_lastExtendedError.isValid()) {
|
||||
emit propertyInvalidated(i.key());
|
||||
} else {
|
||||
emit propertyChanged(i.key(), value);
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
QStringList::const_iterator j = invalidatedProperties.constBegin();
|
||||
while (j != invalidatedProperties.constEnd()) {
|
||||
if (-1 == metaObject()->indexOfProperty(j->toLatin1().constData())) {
|
||||
qDebug() << Q_FUNC_INFO << "Got unknown invalidated property" << *j;
|
||||
} else {
|
||||
m_lastExtendedError = QDBusError();
|
||||
emit propertyInvalidated(*j);
|
||||
}
|
||||
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariant DBusExtendedAbstractInterface::demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error)
|
||||
{
|
||||
Q_ASSERT(metaProperty.isValid());
|
||||
Q_ASSERT(error != 0);
|
||||
|
||||
if (value.userType() == metaProperty.userType()) {
|
||||
// No need demarshalling. Passing back straight away ...
|
||||
*error = QDBusError();
|
||||
return value;
|
||||
}
|
||||
|
||||
QVariant result = QVariant(metaProperty.userType(), (void*)0);
|
||||
QString errorMessage;
|
||||
const char *expectedSignature = QDBusMetaType::typeToSignature(metaProperty.userType());
|
||||
|
||||
if (value.userType() == qMetaTypeId<QDBusArgument>()) {
|
||||
// demarshalling a DBus argument ...
|
||||
QDBusArgument dbusArg = value.value<QDBusArgument>();
|
||||
|
||||
if (expectedSignature == dbusArg.currentSignature().toLatin1()) {
|
||||
QDBusMetaType::demarshall(dbusArg, metaProperty.userType(), result.data());
|
||||
if (!result.isValid()) {
|
||||
errorMessage = QStringLiteral("Unexpected failure demarshalling "
|
||||
"upon PropertiesChanged signal arrival "
|
||||
"for property `%3.%4' (expected type `%5' (%6))")
|
||||
.arg(interface,
|
||||
QString::fromLatin1(metaProperty.name()),
|
||||
QString::fromLatin1(metaProperty.typeName()),
|
||||
expectedSignature);
|
||||
}
|
||||
} else {
|
||||
errorMessage = QStringLiteral("Unexpected `user type' (%2) "
|
||||
"upon PropertiesChanged signal arrival "
|
||||
"for property `%3.%4' (expected type `%5' (%6))")
|
||||
.arg(dbusArg.currentSignature(),
|
||||
interface,
|
||||
QString::fromLatin1(metaProperty.name()),
|
||||
QString::fromLatin1(metaProperty.typeName()),
|
||||
QString::fromLatin1(expectedSignature));
|
||||
}
|
||||
} else {
|
||||
const char *actualSignature = QDBusMetaType::typeToSignature(value.userType());
|
||||
|
||||
errorMessage = QStringLiteral("Unexpected `%1' (%2) "
|
||||
"upon PropertiesChanged signal arrival "
|
||||
"for property `%3.%4' (expected type `%5' (%6))")
|
||||
.arg(QString::fromLatin1(value.typeName()),
|
||||
QString::fromLatin1(actualSignature),
|
||||
interface,
|
||||
QString::fromLatin1(metaProperty.name()),
|
||||
QString::fromLatin1(metaProperty.typeName()),
|
||||
QString::fromLatin1(expectedSignature));
|
||||
}
|
||||
|
||||
if (errorMessage.isEmpty()) {
|
||||
*error = QDBusError();
|
||||
} else {
|
||||
*error = QDBusMessage::createError(QDBusError::InvalidSignature, errorMessage);
|
||||
qDebug() << Q_FUNC_INFO << errorMessage;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DBUSEXTENDEDABSTRACTINTERFACE_H
|
||||
#define DBUSEXTENDEDABSTRACTINTERFACE_H
|
||||
|
||||
#include "dbusextended.h"
|
||||
|
||||
#include <QDBusAbstractInterface>
|
||||
#include <QDBusError>
|
||||
|
||||
class QDBusPendingCallWatcher;
|
||||
class DBusExtendedPendingCallWatcher;
|
||||
|
||||
class QT_DBUS_EXTENDED_EXPORT DBusExtendedAbstractInterface: public QDBusAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual ~DBusExtendedAbstractInterface();
|
||||
|
||||
Q_PROPERTY(bool sync READ sync WRITE setSync)
|
||||
inline bool sync() const { return m_sync; }
|
||||
inline void setSync(bool sync) { m_sync = sync; }
|
||||
|
||||
Q_PROPERTY(bool useCache READ useCache WRITE setUseCache)
|
||||
inline bool useCache() const { return m_useCache; }
|
||||
inline void setUseCache(bool useCache) { m_useCache = useCache; }
|
||||
|
||||
void getAllProperties();
|
||||
inline QDBusError lastExtendedError() const { return m_lastExtendedError; };
|
||||
|
||||
protected:
|
||||
DBusExtendedAbstractInterface(const QString &service,
|
||||
const QString &path,
|
||||
const char *interface,
|
||||
const QDBusConnection &connection,
|
||||
QObject *parent);
|
||||
|
||||
void connectNotify(const QMetaMethod &signal);
|
||||
void disconnectNotify(const QMetaMethod &signal);
|
||||
QVariant internalPropGet(const char *propname, void *propertyPtr);
|
||||
void internalPropSet(const char *propname, const QVariant &value, void *propertyPtr);
|
||||
|
||||
Q_SIGNALS:
|
||||
void propertyChanged(const QString &propertyName, const QVariant &value);
|
||||
void propertyInvalidated(const QString &propertyName);
|
||||
void asyncPropertyFinished(const QString &propertyName);
|
||||
void asyncSetPropertyFinished(const QString &propertyName);
|
||||
void asyncGetAllPropertiesFinished();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPropertiesChanged(const QString& interfaceName,
|
||||
const QVariantMap& changedProperties,
|
||||
const QStringList& invalidatedProperties);
|
||||
void onAsyncPropertyFinished(DBusExtendedPendingCallWatcher *watcher);
|
||||
void onAsyncSetPropertyFinished(DBusExtendedPendingCallWatcher *watcher);
|
||||
void onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *watcher);
|
||||
|
||||
private:
|
||||
QVariant asyncProperty(const QString &propertyName);
|
||||
void asyncSetProperty(const QString &propertyName, const QVariant &value);
|
||||
static QVariant demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error);
|
||||
|
||||
bool m_sync;
|
||||
bool m_useCache;
|
||||
QDBusPendingCallWatcher *m_getAllPendingCallWatcher;
|
||||
QDBusError m_lastExtendedError;
|
||||
bool m_propertiesChangedConnected;
|
||||
};
|
||||
|
||||
#endif /* DBUSEXTENDEDABSTRACTINTERFACE_H */
|
||||
@ -0,0 +1,38 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "dbusextendedpendingcallwatcher_p.h"
|
||||
|
||||
|
||||
DBusExtendedPendingCallWatcher::DBusExtendedPendingCallWatcher(const QDBusPendingCall &call, const QString &asyncProperty, const QVariant &previousValue, QObject *parent)
|
||||
: QDBusPendingCallWatcher(call, parent)
|
||||
, m_asyncProperty(asyncProperty)
|
||||
, m_previousValue(previousValue)
|
||||
{
|
||||
}
|
||||
|
||||
DBusExtendedPendingCallWatcher::~DBusExtendedPendingCallWatcher()
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
/*!
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
*
|
||||
* Contact: Valerio Valerio <valerio.valerio@jolla.com>
|
||||
* Author: Andres Gomez <andres.gomez@jolla.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// 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 DBUSEXTENDEDPENDINGCALLWATCHER_P_H
|
||||
#define DBUSEXTENDEDPENDINGCALLWATCHER_P_H
|
||||
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QDBusError>
|
||||
|
||||
class DBusExtendedPendingCallWatcher: public QDBusPendingCallWatcher
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DBusExtendedPendingCallWatcher(const QDBusPendingCall &call,
|
||||
const QString &asyncProperty,
|
||||
const QVariant &previousValue,
|
||||
QObject *parent = 0);
|
||||
~DBusExtendedPendingCallWatcher();
|
||||
|
||||
Q_PROPERTY(QString AsyncProperty READ asyncProperty)
|
||||
inline QString asyncProperty() const { return m_asyncProperty; }
|
||||
|
||||
Q_PROPERTY(QVariant PreviousValue READ previousValue)
|
||||
inline QVariant previousValue() const { return m_previousValue; }
|
||||
|
||||
private:
|
||||
QString m_asyncProperty;
|
||||
QVariant m_previousValue;
|
||||
};
|
||||
|
||||
#endif /* DBUSEXTENDEDPENDINGCALLWATCHER_P_H */
|
||||
@ -0,0 +1,53 @@
|
||||
set(NETWORKMGR_SRCS
|
||||
appletproxymodel.cpp
|
||||
appletproxymodel.h
|
||||
|
||||
networkitemslist.cpp
|
||||
networkitemslist.h
|
||||
|
||||
networkmodel.cpp
|
||||
networkmodel.h
|
||||
|
||||
networkmodelitem.cpp
|
||||
networkmodelitem.h
|
||||
|
||||
networking.cpp
|
||||
networking.h
|
||||
|
||||
network.cpp
|
||||
network.h
|
||||
|
||||
wiressitemsettings.cpp
|
||||
wiressitemsettings.h
|
||||
|
||||
technologyproxymodel.cpp
|
||||
technologyproxymodel.h
|
||||
|
||||
uiutils.cpp
|
||||
uiutils.h
|
||||
|
||||
connectionicon.cpp
|
||||
connectionicon.h
|
||||
|
||||
qmlplugins.cpp
|
||||
qmlplugins.h
|
||||
)
|
||||
|
||||
find_package(KF5NetworkManagerQt REQUIRED)
|
||||
find_package(KF5ModemManagerQt REQUIRED)
|
||||
|
||||
add_library(cutefishnm_qmlplugins SHARED ${NETWORKMGR_SRCS})
|
||||
generate_export_header(cutefishnm_qmlplugins EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/networkmanager_export.h BASE_NAME NetworkManager)
|
||||
|
||||
target_link_libraries (cutefishnm_qmlplugins
|
||||
Qt5::Core
|
||||
Qt5::Quick
|
||||
Qt5::Gui
|
||||
Qt5::DBus
|
||||
|
||||
KF5::NetworkManagerQt
|
||||
KF5::ModemManagerQt
|
||||
)
|
||||
|
||||
install(TARGETS cutefishnm_qmlplugins DESTINATION ${INSTALL_QMLDIR}/Cutefish/NetworkManagement)
|
||||
install(FILES qmldir DESTINATION ${INSTALL_QMLDIR}/Cutefish/NetworkManagement)
|
||||
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2013-2014 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "appletproxymodel.h"
|
||||
#include "networkmodel.h"
|
||||
#include "uiutils.h"
|
||||
|
||||
AppletProxyModel::AppletProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
setDynamicSortFilter(true);
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
sort(0, Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
AppletProxyModel::~AppletProxyModel()
|
||||
{
|
||||
}
|
||||
|
||||
bool AppletProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
|
||||
|
||||
// slaves are filtered-out when not searching for a connection (makes the state of search results clear)
|
||||
const bool isSlave = sourceModel()->data(index, NetworkModel::SlaveRole).toBool();
|
||||
if (isSlave && filterRegExp().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const NetworkManager::ConnectionSettings::ConnectionType type = (NetworkManager::ConnectionSettings::ConnectionType) sourceModel()->data(index, NetworkModel::TypeRole).toUInt();
|
||||
if (!UiUtils::isConnectionTypeSupported(type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NetworkModelItem::ItemType itemType = (NetworkModelItem::ItemType)sourceModel()->data(index, NetworkModel::ItemTypeRole).toUInt();
|
||||
|
||||
if (itemType != NetworkModelItem::AvailableConnection &&
|
||||
itemType != NetworkModelItem::AvailableAccessPoint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filterRegExp().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sourceModel()->data(index, NetworkModel::ItemUniqueNameRole).toString().contains(filterRegExp());
|
||||
}
|
||||
|
||||
bool AppletProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
const bool leftAvailable = (NetworkModelItem::ItemType)sourceModel()->data(left, NetworkModel::ItemTypeRole).toUInt() != NetworkModelItem::UnavailableConnection;
|
||||
const bool leftConnected = sourceModel()->data(left, NetworkModel::ConnectionStateRole).toUInt() == NetworkManager::ActiveConnection::Activated;
|
||||
const int leftConnectionState = sourceModel()->data(left, NetworkModel::ConnectionStateRole).toUInt();
|
||||
const QString leftName = sourceModel()->data(left, NetworkModel::NameRole).toString();
|
||||
const UiUtils::SortedConnectionType leftType = UiUtils::connectionTypeToSortedType((NetworkManager::ConnectionSettings::ConnectionType) sourceModel()->data(left, NetworkModel::TypeRole).toUInt());
|
||||
const QString leftUuid = sourceModel()->data(left, NetworkModel::UuidRole).toString();
|
||||
const int leftSignal = sourceModel()->data(left, NetworkModel::SignalRole).toInt();
|
||||
const QDateTime leftDate = sourceModel()->data(left, NetworkModel::TimeStampRole).toDateTime();
|
||||
|
||||
const bool rightAvailable = (NetworkModelItem::ItemType)sourceModel()->data(right, NetworkModel::ItemTypeRole).toUInt() != NetworkModelItem::UnavailableConnection;
|
||||
const bool rightConnected = sourceModel()->data(right, NetworkModel::ConnectionStateRole).toUInt() == NetworkManager::ActiveConnection::Activated;
|
||||
const int rightConnectionState = sourceModel()->data(right, NetworkModel::ConnectionStateRole).toUInt();
|
||||
const QString rightName = sourceModel()->data(right, NetworkModel::NameRole).toString();
|
||||
const UiUtils::SortedConnectionType rightType = UiUtils::connectionTypeToSortedType((NetworkManager::ConnectionSettings::ConnectionType) sourceModel()->data(right, NetworkModel::TypeRole).toUInt());
|
||||
const QString rightUuid = sourceModel()->data(right, NetworkModel::UuidRole).toString();
|
||||
const int rightSignal = sourceModel()->data(right, NetworkModel::SignalRole).toInt();
|
||||
const QDateTime rightDate = sourceModel()->data(right, NetworkModel::TimeStampRole).toDateTime();
|
||||
|
||||
if (leftAvailable < rightAvailable) {
|
||||
return true;
|
||||
} else if (leftAvailable > rightAvailable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftConnected < rightConnected) {
|
||||
return true;
|
||||
} else if (leftConnected > rightConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftConnectionState > rightConnectionState) {
|
||||
return true;
|
||||
} else if (leftConnectionState < rightConnectionState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftUuid.isEmpty() && !rightUuid.isEmpty()) {
|
||||
return true;
|
||||
} else if (!leftUuid.isEmpty() && rightUuid.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftType < rightType) {
|
||||
return false;
|
||||
} else if (leftType > rightType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (leftDate > rightDate) {
|
||||
return false;
|
||||
} else if (leftDate < rightDate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (leftSignal < rightSignal) {
|
||||
return true;
|
||||
} else if (leftSignal > rightSignal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QString::localeAwareCompare(leftName, rightName) > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2013-2014 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef APPLETPROXYMODEL_H
|
||||
#define APPLETPROXYMODEL_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "networkmodelitem.h"
|
||||
|
||||
class NETWORKMANAGER_EXPORT AppletProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QAbstractItemModel * sourceModel READ sourceModel WRITE setSourceModel)
|
||||
|
||||
public:
|
||||
explicit AppletProxyModel(QObject *parent = nullptr);
|
||||
~AppletProxyModel() override;
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
};
|
||||
|
||||
#endif // APPLETPROXYMODEL_H
|
||||
@ -0,0 +1,657 @@
|
||||
/*
|
||||
Copyright 2013 Jan Grulich <jgrulich@redhat.com>
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "connectionicon.h"
|
||||
#include "uiutils.h"
|
||||
|
||||
#include <NetworkManagerQt/BluetoothDevice>
|
||||
#include <NetworkManagerQt/Connection>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/Device>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/WiredDevice>
|
||||
#include <NetworkManagerQt/WirelessDevice>
|
||||
#include <NetworkManagerQt/WirelessSetting>
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
#include <ModemManagerQt/manager.h>
|
||||
#endif
|
||||
|
||||
ConnectionIcon::ConnectionIcon(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_signal(0)
|
||||
, m_wirelessNetwork(nullptr)
|
||||
, m_connecting(false)
|
||||
, m_limited(false)
|
||||
, m_vpn(false)
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
, m_modemNetwork(nullptr)
|
||||
#endif
|
||||
{
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::primaryConnectionChanged, this, &ConnectionIcon::primaryConnectionChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activatingConnectionChanged, this, &ConnectionIcon::activatingConnectionChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &ConnectionIcon::activeConnectionAdded);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &ConnectionIcon::connectivityChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &ConnectionIcon::deviceAdded);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &ConnectionIcon::deviceRemoved);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::networkingEnabledChanged, this, &ConnectionIcon::networkingEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &ConnectionIcon::statusChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, this, &ConnectionIcon::wirelessEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessHardwareEnabledChanged, this, &ConnectionIcon::wirelessEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wwanEnabledChanged, this, &ConnectionIcon::wwanEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wwanHardwareEnabledChanged, this, &ConnectionIcon::wwanEnabledChanged);
|
||||
|
||||
for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) {
|
||||
if (device->type() == NetworkManager::Device::Ethernet) {
|
||||
NetworkManager::WiredDevice::Ptr wiredDevice = device.staticCast<NetworkManager::WiredDevice>();
|
||||
if (wiredDevice) {
|
||||
connect(wiredDevice.data(), &NetworkManager::WiredDevice::carrierChanged, this, &ConnectionIcon::carrierChanged);
|
||||
}
|
||||
} else if (device->type() == NetworkManager::Device::Wifi) {
|
||||
NetworkManager::WirelessDevice::Ptr wifiDevice = device.staticCast<NetworkManager::WirelessDevice>();
|
||||
if (wifiDevice) {
|
||||
connect(wifiDevice.data(), &NetworkManager::WirelessDevice::availableConnectionAppeared, this, &ConnectionIcon::wirelessNetworkAppeared);
|
||||
connect(wifiDevice.data(), &NetworkManager::WirelessDevice::networkAppeared, this, &ConnectionIcon::wirelessNetworkAppeared);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const NetworkManager::ActiveConnection::Ptr &activeConnection : NetworkManager::activeConnections()) {
|
||||
addActiveConnection(activeConnection->path());
|
||||
}
|
||||
setStates();
|
||||
|
||||
setIcons();
|
||||
|
||||
QDBusPendingReply<uint> pendingReply = NetworkManager::checkConnectivity();
|
||||
QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(pendingReply);
|
||||
connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *watcher) {
|
||||
QDBusPendingReply<uint> reply = *watcher;
|
||||
if (reply.isValid()) {
|
||||
connectivityChanged((NetworkManager::Connectivity)reply.value());
|
||||
}
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
ConnectionIcon::~ConnectionIcon()
|
||||
{
|
||||
}
|
||||
|
||||
bool ConnectionIcon::connecting() const
|
||||
{
|
||||
return m_connecting;
|
||||
}
|
||||
|
||||
QString ConnectionIcon::connectionIcon() const
|
||||
{
|
||||
if (m_vpn && !m_connectionIcon.contains("available")) {
|
||||
return m_connectionIcon + "-locked";
|
||||
}
|
||||
|
||||
if (m_limited && !m_connectionIcon.contains("available")) {
|
||||
return m_connectionIcon + "-limited";
|
||||
}
|
||||
|
||||
return m_connectionIcon;
|
||||
}
|
||||
|
||||
QString ConnectionIcon::connectionTooltipIcon() const
|
||||
{
|
||||
return m_connectionTooltipIcon;
|
||||
}
|
||||
|
||||
QString ConnectionIcon::currentSSID() const
|
||||
{
|
||||
return m_currentSSID;
|
||||
}
|
||||
|
||||
void ConnectionIcon::activatingConnectionChanged(const QString& connection)
|
||||
{
|
||||
Q_UNUSED(connection);
|
||||
setIcons();
|
||||
}
|
||||
|
||||
void ConnectionIcon::addActiveConnection(const QString &activeConnection)
|
||||
{
|
||||
NetworkManager::ActiveConnection::Ptr active = NetworkManager::findActiveConnection(activeConnection);
|
||||
|
||||
if (active) {
|
||||
NetworkManager::VpnConnection::Ptr vpnConnection;
|
||||
connect(active.data(), &NetworkManager::ActiveConnection::destroyed, this, &ConnectionIcon::activeConnectionDestroyed);
|
||||
if (active->vpn()) {
|
||||
vpnConnection = active.objectCast<NetworkManager::VpnConnection>();
|
||||
connect(vpnConnection.data(), &NetworkManager::VpnConnection::stateChanged, this, &ConnectionIcon::vpnConnectionStateChanged);
|
||||
} else {
|
||||
connect(active.data(), &NetworkManager::ActiveConnection::stateChanged, this, &ConnectionIcon::activeConnectionStateChanged, Qt::UniqueConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::activeConnectionAdded(const QString &activeConnection)
|
||||
{
|
||||
addActiveConnection(activeConnection);
|
||||
setStates();
|
||||
}
|
||||
|
||||
void ConnectionIcon::activeConnectionStateChanged(NetworkManager::ActiveConnection::State state)
|
||||
{
|
||||
Q_UNUSED(state);
|
||||
setStates();
|
||||
}
|
||||
|
||||
void ConnectionIcon::activeConnectionDestroyed()
|
||||
{
|
||||
setStates();
|
||||
}
|
||||
|
||||
void ConnectionIcon::carrierChanged(bool carrier)
|
||||
{
|
||||
Q_UNUSED(carrier);
|
||||
setIcons();
|
||||
}
|
||||
|
||||
void ConnectionIcon::connectivityChanged(NetworkManager::Connectivity conn)
|
||||
{
|
||||
const bool needsPortal = conn == NetworkManager::Portal;
|
||||
if (needsPortal != m_needsPortal) {
|
||||
m_needsPortal = needsPortal;
|
||||
Q_EMIT needsPortalChanged(needsPortal);
|
||||
}
|
||||
setLimited(conn == NetworkManager::Portal || conn == NetworkManager::Limited);
|
||||
}
|
||||
|
||||
void ConnectionIcon::deviceAdded(const QString& device)
|
||||
{
|
||||
NetworkManager::Device::Ptr dev = NetworkManager::findNetworkInterface(device);
|
||||
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->type() == NetworkManager::Device::Ethernet) {
|
||||
NetworkManager::WiredDevice::Ptr wiredDev = dev.objectCast<NetworkManager::WiredDevice>();
|
||||
connect(wiredDev.data(), &NetworkManager::WiredDevice::carrierChanged, this, &ConnectionIcon::carrierChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::deviceRemoved(const QString& device)
|
||||
{
|
||||
Q_UNUSED(device);
|
||||
|
||||
if (NetworkManager::status() == NetworkManager::Disconnected) {
|
||||
setDisconnectedIcon();
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
void ConnectionIcon::modemNetworkRemoved()
|
||||
{
|
||||
m_modemNetwork.clear();
|
||||
}
|
||||
|
||||
void ConnectionIcon::modemSignalChanged(const ModemManager::SignalQualityPair &signalQuality)
|
||||
{
|
||||
int diff = m_signal - signalQuality.signal;
|
||||
|
||||
if (diff >= 10 ||
|
||||
diff <= -10) {
|
||||
m_signal = signalQuality.signal;
|
||||
|
||||
setIconForModem();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConnectionIcon::networkingEnabledChanged(bool enabled)
|
||||
{
|
||||
if (!enabled) {
|
||||
setConnectionIcon("network-unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::primaryConnectionChanged(const QString& connection)
|
||||
{
|
||||
if (!connection.isEmpty()) {
|
||||
setIcons();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::statusChanged(NetworkManager::Status status)
|
||||
{
|
||||
if (status == NetworkManager::Disconnected) {
|
||||
setDisconnectedIcon();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::vpnConnectionStateChanged(NetworkManager::VpnConnection::State state, NetworkManager::VpnConnection::StateChangeReason reason)
|
||||
{
|
||||
Q_UNUSED(state);
|
||||
Q_UNUSED(reason);
|
||||
setStates();
|
||||
setIcons();
|
||||
}
|
||||
|
||||
void ConnectionIcon::wirelessEnabledChanged(bool enabled)
|
||||
{
|
||||
Q_UNUSED(enabled);
|
||||
|
||||
m_currentSSID = "";
|
||||
emit currentSSIDChanged();
|
||||
|
||||
setIcons();
|
||||
}
|
||||
|
||||
void ConnectionIcon::wwanEnabledChanged(bool enabled)
|
||||
{
|
||||
Q_UNUSED(enabled);
|
||||
setIcons();
|
||||
|
||||
}
|
||||
|
||||
void ConnectionIcon::wirelessNetworkAppeared(const QString& network)
|
||||
{
|
||||
Q_UNUSED(network);
|
||||
setIcons();
|
||||
}
|
||||
|
||||
void ConnectionIcon::setStates()
|
||||
{
|
||||
bool connecting = false;
|
||||
bool vpn = false;
|
||||
for (const NetworkManager::ActiveConnection::Ptr &activeConnection : NetworkManager::activeConnections()) {
|
||||
NetworkManager::VpnConnection::Ptr vpnConnection;
|
||||
if (activeConnection->vpn()) {
|
||||
vpnConnection = activeConnection.objectCast<NetworkManager::VpnConnection>();
|
||||
}
|
||||
|
||||
if (!vpnConnection) {
|
||||
if (activeConnection->state() == NetworkManager::ActiveConnection::Activating && UiUtils::isConnectionTypeSupported(activeConnection->type())) {
|
||||
connecting = true;
|
||||
}
|
||||
if (activeConnection->type() == NetworkManager::ConnectionSettings::ConnectionType::WireGuard) {
|
||||
vpn = true;
|
||||
}
|
||||
} else {
|
||||
if (vpnConnection->state() == NetworkManager::VpnConnection::Activated) {
|
||||
vpn = true;
|
||||
} else if (vpnConnection->state() == NetworkManager::VpnConnection::Prepare ||
|
||||
vpnConnection->state() == NetworkManager::VpnConnection::NeedAuth ||
|
||||
vpnConnection->state() == NetworkManager::VpnConnection::Connecting ||
|
||||
vpnConnection->state() == NetworkManager::VpnConnection::GettingIpConfig) {
|
||||
connecting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setVpn(vpn);
|
||||
setConnecting(connecting);
|
||||
}
|
||||
|
||||
void ConnectionIcon::setIcons()
|
||||
{
|
||||
m_signal = 0;
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
if (m_modemNetwork) {
|
||||
disconnect(m_modemNetwork.data(), nullptr, this, nullptr);
|
||||
m_modemNetwork.clear();
|
||||
}
|
||||
#endif
|
||||
if (m_wirelessNetwork) {
|
||||
disconnect(m_wirelessNetwork.data(), nullptr, this, nullptr);
|
||||
m_wirelessNetwork.clear();
|
||||
}
|
||||
|
||||
NetworkManager::ActiveConnection::Ptr connection = NetworkManager::activatingConnection();
|
||||
|
||||
// Set icon based on the current primary connection if the activating connection is virtual
|
||||
// since we're not setting icons for virtual connections
|
||||
if (!connection
|
||||
|| (connection && UiUtils::isConnectionTypeVirtual(connection->type()))
|
||||
|| connection->type() == NetworkManager::ConnectionSettings::WireGuard) {
|
||||
connection = NetworkManager::primaryConnection();
|
||||
}
|
||||
|
||||
/* Fallback: If we still don't have an active connection with default route or the default route goes through a connection
|
||||
of generic type (some type of VPNs) we need to go through all other active connections and pick the one with
|
||||
highest probability of being the main one (order is: vpn, wired, wireless, gsm, cdma, bluetooth) */
|
||||
if ((!connection && !NetworkManager::activeConnections().isEmpty()) || (connection && connection->type() == NetworkManager::ConnectionSettings::Generic)
|
||||
|| (connection && connection->type() == NetworkManager::ConnectionSettings::Tun)) {
|
||||
for (const NetworkManager::ActiveConnection::Ptr &activeConnection : NetworkManager::activeConnections()) {
|
||||
const NetworkManager::ConnectionSettings::ConnectionType type = activeConnection->type();
|
||||
if (type == NetworkManager::ConnectionSettings::Bluetooth) {
|
||||
if (connection && connection->type() <= NetworkManager::ConnectionSettings::Bluetooth) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Cdma) {
|
||||
if (connection && connection->type() <= NetworkManager::ConnectionSettings::Cdma) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Gsm) {
|
||||
if (connection && connection->type() <= NetworkManager::ConnectionSettings::Gsm) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Vpn) {
|
||||
connection = activeConnection;
|
||||
} else if (type == NetworkManager::ConnectionSettings::WireGuard) {
|
||||
connection = activeConnection;
|
||||
} else if (type == NetworkManager::ConnectionSettings::Wired) {
|
||||
if (connection && (connection->type() != NetworkManager::ConnectionSettings::Vpn
|
||||
|| connection->type() != NetworkManager::ConnectionSettings::WireGuard)) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Wireless) {
|
||||
if (connection && (connection->type() != NetworkManager::ConnectionSettings::Vpn &&
|
||||
(connection->type() != NetworkManager::ConnectionSettings::Wired))) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connection && !connection->devices().isEmpty()) {
|
||||
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(connection->devices().first());
|
||||
|
||||
if (device) {
|
||||
NetworkManager::Device::Type type = device->type();
|
||||
if (type == NetworkManager::Device::Wifi) {
|
||||
NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>();
|
||||
if (wifiDevice->mode() == NetworkManager::WirelessDevice::Adhoc) {
|
||||
setWirelessIconForSignalStrength(100);
|
||||
} else {
|
||||
NetworkManager::AccessPoint::Ptr ap = wifiDevice->activeAccessPoint();
|
||||
if (ap) {
|
||||
setWirelessIcon(device, ap->ssid());
|
||||
}
|
||||
}
|
||||
} else if (type == NetworkManager::Device::Ethernet) {
|
||||
setConnectionIcon("network-wired-activated");
|
||||
setConnectionTooltipIcon("network-wired-activated");
|
||||
} else if (type == NetworkManager::Device::Modem) {
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
setModemIcon(device);
|
||||
#else
|
||||
setConnectionIcon("network-mobile-0");
|
||||
setConnectionTooltipIcon("phone");
|
||||
#endif
|
||||
} else if (type == NetworkManager::Device::Bluetooth) {
|
||||
NetworkManager::BluetoothDevice::Ptr btDevice = device.objectCast<NetworkManager::BluetoothDevice>();
|
||||
if (btDevice) {
|
||||
if (btDevice->bluetoothCapabilities().testFlag(NetworkManager::BluetoothDevice::Dun)) {
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
setModemIcon(device);
|
||||
#else
|
||||
setConnectionIcon("network-mobile-0");
|
||||
setConnectionTooltipIcon("phone");
|
||||
#endif
|
||||
} else {
|
||||
setConnectionIcon("network-bluetooth-activated");
|
||||
setConnectionTooltipIcon("preferences-system-bluetooth");
|
||||
}
|
||||
}
|
||||
} else if (type == 29) { // TODO change to WireGuard enum value once it is added
|
||||
// WireGuard is a VPN but is not implemented
|
||||
// in NetworkManager as a VPN, so we don't want to
|
||||
// do anything just because it has a device
|
||||
// associated with it.
|
||||
} else {
|
||||
// Ignore other devices (bond/bridge/team etc.)
|
||||
setDisconnectedIcon();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setDisconnectedIcon();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setDisconnectedIcon()
|
||||
{
|
||||
// if (Configuration::airplaneModeEnabled()) {
|
||||
// setConnectionIcon(QStringLiteral("network-flightmode-on"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (NetworkManager::status() == NetworkManager::Unknown ||
|
||||
NetworkManager::status() == NetworkManager::Asleep) {
|
||||
setConnectionIcon("network-unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
bool wired = false;
|
||||
bool wireless = false;
|
||||
bool modem = false;
|
||||
|
||||
m_limited = false;
|
||||
m_vpn = false;
|
||||
|
||||
for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) {
|
||||
if (device->type() == NetworkManager::Device::Ethernet) {
|
||||
NetworkManager::WiredDevice::Ptr wiredDev = device.objectCast<NetworkManager::WiredDevice>();
|
||||
if (wiredDev->carrier()) {
|
||||
wired = true;
|
||||
}
|
||||
} else if (device->type() == NetworkManager::Device::Wifi &&
|
||||
NetworkManager::isWirelessEnabled() &&
|
||||
NetworkManager::isWirelessHardwareEnabled()) {
|
||||
NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>();
|
||||
if (!wifiDevice->accessPoints().isEmpty() || !wifiDevice->availableConnections().isEmpty()) {
|
||||
wireless = true;
|
||||
}
|
||||
} else if (device->type() == NetworkManager::Device::Modem &&
|
||||
NetworkManager::isWwanEnabled() &&
|
||||
NetworkManager::isWwanHardwareEnabled()) {
|
||||
modem = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wired) {
|
||||
setConnectionIcon("network-wired-available");
|
||||
setConnectionTooltipIcon("network-wired");
|
||||
return;
|
||||
} else if (wireless) {
|
||||
setConnectionIcon("network-wireless-available");
|
||||
setConnectionTooltipIcon("network-wireless-connected-00");
|
||||
return;
|
||||
} else if (modem) {
|
||||
setConnectionIcon("network-mobile-available");
|
||||
setConnectionTooltipIcon("phone");
|
||||
return;
|
||||
} else {
|
||||
setConnectionIcon("network-unavailable");
|
||||
setConnectionTooltipIcon("network-wired");
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
void ConnectionIcon::setModemIcon(const NetworkManager::Device::Ptr & device)
|
||||
{
|
||||
NetworkManager::ModemDevice::Ptr modemDevice = device.objectCast<NetworkManager::ModemDevice>();
|
||||
|
||||
if (!modemDevice) {
|
||||
setConnectionIcon("network-mobile-100");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(device->udi());
|
||||
if (modem) {
|
||||
if (modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) {
|
||||
m_modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_modemNetwork) {
|
||||
connect(m_modemNetwork.data(), &ModemManager::Modem::signalQualityChanged, this, &ConnectionIcon::modemSignalChanged, Qt::UniqueConnection);
|
||||
connect(m_modemNetwork.data(), &ModemManager::Modem::accessTechnologiesChanged, this, &ConnectionIcon::setIconForModem, Qt::UniqueConnection);
|
||||
connect(m_modemNetwork.data(), &ModemManager::Modem::destroyed, this, &ConnectionIcon::modemNetworkRemoved);
|
||||
|
||||
m_signal = m_modemNetwork->signalQuality().signal;
|
||||
setIconForModem();
|
||||
} else {
|
||||
setConnectionIcon("network-mobile-0");
|
||||
setConnectionTooltipIcon("phone");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setIconForModem()
|
||||
{
|
||||
if (!m_signal) {
|
||||
m_signal = m_modemNetwork->signalQuality().signal;
|
||||
}
|
||||
QString strength = "00";
|
||||
|
||||
if (m_signal == 0) {
|
||||
strength = '0';
|
||||
} else if (m_signal < 20) {
|
||||
strength = "20";
|
||||
} else if (m_signal < 40) {
|
||||
strength = "40";
|
||||
} else if (m_signal < 60) {
|
||||
strength = "60";
|
||||
} else if (m_signal < 80) {
|
||||
strength = "80";
|
||||
} else {
|
||||
strength = "100";
|
||||
}
|
||||
|
||||
QString result;
|
||||
|
||||
switch(m_modemNetwork->accessTechnologies()) {
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_GSM:
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT:
|
||||
result = "network-mobile-%1";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_GPRS:
|
||||
result = "network-mobile-%1-gprs";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_EDGE:
|
||||
result = "network-mobile-%1-edge";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
|
||||
result = "network-mobile-%1-umts";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSDPA:
|
||||
result = "network-mobile-%1-hsdpa";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSUPA:
|
||||
result = "network-mobile-%1-hsupa";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSPA:
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS:
|
||||
result = "network-mobile-%1-hspa";
|
||||
break;
|
||||
case MM_MODEM_ACCESS_TECHNOLOGY_LTE:
|
||||
result = "network-mobile-%1-lte";
|
||||
break;
|
||||
default:
|
||||
result = "network-mobile-%1";
|
||||
break;
|
||||
}
|
||||
|
||||
setConnectionIcon(QString(result).arg(strength));
|
||||
setConnectionTooltipIcon("phone");
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConnectionIcon::setWirelessIcon(const NetworkManager::Device::Ptr &device, const QString& ssid)
|
||||
{
|
||||
NetworkManager::WirelessDevice::Ptr wirelessDevice = device.objectCast<NetworkManager::WirelessDevice>();
|
||||
if (device) {
|
||||
m_wirelessNetwork = wirelessDevice->findNetwork(ssid);
|
||||
} else {
|
||||
m_wirelessNetwork.clear();
|
||||
}
|
||||
|
||||
if (m_wirelessNetwork) {
|
||||
m_currentSSID = ssid;
|
||||
emit currentSSIDChanged();
|
||||
|
||||
connect(m_wirelessNetwork.data(), &NetworkManager::WirelessNetwork::signalStrengthChanged, this, &ConnectionIcon::setWirelessIconForSignalStrength, Qt::UniqueConnection);
|
||||
|
||||
setWirelessIconForSignalStrength(m_wirelessNetwork->signalStrength());
|
||||
} else {
|
||||
setDisconnectedIcon();
|
||||
|
||||
m_currentSSID = "";
|
||||
emit currentSSIDChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setWirelessIconForSignalStrength(int strength)
|
||||
{
|
||||
int iconStrength = 100;
|
||||
if (strength == 0) {
|
||||
iconStrength = 0;
|
||||
setConnectionTooltipIcon("network-wireless-connected-00");
|
||||
} else if (strength <= 25) {
|
||||
iconStrength = 25;
|
||||
setConnectionTooltipIcon("network-wireless-connected-25");
|
||||
} else if (strength <= 50) {
|
||||
iconStrength = 50;
|
||||
setConnectionTooltipIcon("network-wireless-connected-50");
|
||||
} else if (strength < 75) {
|
||||
iconStrength = 75;
|
||||
setConnectionTooltipIcon("network-wireless-connected-75");
|
||||
} else if (strength < 100) {
|
||||
setConnectionTooltipIcon("network-wireless-connected-100");
|
||||
}
|
||||
|
||||
QString icon = QString("network-wireless-%1").arg(iconStrength);
|
||||
|
||||
setConnectionIcon(icon);
|
||||
}
|
||||
|
||||
void ConnectionIcon::setConnecting(bool connecting)
|
||||
{
|
||||
if (connecting != m_connecting) {
|
||||
m_connecting = connecting;
|
||||
Q_EMIT connectingChanged(m_connecting);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setConnectionIcon(const QString & icon)
|
||||
{
|
||||
if (icon != m_connectionIcon) {
|
||||
m_connectionIcon = icon;
|
||||
Q_EMIT connectionIconChanged(connectionIcon());
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setConnectionTooltipIcon(const QString & icon)
|
||||
{
|
||||
if (icon != m_connectionTooltipIcon) {
|
||||
m_connectionTooltipIcon = icon;
|
||||
Q_EMIT connectionTooltipIconChanged(m_connectionTooltipIcon);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setVpn(bool vpn)
|
||||
{
|
||||
if (m_vpn != vpn) {
|
||||
m_vpn = vpn;
|
||||
Q_EMIT connectionIconChanged(connectionIcon());
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionIcon::setLimited(bool limited)
|
||||
{
|
||||
if (m_limited != limited) {
|
||||
m_limited = limited;
|
||||
Q_EMIT connectionIconChanged(connectionIcon());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright 2013 Jan Grulich <jgrulich@redhat.com>
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PLASMA_NM_CONNECTION_ICON_H
|
||||
#define PLASMA_NM_CONNECTION_ICON_H
|
||||
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ActiveConnection>
|
||||
#include <NetworkManagerQt/VpnConnection>
|
||||
#include <NetworkManagerQt/WirelessNetwork>
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
#include <ModemManagerQt/modem.h>
|
||||
#endif
|
||||
|
||||
class ConnectionIcon : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool connecting READ connecting NOTIFY connectingChanged)
|
||||
Q_PROPERTY(QString connectionIcon READ connectionIcon NOTIFY connectionIconChanged)
|
||||
Q_PROPERTY(QString connectionTooltipIcon READ connectionTooltipIcon NOTIFY connectionTooltipIconChanged)
|
||||
Q_PROPERTY(bool needsPortal READ needsPortal NOTIFY needsPortalChanged)
|
||||
Q_PROPERTY(QString currentSSID READ currentSSID NOTIFY currentSSIDChanged)
|
||||
|
||||
public:
|
||||
explicit ConnectionIcon(QObject* parent = nullptr);
|
||||
~ConnectionIcon() override;
|
||||
|
||||
bool connecting() const;
|
||||
QString connectionIcon() const;
|
||||
QString connectionTooltipIcon() const;
|
||||
|
||||
QString currentSSID() const;
|
||||
|
||||
bool needsPortal() const { return m_needsPortal; }
|
||||
|
||||
private Q_SLOTS:
|
||||
void activatingConnectionChanged(const QString & connection);
|
||||
void activeConnectionAdded(const QString & activeConnection);
|
||||
void activeConnectionDestroyed();
|
||||
void activeConnectionStateChanged(NetworkManager::ActiveConnection::State state);
|
||||
void carrierChanged(bool carrier);
|
||||
void connectivityChanged(NetworkManager::Connectivity connectivity);
|
||||
void deviceAdded(const QString & device);
|
||||
void deviceRemoved(const QString & device);
|
||||
void networkingEnabledChanged(bool enabled);
|
||||
void primaryConnectionChanged(const QString & connection);
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
void modemNetworkRemoved();
|
||||
void modemSignalChanged(const ModemManager::SignalQualityPair &signalQuality);
|
||||
void setIconForModem();
|
||||
#endif
|
||||
void statusChanged(NetworkManager::Status status);
|
||||
void setWirelessIconForSignalStrength(int strength);
|
||||
void vpnConnectionStateChanged(NetworkManager::VpnConnection::State state, NetworkManager::VpnConnection::StateChangeReason reason);
|
||||
void wirelessEnabledChanged(bool enabled);
|
||||
void wirelessNetworkAppeared(const QString &network);
|
||||
void wwanEnabledChanged(bool enabled);
|
||||
Q_SIGNALS:
|
||||
void connectingChanged(bool connecting);
|
||||
void connectionIconChanged(const QString & icon);
|
||||
void connectionTooltipIconChanged(const QString & icon);
|
||||
void needsPortalChanged(bool needsPortal);
|
||||
void currentSSIDChanged();
|
||||
|
||||
private:
|
||||
void addActiveConnection(const QString & activeConnection);
|
||||
void setConnecting(bool connecting);
|
||||
void setConnectionIcon(const QString & icon);
|
||||
void setConnectionTooltipIcon(const QString & icon);
|
||||
void setVpn(bool vpn);
|
||||
void setLimited(bool limited);
|
||||
uint m_signal;
|
||||
NetworkManager::WirelessNetwork::Ptr m_wirelessNetwork;
|
||||
|
||||
QString m_currentSSID;
|
||||
|
||||
bool m_connecting;
|
||||
bool m_limited;
|
||||
bool m_vpn;
|
||||
QString m_connectionIcon;
|
||||
QString m_connectionTooltipIcon;
|
||||
bool m_needsPortal = false;
|
||||
|
||||
void setDisconnectedIcon();
|
||||
void setIcons();
|
||||
void setStates();
|
||||
void setWirelessIcon(const NetworkManager::Device::Ptr & device, const QString & ssid);
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
ModemManager::Modem::Ptr m_modemNetwork;
|
||||
void setModemIcon(const NetworkManager::Device::Ptr & device);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // PLASMA_NM_CONNECTION_ICON_H
|
||||
@ -0,0 +1,322 @@
|
||||
#include "network.h"
|
||||
#include "uiutils.h"
|
||||
#include <QDebug>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
Network::Network(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_wirelessNetwork(nullptr)
|
||||
{
|
||||
::passwd *pw = ::getpwuid(::getuid());
|
||||
m_userName = QString::fromLocal8Bit(pw->pw_name);
|
||||
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::networkingEnabledChanged, this, &Network::enabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, this, &Network::onWirelessEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessHardwareEnabledChanged, this, &Network::wirelessHardwareEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &Network::statusChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::activatingConnectionChanged, this, &Network::activatingConnectionChanged);
|
||||
|
||||
for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) {
|
||||
if (device->type() == NetworkManager::Device::Wifi) {
|
||||
NetworkManager::WirelessDevice::Ptr wifiDevice = device.staticCast<NetworkManager::WirelessDevice>();
|
||||
if (wifiDevice) {
|
||||
connect(wifiDevice.data(), &NetworkManager::WirelessDevice::availableConnectionAppeared, this, &Network::onWirelessNetworkAppeared);
|
||||
connect(wifiDevice.data(), &NetworkManager::WirelessDevice::networkAppeared, this, &Network::onWirelessNetworkAppeared);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statusChanged(NetworkManager::status());
|
||||
changeActiveConnections();
|
||||
updateIcons();
|
||||
}
|
||||
|
||||
bool Network::isEnabled() const
|
||||
{
|
||||
return NetworkManager::isNetworkingEnabled();
|
||||
}
|
||||
|
||||
void Network::setEnabled(bool enabled)
|
||||
{
|
||||
NetworkManager::setNetworkingEnabled(enabled);
|
||||
}
|
||||
|
||||
bool Network::isWirelessEnabled() const
|
||||
{
|
||||
return NetworkManager::isWirelessEnabled();
|
||||
}
|
||||
|
||||
void Network::setWirelessEnabled(bool enabled)
|
||||
{
|
||||
NetworkManager::setWirelessEnabled(enabled);
|
||||
}
|
||||
|
||||
bool Network::isWirelessHardwareEnabled() const
|
||||
{
|
||||
return NetworkManager::isWirelessHardwareEnabled();
|
||||
}
|
||||
|
||||
QString Network::wirelessConnectionName() const
|
||||
{
|
||||
return m_wirelessConnectionName;
|
||||
}
|
||||
|
||||
QString Network::wirelessIconName() const
|
||||
{
|
||||
return m_wirelessIconName;
|
||||
}
|
||||
|
||||
Network::SortedConnectionType Network::connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type)
|
||||
{
|
||||
switch (type) {
|
||||
case NetworkManager::ConnectionSettings::Adsl:
|
||||
return Network::Adsl;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bluetooth:
|
||||
return Network::Bluetooth;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Cdma:
|
||||
return Network::Cdma;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Gsm:
|
||||
return Network::Gsm;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Infiniband:
|
||||
return Network::Infiniband;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::OLPCMesh:
|
||||
return Network::OLPCMesh;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Pppoe:
|
||||
return Network::Pppoe;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Vpn:
|
||||
return Network::Vpn;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wired:
|
||||
return Network::Wired;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wireless:
|
||||
return Network::Wireless;
|
||||
break;
|
||||
default:
|
||||
return Network::Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Network::statusChanged(NetworkManager::Status status)
|
||||
{
|
||||
if (status == NetworkManager::ConnectedLinkLocal ||
|
||||
status == NetworkManager::ConnectedSiteOnly ||
|
||||
status == NetworkManager::Connected) {
|
||||
changeActiveConnections();
|
||||
}
|
||||
|
||||
if (status == NetworkManager::Disconnected) {
|
||||
resetWireless();
|
||||
}
|
||||
}
|
||||
|
||||
void Network::changeActiveConnections()
|
||||
{
|
||||
if (NetworkManager::status() != NetworkManager::Connected &&
|
||||
NetworkManager::status() != NetworkManager::ConnectedLinkLocal &&
|
||||
NetworkManager::status() != NetworkManager::ConnectedSiteOnly) {
|
||||
|
||||
m_wirelessConnectionName = "";
|
||||
emit wirelessConnectionNameChanged();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QString activeConnections;
|
||||
QList<NetworkManager::ActiveConnection::Ptr> activeConnectionList = NetworkManager::activeConnections();
|
||||
std::sort(activeConnectionList.begin(), activeConnectionList.end(), [](const NetworkManager::ActiveConnection::Ptr &left, const NetworkManager::ActiveConnection::Ptr &right) {
|
||||
return Network::connectionTypeToSortedType(left->type()) < Network::connectionTypeToSortedType(right->type());
|
||||
});
|
||||
|
||||
for (const NetworkManager::ActiveConnection::Ptr &active : activeConnectionList) {
|
||||
if (active->devices().isEmpty() && !UiUtils::isConnectionTypeSupported(active->type()))
|
||||
continue;
|
||||
|
||||
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first());
|
||||
NetworkManager::Connection::Ptr connection = active->connection();
|
||||
bool connecting = false;
|
||||
bool connected = false;
|
||||
|
||||
if (active->state() == NetworkManager::ActiveConnection::Activated)
|
||||
connected = true;
|
||||
else if (active->state() == NetworkManager::ActiveConnection::Activating)
|
||||
connecting = true;
|
||||
|
||||
if (device->type() == NetworkManager::Device::Wifi) {
|
||||
if (m_wirelessConnectionName != connection->name()) {
|
||||
m_wirelessConnectionName = connection->name();
|
||||
emit wirelessConnectionNameChanged();
|
||||
|
||||
updateIcons();
|
||||
}
|
||||
}
|
||||
|
||||
connect(connection.data(), &NetworkManager::Connection::updated, this, &Network::changeActiveConnections, Qt::UniqueConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void Network::activatingConnectionChanged()
|
||||
{
|
||||
updateIcons();
|
||||
}
|
||||
|
||||
void Network::defaultChanged()
|
||||
{
|
||||
statusChanged(NetworkManager::status());
|
||||
}
|
||||
|
||||
void Network::onWirelessEnabledChanged()
|
||||
{
|
||||
if (!isWirelessEnabled()) {
|
||||
resetWireless();
|
||||
} else {
|
||||
updateIcons();
|
||||
}
|
||||
|
||||
emit wirelessEnabledChanged();
|
||||
}
|
||||
|
||||
void Network::onWirelessNetworkAppeared(const QString& network)
|
||||
{
|
||||
Q_UNUSED(network);
|
||||
|
||||
updateIcons();
|
||||
}
|
||||
|
||||
void Network::updateIcons()
|
||||
{
|
||||
if (m_wirelessNetwork) {
|
||||
disconnect(m_wirelessNetwork.data(), nullptr, this, nullptr);
|
||||
m_wirelessNetwork.clear();
|
||||
}
|
||||
|
||||
NetworkManager::ActiveConnection::Ptr connection = NetworkManager::activatingConnection();
|
||||
|
||||
// Set icon based on the current primary connection if the activating connection is virtual
|
||||
// since we're not setting icons for virtual connections
|
||||
if (!connection
|
||||
|| (connection && UiUtils::isConnectionTypeVirtual(connection->type()))
|
||||
|| connection->type() == NetworkManager::ConnectionSettings::WireGuard) {
|
||||
connection = NetworkManager::primaryConnection();
|
||||
}
|
||||
|
||||
/* Fallback: If we still don't have an active connection with default route or the default route goes through a connection
|
||||
of generic type (some type of VPNs) we need to go through all other active connections and pick the one with
|
||||
highest probability of being the main one (order is: vpn, wired, wireless, gsm, cdma, bluetooth) */
|
||||
if ((!connection && !NetworkManager::activeConnections().isEmpty()) || (connection && connection->type() == NetworkManager::ConnectionSettings::Generic)
|
||||
|| (connection && connection->type() == NetworkManager::ConnectionSettings::Tun)) {
|
||||
for (const NetworkManager::ActiveConnection::Ptr &activeConnection : NetworkManager::activeConnections()) {
|
||||
const NetworkManager::ConnectionSettings::ConnectionType type = activeConnection->type();
|
||||
if (type == NetworkManager::ConnectionSettings::Bluetooth) {
|
||||
if (connection && connection->type() <= NetworkManager::ConnectionSettings::Bluetooth) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Cdma) {
|
||||
if (connection && connection->type() <= NetworkManager::ConnectionSettings::Cdma) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Gsm) {
|
||||
if (connection && connection->type() <= NetworkManager::ConnectionSettings::Gsm) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Vpn) {
|
||||
connection = activeConnection;
|
||||
} else if (type == NetworkManager::ConnectionSettings::WireGuard) {
|
||||
connection = activeConnection;
|
||||
} else if (type == NetworkManager::ConnectionSettings::Wired) {
|
||||
if (connection && (connection->type() != NetworkManager::ConnectionSettings::Vpn
|
||||
|| connection->type() != NetworkManager::ConnectionSettings::WireGuard)) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
} else if (type == NetworkManager::ConnectionSettings::Wireless) {
|
||||
if (connection && (connection->type() != NetworkManager::ConnectionSettings::Vpn &&
|
||||
(connection->type() != NetworkManager::ConnectionSettings::Wired))) {
|
||||
connection = activeConnection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connection && !connection->devices().isEmpty()) {
|
||||
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(connection->devices().first());
|
||||
|
||||
if (device) {
|
||||
NetworkManager::Device::Type type = device->type();
|
||||
|
||||
if (type == NetworkManager::Device::Wifi) {
|
||||
NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast<NetworkManager::WirelessDevice>();
|
||||
|
||||
if (wifiDevice->mode() == NetworkManager::WirelessDevice::Adhoc) {
|
||||
updateWirelessIconForSignalStrength(100);
|
||||
} else {
|
||||
NetworkManager::AccessPoint::Ptr ap = wifiDevice->activeAccessPoint();
|
||||
if (ap) {
|
||||
updateWirelessIcon(device, ap->ssid());
|
||||
}
|
||||
}
|
||||
} else if (type == NetworkManager::Device::Ethernet) {
|
||||
|
||||
} else {
|
||||
resetWireless();
|
||||
}
|
||||
} else {
|
||||
resetWireless();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Network::updateWirelessIcon(const NetworkManager::Device::Ptr &device, const QString& ssid)
|
||||
{
|
||||
NetworkManager::WirelessDevice::Ptr wirelessDevice = device.objectCast<NetworkManager::WirelessDevice>();
|
||||
|
||||
if (device) {
|
||||
m_wirelessNetwork = wirelessDevice->findNetwork(ssid);
|
||||
} else {
|
||||
m_wirelessNetwork.clear();
|
||||
}
|
||||
|
||||
if (m_wirelessNetwork) {
|
||||
connect(m_wirelessNetwork.data(), &NetworkManager::WirelessNetwork::signalStrengthChanged, this, &Network::updateWirelessIconForSignalStrength, Qt::UniqueConnection);
|
||||
updateWirelessIconForSignalStrength(m_wirelessNetwork->signalStrength());
|
||||
} else {
|
||||
resetWireless();
|
||||
}
|
||||
}
|
||||
|
||||
void Network::updateWirelessIconForSignalStrength(int strength)
|
||||
{
|
||||
int iconStrength = 0;
|
||||
|
||||
if (strength == 0)
|
||||
iconStrength = 0;
|
||||
else if (strength <= 25)
|
||||
iconStrength = 25;
|
||||
else if (strength <= 50)
|
||||
iconStrength = 50;
|
||||
else if (strength <= 75)
|
||||
iconStrength = 75;
|
||||
else if (strength <= 100)
|
||||
iconStrength = 100;
|
||||
|
||||
m_wirelessIconName = QString("network-wireless-connected-%1").arg(iconStrength);
|
||||
emit wirelessIconNameChanged();
|
||||
}
|
||||
|
||||
void Network::resetWireless()
|
||||
{
|
||||
m_wirelessConnectionName = "";
|
||||
m_wirelessIconName = "";
|
||||
|
||||
emit wirelessConnectionNameChanged();
|
||||
emit wirelessIconNameChanged();
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
#ifndef NETWORK_H
|
||||
#define NETWORK_H
|
||||
|
||||
#include <QObject>
|
||||
#include <NetworkManagerQt/Device>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/WirelessNetwork>
|
||||
|
||||
class Network : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
Q_PROPERTY(bool wirelessEnabled READ isWirelessEnabled WRITE setWirelessEnabled NOTIFY wirelessEnabledChanged)
|
||||
Q_PROPERTY(bool wirelessHardwareEnabled READ isWirelessHardwareEnabled NOTIFY wirelessHardwareEnabledChanged)
|
||||
Q_PROPERTY(QString wirelessConnectionName READ wirelessConnectionName NOTIFY wirelessConnectionNameChanged)
|
||||
Q_PROPERTY(QString wirelessIconName READ wirelessIconName NOTIFY wirelessIconNameChanged)
|
||||
|
||||
public:
|
||||
enum SortedConnectionType {
|
||||
Wired,
|
||||
Wireless,
|
||||
Gsm,
|
||||
Cdma,
|
||||
Pppoe,
|
||||
Adsl,
|
||||
Infiniband,
|
||||
OLPCMesh,
|
||||
Bluetooth,
|
||||
Vpn,
|
||||
Other
|
||||
};
|
||||
Q_ENUM(SortedConnectionType)
|
||||
|
||||
explicit Network(QObject *parent = nullptr);
|
||||
|
||||
bool isEnabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
bool isWirelessEnabled() const;
|
||||
void setWirelessEnabled(bool enabled);
|
||||
|
||||
bool isWirelessHardwareEnabled() const;
|
||||
|
||||
QString wirelessConnectionName() const;
|
||||
QString wirelessIconName() const;
|
||||
|
||||
static SortedConnectionType connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type);
|
||||
|
||||
signals:
|
||||
void enabledChanged();
|
||||
void wirelessEnabledChanged();
|
||||
void wirelessHardwareEnabledChanged();
|
||||
void wirelessConnectionNameChanged();
|
||||
void wirelessIconNameChanged();
|
||||
|
||||
private slots:
|
||||
void statusChanged(NetworkManager::Status status);
|
||||
void changeActiveConnections();
|
||||
void activatingConnectionChanged();
|
||||
void defaultChanged();
|
||||
|
||||
void onWirelessEnabledChanged();
|
||||
void onWirelessNetworkAppeared(const QString& network);
|
||||
|
||||
void updateIcons();
|
||||
void updateWirelessIcon(const NetworkManager::Device::Ptr &device, const QString& ssid);
|
||||
void updateWirelessIconForSignalStrength(int strength);
|
||||
|
||||
void resetWireless();
|
||||
|
||||
private:
|
||||
QString m_userName;
|
||||
QString m_wirelessConnectionName;
|
||||
QString m_wirelessIconName;
|
||||
NetworkManager::WirelessNetwork::Ptr m_wirelessNetwork;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,525 @@
|
||||
/*
|
||||
Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
Copyright 2013-2014 Jan Grulich <jgrulich@redhat.com>
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/VpnSetting>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
# include <NetworkManagerQt/GsmSetting>
|
||||
# include <NetworkManagerQt/ModemDevice>
|
||||
# include <ModemManagerQt/ModemDevice>
|
||||
#endif
|
||||
|
||||
#include "uiutils.h"
|
||||
#include "networking.h"
|
||||
#include "networkmodel.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
Networking::Networking(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_lastWirelessEnabled(isWirelessEnabled())
|
||||
, m_lastMobileEnabled(isMobileEnabled())
|
||||
{
|
||||
::passwd *pw = ::getpwuid(::getuid());
|
||||
m_userName = QString::fromLocal8Bit(pw->pw_name);
|
||||
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::networkingEnabledChanged,
|
||||
this, &Networking::enabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged,
|
||||
this, &Networking::wirelessEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessHardwareEnabledChanged,
|
||||
this, &Networking::wirelessHardwareEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wwanEnabledChanged,
|
||||
this, &Networking::mobileEnabledChanged);
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::wwanHardwareEnabledChanged,
|
||||
this, &Networking::mobileHardwareEnabledChanged);
|
||||
|
||||
connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged,
|
||||
this, &Networking::statusChanged);
|
||||
doChangeActiveConnections();
|
||||
statusChanged(NetworkManager::status());
|
||||
}
|
||||
|
||||
bool Networking::isEnabled() const
|
||||
{
|
||||
return NetworkManager::isNetworkingEnabled();
|
||||
}
|
||||
|
||||
void Networking::setEnabled(bool enabled)
|
||||
{
|
||||
NetworkManager::setNetworkingEnabled(enabled);
|
||||
}
|
||||
|
||||
bool Networking::isWirelessEnabled() const
|
||||
{
|
||||
return NetworkManager::isWirelessEnabled();
|
||||
}
|
||||
|
||||
void Networking::setWirelessEnabled(bool enabled)
|
||||
{
|
||||
NetworkManager::setWirelessEnabled(enabled);
|
||||
}
|
||||
|
||||
bool Networking::isWirelessHardwareEnabled() const
|
||||
{
|
||||
return NetworkManager::isWirelessHardwareEnabled();
|
||||
}
|
||||
|
||||
bool Networking::isMobileEnabled() const
|
||||
{
|
||||
return NetworkManager::isWwanEnabled();
|
||||
}
|
||||
|
||||
void Networking::setMobileEnabled(bool enabled)
|
||||
{
|
||||
NetworkManager::setWwanEnabled(enabled);
|
||||
}
|
||||
|
||||
bool Networking::isMobileHardwareEnabled() const
|
||||
{
|
||||
return NetworkManager::isWwanHardwareEnabled();
|
||||
}
|
||||
|
||||
bool Networking::isAirplaneModeEnabled() const
|
||||
{
|
||||
return !isWirelessEnabled() && !isMobileEnabled();
|
||||
}
|
||||
|
||||
void Networking::setAirplaneModeEnabled(bool enabled)
|
||||
{
|
||||
if (isAirplaneModeEnabled() == enabled)
|
||||
return;
|
||||
|
||||
m_lastWirelessEnabled = isWirelessEnabled();
|
||||
m_lastMobileEnabled = isMobileEnabled();
|
||||
|
||||
if (enabled) {
|
||||
setWirelessEnabled(false);
|
||||
setMobileEnabled(false);
|
||||
} else {
|
||||
if (m_lastWirelessEnabled)
|
||||
setWirelessEnabled(true);
|
||||
if (m_lastMobileEnabled)
|
||||
setMobileEnabled(true);
|
||||
}
|
||||
|
||||
Q_EMIT airplaneModeEnabledChanged();
|
||||
}
|
||||
|
||||
QString Networking::activeConnections() const
|
||||
{
|
||||
return m_activeConnections;
|
||||
}
|
||||
|
||||
QString Networking::networkStatus() const
|
||||
{
|
||||
return m_networkStatus;
|
||||
}
|
||||
|
||||
void Networking::activateConnection(const QString &connectionPath, const QString &device, const QString &specificObject)
|
||||
{
|
||||
NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionPath);
|
||||
|
||||
if (!connection) {
|
||||
qCWarning(gLcNm, "Unable to activate connection \"%s\"", qPrintable(connectionPath));
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->settings()->connectionType() == NetworkManager::ConnectionSettings::Vpn) {
|
||||
NetworkManager::VpnSetting::Ptr vpnSetting = connection->settings()->setting(NetworkManager::Setting::Vpn).staticCast<NetworkManager::VpnSetting>();
|
||||
if (vpnSetting) {
|
||||
qCDebug(gLcNm, "Checking VPN \"%s\" type \"%s\"", qPrintable(connection->name()), qPrintable(vpnSetting->serviceType()));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
if (connection->settings()->connectionType() == NetworkManager::ConnectionSettings::Gsm) {
|
||||
NetworkManager::ModemDevice::Ptr nmModemDevice = NetworkManager::findNetworkInterface(device).objectCast<NetworkManager::ModemDevice>();
|
||||
if (nmModemDevice) {
|
||||
ModemManager::ModemDevice::Ptr mmModemDevice = ModemManager::findModemDevice(nmModemDevice->udi());
|
||||
if (mmModemDevice) {
|
||||
ModemManager::Modem::Ptr modem = mmModemDevice->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
|
||||
NetworkManager::GsmSetting::Ptr gsmSetting = connection->settings()->setting(NetworkManager::Setting::Gsm).staticCast<NetworkManager::GsmSetting>();
|
||||
if (gsmSetting && gsmSetting->pinFlags() == NetworkManager::Setting::NotSaved &&
|
||||
modem && modem->unlockRequired() > MM_MODEM_LOCK_NONE) {
|
||||
QDBusInterface managerIface("org.kde.plasmanetworkmanagement", "/org/kde/plasmanetworkmanagement", "org.kde.plasmanetworkmanagement", QDBusConnection::sessionBus(), this);
|
||||
managerIface.call("unlockModem", mmModemDevice->uni());
|
||||
connect(modem.data(), &ModemManager::Modem::unlockRequiredChanged, this, &Handler::unlockRequiredChanged);
|
||||
// m_tmpConnectionPath = connectionPath;
|
||||
// m_tmpDevicePath = device;
|
||||
// m_tmpSpecificPath = specificObject;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::activateConnection(connectionPath, device, specificObject);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
watcher->setProperty("connectionName", connection->name());
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) {
|
||||
QDBusPendingReply<> reply = *self;
|
||||
|
||||
if (reply.isError() || !reply.isValid()) {
|
||||
const QString error = reply.error().message();
|
||||
const QString connectionName = self->property("connectionName").toString();
|
||||
}
|
||||
|
||||
self->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
void Networking::addAndActivateConnection(const QString &device, const QString &specificObject, const QString &password)
|
||||
{
|
||||
NetworkManager::AccessPoint::Ptr ap;
|
||||
NetworkManager::WirelessDevice::Ptr wifiDev;
|
||||
for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) {
|
||||
if (dev->type() == NetworkManager::Device::Wifi) {
|
||||
wifiDev = dev.objectCast<NetworkManager::WirelessDevice>();
|
||||
ap = wifiDev->findAccessPoint(specificObject);
|
||||
if (ap)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ap)
|
||||
return;
|
||||
|
||||
NetworkManager::ConnectionSettings::Ptr settings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless));
|
||||
settings->setId(ap->ssid());
|
||||
settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid());
|
||||
settings->setAutoconnect(true);
|
||||
settings->addToPermissions(m_userName, QString());
|
||||
|
||||
NetworkManager::WirelessSetting::Ptr wifiSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>();
|
||||
wifiSetting->setInitialized(true);
|
||||
wifiSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast<NetworkManager::WirelessSetting>();
|
||||
wifiSetting->setSsid(ap->ssid().toUtf8());
|
||||
if (ap->mode() == NetworkManager::AccessPoint::Adhoc) {
|
||||
wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc);
|
||||
}
|
||||
|
||||
NetworkManager::WirelessSecuritySetting::Ptr wifiSecurity = settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast<NetworkManager::WirelessSecuritySetting>();
|
||||
NetworkManager::WirelessSecurityType securityType = NetworkManager::findBestWirelessSecurity(wifiDev->wirelessCapabilities(), true, (ap->mode() == NetworkManager::AccessPoint::Adhoc), ap->capabilities(), ap->wpaFlags(), ap->rsnFlags());
|
||||
|
||||
if (securityType != NetworkManager::NoneSecurity) {
|
||||
wifiSecurity->setInitialized(true);
|
||||
wifiSetting->setSecurity("802-11-wireless-security");
|
||||
}
|
||||
|
||||
if (securityType == NetworkManager::Leap ||
|
||||
securityType == NetworkManager::DynamicWep ||
|
||||
securityType == NetworkManager::Wpa2Eap ||
|
||||
securityType == NetworkManager::WpaEap) {
|
||||
if (securityType == NetworkManager::DynamicWep || securityType == NetworkManager::Leap) {
|
||||
wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Ieee8021x);
|
||||
if (securityType == NetworkManager::Leap)
|
||||
wifiSecurity->setAuthAlg(NetworkManager::WirelessSecuritySetting::Leap);
|
||||
} else {
|
||||
wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap);
|
||||
}
|
||||
// m_tmpConnectionUuid = settings->uuid();
|
||||
// m_tmpDevicePath = device;
|
||||
// m_tmpSpecificPath = specificObject;
|
||||
|
||||
// TODO: Edit connection?
|
||||
} else {
|
||||
if (securityType == NetworkManager::StaticWep) {
|
||||
wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::Wep);
|
||||
wifiSecurity->setWepKey0(password);
|
||||
#if 0
|
||||
if (KWallet::Wallet::isEnabled())
|
||||
wifiSecurity->setWepKeyFlags(NetworkManager::Setting::AgentOwned);
|
||||
#endif
|
||||
} else {
|
||||
if (ap->mode() == NetworkManager::AccessPoint::Adhoc)
|
||||
wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone);
|
||||
else
|
||||
wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk);
|
||||
wifiSecurity->setPsk(password);
|
||||
#if 0
|
||||
if (KWallet::Wallet::isEnabled())
|
||||
wifiSecurity->setPskFlags(NetworkManager::Setting::AgentOwned);
|
||||
#endif
|
||||
}
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addAndActivateConnection(settings->toMap(), device, specificObject);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
watcher->setProperty("connectionName", settings->name());
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) {
|
||||
QDBusPendingReply<> reply = *self;
|
||||
|
||||
if (reply.isError() || !reply.isValid()) {
|
||||
const QString error = reply.error().message();
|
||||
const QString connectionName = self->property("connectionName").toString();
|
||||
}
|
||||
|
||||
self->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
settings.clear();
|
||||
}
|
||||
|
||||
void Networking::deactivateConnection(const QString &connectionName, const QString &device)
|
||||
{
|
||||
NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionName);
|
||||
|
||||
if (!connection) {
|
||||
qCWarning(gLcNm, "Failed to deactivate connection \"%s\"", qPrintable(connectionName));
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply;
|
||||
for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) {
|
||||
if (active->uuid() == connection->uuid() && ((!active->devices().isEmpty() && active->devices().first() == device) ||
|
||||
active->vpn())) {
|
||||
if (active->vpn()) {
|
||||
reply = NetworkManager::deactivateConnection(active->path());
|
||||
} else {
|
||||
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first());
|
||||
if (device)
|
||||
reply = device->disconnectInterface();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) {
|
||||
QDBusPendingReply<> reply = *self;
|
||||
|
||||
if (reply.isError() || !reply.isValid()) {
|
||||
const QString error = reply.error().message();
|
||||
const QString connectionName = self->property("connectionName").toString();
|
||||
}
|
||||
|
||||
self->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
void Networking::removeConnection(const QString &connectionPath)
|
||||
{
|
||||
NetworkManager::Connection::Ptr con = NetworkManager::findConnection(connectionPath);
|
||||
|
||||
if (!con || con->uuid().isEmpty()) {
|
||||
qCWarning(gLcNm) << "Not possible to remove connection " << connectionPath;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove slave connections
|
||||
for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) {
|
||||
NetworkManager::ConnectionSettings::Ptr settings = connection->settings();
|
||||
if (settings->master() == con->uuid()) {
|
||||
connection->remove();
|
||||
}
|
||||
}
|
||||
|
||||
QDBusPendingReply<> reply = con->remove();
|
||||
// QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
|
||||
// watcher->setProperty("action", Networking::RemoveConnection);
|
||||
// watcher->setProperty("connection", con->name());
|
||||
// connect(watcher, &QDBusPendingCallWatcher::finished, this, [=] (QDBusPendingCallWatcher * watcher) {
|
||||
// });
|
||||
}
|
||||
|
||||
Networking::SortedConnectionType Networking::connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type)
|
||||
{
|
||||
switch (type) {
|
||||
case NetworkManager::ConnectionSettings::Adsl:
|
||||
return Networking::Adsl;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bluetooth:
|
||||
return Networking::Bluetooth;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Cdma:
|
||||
return Networking::Cdma;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Gsm:
|
||||
return Networking::Gsm;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Infiniband:
|
||||
return Networking::Infiniband;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::OLPCMesh:
|
||||
return Networking::OLPCMesh;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Pppoe:
|
||||
return Networking::Pppoe;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Vpn:
|
||||
return Networking::Vpn;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wired:
|
||||
return Networking::Wired;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wireless:
|
||||
return Networking::Wireless;
|
||||
break;
|
||||
default:
|
||||
return Networking::Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Networking::doChangeActiveConnections()
|
||||
{
|
||||
for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) {
|
||||
connect(active.data(), &NetworkManager::ActiveConnection::default4Changed,
|
||||
this, &Networking::defaultChanged,
|
||||
Qt::UniqueConnection);
|
||||
connect(active.data(), &NetworkManager::ActiveConnection::default6Changed,
|
||||
this, &Networking::defaultChanged,
|
||||
Qt::UniqueConnection);
|
||||
connect(active.data(), &NetworkManager::ActiveConnection::stateChanged,
|
||||
this, &Networking::changeActiveConnections);
|
||||
}
|
||||
|
||||
changeActiveConnections();
|
||||
}
|
||||
|
||||
QString Networking::checkUnknownReason() const
|
||||
{
|
||||
// Check if NetworkManager is running.
|
||||
if (!QDBusConnection::systemBus().interface()->isServiceRegistered(QLatin1String(NM_DBUS_INTERFACE)))
|
||||
return tr("NetworkManager not running");
|
||||
|
||||
// Check for compatible NetworkManager version.
|
||||
if (NetworkManager::compareVersion(0, 9, 8) < 0)
|
||||
return tr("NetworkManager 0.9.8 required, found %1").arg(NetworkManager::version());
|
||||
|
||||
return tr("Unknown");
|
||||
}
|
||||
|
||||
void Networking::statusChanged(NetworkManager::Status status)
|
||||
{
|
||||
switch (status) {
|
||||
case NetworkManager::ConnectedLinkLocal:
|
||||
case NetworkManager::ConnectedSiteOnly:
|
||||
case NetworkManager::Connected:
|
||||
m_networkStatus = tr("Connected");
|
||||
break;
|
||||
case NetworkManager::Asleep:
|
||||
m_networkStatus = tr("Inactive");
|
||||
break;
|
||||
case NetworkManager::Disconnected:
|
||||
m_networkStatus = tr("Disconnected");
|
||||
break;
|
||||
case NetworkManager::Disconnecting:
|
||||
m_networkStatus = tr("Disconnecting");
|
||||
break;
|
||||
case NetworkManager::Connecting:
|
||||
m_networkStatus = tr("Connecting");
|
||||
break;
|
||||
default:
|
||||
m_networkStatus = checkUnknownReason();
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == NetworkManager::ConnectedLinkLocal ||
|
||||
status == NetworkManager::ConnectedSiteOnly ||
|
||||
status == NetworkManager::Connected) {
|
||||
changeActiveConnections();
|
||||
} else {
|
||||
m_activeConnections = m_networkStatus;
|
||||
Q_EMIT activeConnectionsChanged();
|
||||
}
|
||||
|
||||
Q_EMIT networkStatusChanged();
|
||||
}
|
||||
|
||||
void Networking::changeActiveConnections()
|
||||
{
|
||||
if (NetworkManager::status() != NetworkManager::Connected &&
|
||||
NetworkManager::status() != NetworkManager::ConnectedLinkLocal &&
|
||||
NetworkManager::status() != NetworkManager::ConnectedSiteOnly)
|
||||
return;
|
||||
|
||||
QString activeConnections;
|
||||
const QString format = tr("%1: %2");
|
||||
|
||||
QList<NetworkManager::ActiveConnection::Ptr> activeConnectionList = NetworkManager::activeConnections();
|
||||
std::sort(activeConnectionList.begin(), activeConnectionList.end(), [](const NetworkManager::ActiveConnection::Ptr &left, const NetworkManager::ActiveConnection::Ptr &right) {
|
||||
return Networking::connectionTypeToSortedType(left->type()) < Networking::connectionTypeToSortedType(right->type());
|
||||
});
|
||||
|
||||
for (const NetworkManager::ActiveConnection::Ptr &active : activeConnectionList) {
|
||||
if (!active->devices().isEmpty() && UiUtils::isConnectionTypeSupported(active->type())) {
|
||||
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first());
|
||||
if (device && device->type() != NetworkManager::Device::Generic && device->type() <= NetworkManager::Device::Team) {
|
||||
bool connecting = false;
|
||||
bool connected = false;
|
||||
QString conType;
|
||||
QString status;
|
||||
NetworkManager::VpnConnection::Ptr vpnConnection;
|
||||
|
||||
if (active->vpn()) {
|
||||
conType = tr("VPN");
|
||||
vpnConnection = active.objectCast<NetworkManager::VpnConnection>();
|
||||
} else {
|
||||
conType = UiUtils::interfaceTypeLabel(device->type(), device);
|
||||
}
|
||||
|
||||
if (vpnConnection && active->vpn()) {
|
||||
if (vpnConnection->state() >= NetworkManager::VpnConnection::Prepare &&
|
||||
vpnConnection->state() <= NetworkManager::VpnConnection::GettingIpConfig)
|
||||
connecting = true;
|
||||
else if (vpnConnection->state() == NetworkManager::VpnConnection::Activated)
|
||||
connected = true;
|
||||
} else {
|
||||
if (active->state() == NetworkManager::ActiveConnection::Activated)
|
||||
connected = true;
|
||||
else if (active->state() == NetworkManager::ActiveConnection::Activating)
|
||||
connecting = true;
|
||||
}
|
||||
|
||||
NetworkManager::Connection::Ptr connection = active->connection();
|
||||
if (connecting) {
|
||||
status = tr("Connecting to %1").arg(connection->name());
|
||||
} else if (connected) {
|
||||
status = tr("Connected to %1").arg(connection->name());
|
||||
}
|
||||
|
||||
if (!activeConnections.isEmpty())
|
||||
activeConnections += QLatin1Char('\n');
|
||||
activeConnections += format.arg(conType, status);
|
||||
|
||||
connect(connection.data(), &NetworkManager::Connection::updated,
|
||||
this, &Networking::changeActiveConnections,
|
||||
Qt::UniqueConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_activeConnections = activeConnections;
|
||||
Q_EMIT activeConnectionsChanged();
|
||||
}
|
||||
|
||||
void Networking::defaultChanged()
|
||||
{
|
||||
statusChanged(NetworkManager::status());
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
Copyright 2013-2014 Jan Grulich <jgrulich@redhat.com>
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORKING_H
|
||||
#define NETWORKING_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
#include <QObject>
|
||||
|
||||
#include <NetworkManagerQt/Device>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
|
||||
class NETWORKMANAGER_EXPORT Networking : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
Q_PROPERTY(bool wirelessEnabled READ isWirelessEnabled WRITE setWirelessEnabled NOTIFY wirelessEnabledChanged)
|
||||
Q_PROPERTY(bool wirelessHardwareEnabled READ isWirelessHardwareEnabled NOTIFY wirelessHardwareEnabledChanged)
|
||||
Q_PROPERTY(bool mobileEnabled READ isMobileEnabled WRITE setMobileEnabled NOTIFY mobileEnabledChanged)
|
||||
Q_PROPERTY(bool mobileHardwareEnabled READ isMobileHardwareEnabled NOTIFY mobileHardwareEnabledChanged)
|
||||
Q_PROPERTY(bool airplaneModeEnabled READ isAirplaneModeEnabled WRITE setAirplaneModeEnabled NOTIFY airplaneModeEnabledChanged)
|
||||
Q_PROPERTY(QString activeConnections READ activeConnections NOTIFY activeConnectionsChanged)
|
||||
Q_PROPERTY(QString networkStatus READ networkStatus NOTIFY networkStatusChanged)
|
||||
|
||||
public:
|
||||
enum SortedConnectionType {
|
||||
Wired,
|
||||
Wireless,
|
||||
Gsm,
|
||||
Cdma,
|
||||
Pppoe,
|
||||
Adsl,
|
||||
Infiniband,
|
||||
OLPCMesh,
|
||||
Bluetooth,
|
||||
Vpn,
|
||||
Other
|
||||
};
|
||||
Q_ENUM(SortedConnectionType)
|
||||
|
||||
enum HandlerAction {
|
||||
ActivateConnection,
|
||||
AddAndActivateConnection,
|
||||
AddConnection,
|
||||
DeactivateConnection,
|
||||
RemoveConnection,
|
||||
RequestScan,
|
||||
UpdateConnection,
|
||||
CreateHotspot,
|
||||
};
|
||||
Q_ENUM(HandlerAction)
|
||||
|
||||
explicit Networking(QObject *parent = nullptr);
|
||||
|
||||
bool isEnabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
bool isWirelessEnabled() const;
|
||||
void setWirelessEnabled(bool enabled);
|
||||
|
||||
bool isWirelessHardwareEnabled() const;
|
||||
|
||||
bool isMobileEnabled() const;
|
||||
void setMobileEnabled(bool enabled);
|
||||
|
||||
bool isMobileHardwareEnabled() const;
|
||||
|
||||
bool isAirplaneModeEnabled() const;
|
||||
void setAirplaneModeEnabled(bool enabled);
|
||||
|
||||
QString activeConnections() const;
|
||||
QString networkStatus() const;
|
||||
|
||||
Q_INVOKABLE void activateConnection(const QString &connectionPath, const QString &device, const QString &specificObject);
|
||||
Q_INVOKABLE void addAndActivateConnection(const QString &device, const QString &specificObject, const QString &password = QString());
|
||||
Q_INVOKABLE void deactivateConnection(const QString &connectionName, const QString &device);
|
||||
Q_INVOKABLE void removeConnection(const QString &connectionPath);
|
||||
|
||||
static SortedConnectionType connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type);
|
||||
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
void wirelessEnabledChanged();
|
||||
void wirelessHardwareEnabledChanged();
|
||||
void mobileEnabledChanged();
|
||||
void mobileHardwareEnabledChanged();
|
||||
void airplaneModeEnabledChanged();
|
||||
void activeConnectionsChanged();
|
||||
void networkStatusChanged();
|
||||
|
||||
private:
|
||||
bool m_lastWirelessEnabled = false;
|
||||
bool m_lastMobileEnabled = false;
|
||||
QString m_userName;
|
||||
QString m_activeConnections;
|
||||
QString m_networkStatus;
|
||||
|
||||
void doChangeActiveConnections();
|
||||
QString checkUnknownReason() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void statusChanged(NetworkManager::Status status);
|
||||
void changeActiveConnections();
|
||||
void defaultChanged();
|
||||
};
|
||||
|
||||
#endif // NETWORKING_H
|
||||
@ -0,0 +1,175 @@
|
||||
/*
|
||||
Copyright 2013-2018 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "networkitemslist.h"
|
||||
#include "networkmodelitem.h"
|
||||
|
||||
NetworkItemsList::NetworkItemsList(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NetworkItemsList::~NetworkItemsList()
|
||||
{
|
||||
qDeleteAll(m_items);
|
||||
}
|
||||
|
||||
bool NetworkItemsList::contains(const NetworkItemsList::FilterType type, const QString ¶meter) const
|
||||
{
|
||||
for (NetworkModelItem *item : m_items) {
|
||||
switch (type) {
|
||||
case NetworkItemsList::ActiveConnection:
|
||||
if (item->activeConnectionPath() == parameter) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Connection:
|
||||
if (item->connectionPath() == parameter) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Device:
|
||||
if (item->devicePath() == parameter) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Name:
|
||||
if (item->name() == parameter) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Ssid:
|
||||
if (item->ssid() == parameter) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Uuid:
|
||||
if (item->uuid() == parameter) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Type:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int NetworkItemsList::count() const
|
||||
{
|
||||
return m_items.count();
|
||||
}
|
||||
|
||||
int NetworkItemsList::indexOf(NetworkModelItem *item) const
|
||||
{
|
||||
return m_items.indexOf(item);
|
||||
}
|
||||
|
||||
void NetworkItemsList::insertItem(NetworkModelItem *item)
|
||||
{
|
||||
m_items << item;
|
||||
}
|
||||
|
||||
NetworkModelItem *NetworkItemsList::itemAt(int index) const
|
||||
{
|
||||
return m_items.at(index);
|
||||
}
|
||||
|
||||
QList< NetworkModelItem*> NetworkItemsList::items() const
|
||||
{
|
||||
return m_items;
|
||||
}
|
||||
|
||||
void NetworkItemsList::removeItem(NetworkModelItem *item)
|
||||
{
|
||||
m_items.removeAll(item);
|
||||
}
|
||||
|
||||
QList< NetworkModelItem*> NetworkItemsList::returnItems(const NetworkItemsList::FilterType type, const QString ¶meter, const QString &additionalParameter) const
|
||||
{
|
||||
QList<NetworkModelItem*> result;
|
||||
|
||||
for (NetworkModelItem *item : m_items) {
|
||||
switch (type) {
|
||||
case NetworkItemsList::ActiveConnection:
|
||||
if (item->activeConnectionPath() == parameter) {
|
||||
result << item;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Connection:
|
||||
if (item->connectionPath() == parameter) {
|
||||
if (additionalParameter.isEmpty()) {
|
||||
result << item;
|
||||
} else {
|
||||
if (item->devicePath() == additionalParameter) {
|
||||
result << item;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Device:
|
||||
if (item->devicePath() == parameter) {
|
||||
result << item;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Name:
|
||||
if (item->name() == parameter) {
|
||||
result << item;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Ssid:
|
||||
if (item->ssid() == parameter) {
|
||||
if (additionalParameter.isEmpty()) {
|
||||
result << item;
|
||||
} else {
|
||||
if (item->devicePath() == additionalParameter) {
|
||||
result << item;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Uuid:
|
||||
if (item->uuid() == parameter) {
|
||||
result << item;
|
||||
}
|
||||
break;
|
||||
case NetworkItemsList::Type:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<NetworkModelItem*> NetworkItemsList::returnItems(const NetworkItemsList::FilterType type, NetworkManager::ConnectionSettings::ConnectionType typeParameter) const
|
||||
{
|
||||
QList<NetworkModelItem*> result;
|
||||
|
||||
for (NetworkModelItem *item : m_items) {
|
||||
if (type == NetworkItemsList::Type) {
|
||||
if (item->type() == typeParameter) {
|
||||
result << item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2013-2018 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORKITEMSLIST_H
|
||||
#define NETWORKITEMSLIST_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
|
||||
class NetworkModelItem;
|
||||
|
||||
class NETWORKMANAGER_EXPORT NetworkItemsList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum FilterType {
|
||||
ActiveConnection,
|
||||
Connection,
|
||||
Device,
|
||||
Name,
|
||||
Ssid,
|
||||
Uuid,
|
||||
Type
|
||||
};
|
||||
|
||||
explicit NetworkItemsList(QObject *parent = nullptr);
|
||||
~NetworkItemsList() override;
|
||||
|
||||
bool contains(const FilterType type, const QString ¶meter) const;
|
||||
int count() const;
|
||||
int indexOf(NetworkModelItem *item) const;
|
||||
NetworkModelItem *itemAt(int index) const;
|
||||
QList<NetworkModelItem*> items() const;
|
||||
QList<NetworkModelItem*> returnItems(const FilterType type, const QString ¶meter, const QString &additionalParameter = QString()) const;
|
||||
QList<NetworkModelItem*> returnItems(const FilterType type, NetworkManager::ConnectionSettings::ConnectionType typeParameter) const;
|
||||
|
||||
void insertItem(NetworkModelItem *item);
|
||||
void removeItem(NetworkModelItem *item);
|
||||
|
||||
private:
|
||||
QList<NetworkModelItem*> m_items;
|
||||
};
|
||||
|
||||
#endif // NETWORKITEMSLIST_H
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 2013-2018 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORKMODEL_H
|
||||
#define NETWORKMODEL_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "networkitemslist.h"
|
||||
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/VpnConnection>
|
||||
#include <NetworkManagerQt/WirelessDevice>
|
||||
#include <NetworkManagerQt/Utils>
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
#include <ModemManagerQt/modem.h>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(gLcNm)
|
||||
|
||||
class NETWORKMANAGER_EXPORT NetworkModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NetworkModel(QObject *parent = nullptr);
|
||||
~NetworkModel() override;
|
||||
|
||||
enum ItemRole {
|
||||
ConnectionDetailsRole = Qt::UserRole + 1,
|
||||
ConnectionIconRole,
|
||||
ConnectionPathRole,
|
||||
ConnectionStateRole,
|
||||
DeviceName,
|
||||
DevicePathRole,
|
||||
DeviceStateRole,
|
||||
DuplicateRole,
|
||||
ItemUniqueNameRole,
|
||||
ItemTypeRole,
|
||||
LastUsedRole,
|
||||
LastUsedDateOnlyRole,
|
||||
NameRole,
|
||||
SecurityTypeRole,
|
||||
SecurityTypeStringRole,
|
||||
SectionRole,
|
||||
SignalRole,
|
||||
SlaveRole,
|
||||
SsidRole,
|
||||
SpecificPathRole,
|
||||
TimeStampRole,
|
||||
TypeRole,
|
||||
UniRole,
|
||||
UuidRole,
|
||||
VpnState,
|
||||
VpnType,
|
||||
RxBytesRole,
|
||||
TxBytesRole
|
||||
};
|
||||
Q_ENUMS(ItemRole)
|
||||
|
||||
enum ConnectionStatus {
|
||||
UnknownState = 0,
|
||||
Activating,
|
||||
Activated,
|
||||
Deactivating,
|
||||
Deactivated
|
||||
};
|
||||
Q_ENUMS(ConnectionStatus)
|
||||
|
||||
enum ConnectionType {
|
||||
UnknownConnectionType = 0,
|
||||
Adsl,
|
||||
Bluetooth,
|
||||
Bond,
|
||||
Bridge,
|
||||
Cdma,
|
||||
Gsm,
|
||||
Infiniband,
|
||||
OLPCMesh,
|
||||
Pppoe,
|
||||
Vlan,
|
||||
Vpn,
|
||||
Wimax,
|
||||
Wired,
|
||||
Wireless
|
||||
};
|
||||
Q_ENUMS(ConnectionType)
|
||||
|
||||
enum SecurityType {
|
||||
UnknownSecurity = -1,
|
||||
NoneSecurity = 0,
|
||||
StaticWep,
|
||||
DynamicWep,
|
||||
Leap,
|
||||
WpaPsk,
|
||||
WpaEap,
|
||||
Wpa2Psk,
|
||||
Wpa2Eap,
|
||||
SAE
|
||||
};
|
||||
Q_ENUMS(SecurityType)
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void onItemUpdated();
|
||||
void setDeviceStatisticsRefreshRateMs(const QString &devicePath, uint refreshRate);
|
||||
|
||||
private Q_SLOTS:
|
||||
void accessPointSignalStrengthChanged(int signal);
|
||||
void activeConnectionAdded(const QString &activeConnection);
|
||||
void activeConnectionRemoved(const QString &activeConnection);
|
||||
void activeConnectionStateChanged(NetworkManager::ActiveConnection::State state);
|
||||
void activeVpnConnectionStateChanged(NetworkManager::VpnConnection::State state,NetworkManager::VpnConnection::StateChangeReason reason);
|
||||
void availableConnectionAppeared(const QString &connection);
|
||||
void availableConnectionDisappeared(const QString &connection);
|
||||
void connectionAdded(const QString &connection);
|
||||
void connectionRemoved(const QString &connection);
|
||||
void connectionUpdated();
|
||||
void deviceAdded(const QString &device);
|
||||
void deviceRemoved(const QString &device);
|
||||
void deviceStateChanged(NetworkManager::Device::State state, NetworkManager::Device::State oldState, NetworkManager::Device::StateChangeReason reason);
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
void gsmNetworkAccessTechnologiesChanged(QFlags<MMModemAccessTechnology> accessTechnologies);
|
||||
void gsmNetworkCurrentModesChanged();
|
||||
void gsmNetworkSignalQualityChanged(const ModemManager::SignalQualityPair &signalQuality);
|
||||
#endif
|
||||
void ipConfigChanged();
|
||||
void ipInterfaceChanged();
|
||||
void statusChanged(NetworkManager::Status status);
|
||||
void wirelessNetworkAppeared(const QString &ssid);
|
||||
void wirelessNetworkDisappeared(const QString &ssid);
|
||||
void wirelessNetworkSignalChanged(int signal);
|
||||
void wirelessNetworkReferenceApChanged(const QString &accessPoint);
|
||||
|
||||
void initialize();
|
||||
private:
|
||||
NetworkItemsList m_list;
|
||||
|
||||
void addActiveConnection(const NetworkManager::ActiveConnection::Ptr &activeConnection);
|
||||
void addAvailableConnection(const QString &connection, const NetworkManager::Device::Ptr &device);
|
||||
void addConnection(const NetworkManager::Connection::Ptr &connection);
|
||||
void addDevice(const NetworkManager::Device::Ptr &device);
|
||||
void addWirelessNetwork(const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device);
|
||||
void checkAndCreateDuplicate(const QString &connection, const QString &deviceUni);
|
||||
void initializeSignals();
|
||||
void initializeSignals(const NetworkManager::ActiveConnection::Ptr &activeConnection);
|
||||
void initializeSignals(const NetworkManager::Connection::Ptr &connection);
|
||||
void initializeSignals(const NetworkManager::Device::Ptr &device);
|
||||
void initializeSignals(const NetworkManager::WirelessNetwork::Ptr &network);
|
||||
void updateItem(NetworkModelItem *item);
|
||||
void updateFromWirelessNetwork(NetworkModelItem *item, const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device);
|
||||
|
||||
NetworkManager::WirelessSecurityType alternativeWirelessSecurity(const NetworkManager::WirelessSecurityType type);
|
||||
};
|
||||
|
||||
#endif // NETWORKMODEL_H
|
||||
@ -0,0 +1,686 @@
|
||||
/*
|
||||
Copyright 2013-2018 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "networkmodelitem.h"
|
||||
#include "uiutils.h"
|
||||
|
||||
#include <NetworkManagerQt/AdslDevice>
|
||||
#include <NetworkManagerQt/BluetoothDevice>
|
||||
#include <NetworkManagerQt/BondDevice>
|
||||
#include <NetworkManagerQt/BridgeDevice>
|
||||
#include <NetworkManagerQt/InfinibandDevice>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/Settings>
|
||||
#include <NetworkManagerQt/TeamDevice>
|
||||
#include <NetworkManagerQt/VlanDevice>
|
||||
#include <NetworkManagerQt/VpnConnection>
|
||||
#include <NetworkManagerQt/VpnSetting>
|
||||
#include <NetworkManagerQt/WiredDevice>
|
||||
#include <NetworkManagerQt/WirelessDevice>
|
||||
#include <NetworkManagerQt/WirelessSetting>
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
#include <ModemManagerQt/manager.h>
|
||||
#include <ModemManagerQt/modem.h>
|
||||
#include <ModemManagerQt/modemdevice.h>
|
||||
#include <ModemManagerQt/modem3gpp.h>
|
||||
#include <ModemManagerQt/modemcdma.h>
|
||||
#endif
|
||||
|
||||
NetworkModelItem::NetworkModelItem(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_connectionState(NetworkManager::ActiveConnection::Deactivated)
|
||||
, m_deviceState(NetworkManager::Device::UnknownState)
|
||||
, m_detailsValid(false)
|
||||
, m_duplicate(false)
|
||||
, m_mode(NetworkManager::WirelessSetting::Infrastructure)
|
||||
, m_securityType(NetworkManager::NoneSecurity)
|
||||
, m_signal(0)
|
||||
, m_slave(false)
|
||||
, m_type(NetworkManager::ConnectionSettings::Unknown)
|
||||
, m_vpnState(NetworkManager::VpnConnection::Unknown)
|
||||
, m_rxBytes(0)
|
||||
, m_txBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
NetworkModelItem::NetworkModelItem(const NetworkModelItem *item, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_connectionPath(item->connectionPath())
|
||||
, m_connectionState(NetworkManager::ActiveConnection::Deactivated)
|
||||
, m_detailsValid(false)
|
||||
, m_duplicate(true)
|
||||
, m_mode(item->mode())
|
||||
, m_name(item->name())
|
||||
, m_securityType(item->securityType())
|
||||
, m_slave(item->slave())
|
||||
, m_ssid(item->ssid())
|
||||
, m_timestamp(item->timestamp())
|
||||
, m_type(item->type())
|
||||
, m_uuid(item->uuid())
|
||||
, m_vpnState(NetworkManager::VpnConnection::Unknown)
|
||||
, m_rxBytes(0)
|
||||
, m_txBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
NetworkModelItem::~NetworkModelItem()
|
||||
{
|
||||
}
|
||||
|
||||
QString NetworkModelItem::activeConnectionPath() const
|
||||
{
|
||||
return m_activeConnectionPath;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setActiveConnectionPath(const QString &path)
|
||||
{
|
||||
m_activeConnectionPath = path;
|
||||
}
|
||||
|
||||
QString NetworkModelItem::connectionPath() const
|
||||
{
|
||||
return m_connectionPath;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setConnectionPath(const QString &path)
|
||||
{
|
||||
if (m_connectionPath != path) {
|
||||
m_connectionPath = path;
|
||||
m_changedRoles << NetworkModel::ConnectionPathRole << NetworkModel::UniRole;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkManager::ActiveConnection::State NetworkModelItem::connectionState() const
|
||||
{
|
||||
return m_connectionState;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setConnectionState(NetworkManager::ActiveConnection::State state)
|
||||
{
|
||||
if (m_connectionState != state) {
|
||||
m_connectionState = state;
|
||||
m_changedRoles << NetworkModel::ConnectionStateRole << NetworkModel::SectionRole;
|
||||
refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList NetworkModelItem::details() const
|
||||
{
|
||||
if (!m_detailsValid) {
|
||||
updateDetails();
|
||||
}
|
||||
return m_details;
|
||||
}
|
||||
|
||||
QString NetworkModelItem::devicePath() const
|
||||
{
|
||||
return m_devicePath;
|
||||
}
|
||||
|
||||
QString NetworkModelItem::deviceName() const
|
||||
{
|
||||
return m_deviceName;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setDeviceName(const QString &name)
|
||||
{
|
||||
if (m_deviceName != name) {
|
||||
m_deviceName = name;
|
||||
m_changedRoles << NetworkModel::DeviceName;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkModelItem::setDevicePath(const QString &path)
|
||||
{
|
||||
if (m_devicePath != path) {
|
||||
m_devicePath = path;
|
||||
m_changedRoles << NetworkModel::DevicePathRole << NetworkModel::ItemTypeRole << NetworkModel::UniRole;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::deviceState() const
|
||||
{
|
||||
return UiUtils::connectionStateToString(m_deviceState);
|
||||
}
|
||||
|
||||
void NetworkModelItem::setDeviceState(const NetworkManager::Device::State state)
|
||||
{
|
||||
if (m_deviceState != state) {
|
||||
m_deviceState = state;
|
||||
m_changedRoles << NetworkModel::DeviceStateRole;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkModelItem::duplicate() const
|
||||
{
|
||||
return m_duplicate;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setIcon(const QString& icon)
|
||||
{
|
||||
if (icon != m_icon) {
|
||||
m_icon = icon;
|
||||
m_changedRoles << NetworkModel::ConnectionIconRole;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkModelItem::refreshIcon()
|
||||
{
|
||||
setIcon(computeIcon());
|
||||
}
|
||||
|
||||
QString NetworkModelItem::computeIcon() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case NetworkManager::ConnectionSettings::Adsl:
|
||||
return QStringLiteral("network-mobile-100");
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bluetooth:
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
return QStringLiteral("network-bluetooth-activated");
|
||||
} else {
|
||||
return QStringLiteral("network-bluetooth");
|
||||
}
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bond:
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bridge:
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Cdma:
|
||||
case NetworkManager::ConnectionSettings::Gsm:
|
||||
if (m_signal == 0 ) {
|
||||
return QStringLiteral("network-mobile-0");
|
||||
} else if (m_signal < 20) {
|
||||
return QStringLiteral("network-mobile-20");
|
||||
} else if (m_signal < 40) {
|
||||
return QStringLiteral("network-mobile-40");
|
||||
} else if (m_signal < 60) {
|
||||
return QStringLiteral("network-mobile-60");
|
||||
} else if (m_signal < 80) {
|
||||
return QStringLiteral("network-mobile-80");
|
||||
} else {
|
||||
return QStringLiteral("network-mobile-100");
|
||||
}
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Infiniband:
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::OLPCMesh:
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Pppoe:
|
||||
return QStringLiteral("network-mobile-100");
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Vlan:
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Vpn:
|
||||
case NetworkManager::ConnectionSettings::WireGuard:
|
||||
return QStringLiteral("network-vpn");
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wired:
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
return QStringLiteral("network-wired-activated");
|
||||
} else {
|
||||
return QStringLiteral("network-wired");
|
||||
}
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wireless:
|
||||
if (m_signal == 0 ) {
|
||||
if (m_mode == NetworkManager::WirelessSetting::Adhoc || m_mode == NetworkManager::WirelessSetting::Ap) {
|
||||
return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-connected-100") : QStringLiteral("network-wireless-connected-100");
|
||||
}
|
||||
return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-connected-100") : QStringLiteral("network-wireless-connected-100");
|
||||
} else if (m_signal <= 25) {
|
||||
return QStringLiteral("network-wireless-connected-25");
|
||||
} else if (m_signal <= 50) {
|
||||
return QStringLiteral("network-wireless-connected-50");
|
||||
} else if (m_signal <= 75) {
|
||||
return QStringLiteral("network-wireless-connected-75");
|
||||
} else {
|
||||
return QStringLiteral("network-wireless-connected-100");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
return QStringLiteral("network-wired-activated");
|
||||
} else {
|
||||
return QStringLiteral("network-wired");
|
||||
}
|
||||
}
|
||||
|
||||
NetworkModelItem::ItemType NetworkModelItem::itemType() const
|
||||
{
|
||||
if (!m_devicePath.isEmpty() ||
|
||||
m_type == NetworkManager::ConnectionSettings::Bond ||
|
||||
m_type == NetworkManager::ConnectionSettings::Bridge ||
|
||||
m_type == NetworkManager::ConnectionSettings::Vlan ||
|
||||
m_type == NetworkManager::ConnectionSettings::Team ||
|
||||
((NetworkManager::status() == NetworkManager::Connected ||
|
||||
NetworkManager::status() == NetworkManager::ConnectedLinkLocal ||
|
||||
NetworkManager::status() == NetworkManager::ConnectedSiteOnly) && (m_type == NetworkManager::ConnectionSettings::Vpn || m_type == NetworkManager::ConnectionSettings::WireGuard))) {
|
||||
if (m_connectionPath.isEmpty() && m_type == NetworkManager::ConnectionSettings::Wireless) {
|
||||
return NetworkModelItem::AvailableAccessPoint;
|
||||
} else {
|
||||
return NetworkModelItem::AvailableConnection;
|
||||
}
|
||||
}
|
||||
return NetworkModelItem::UnavailableConnection;
|
||||
}
|
||||
|
||||
NetworkManager::WirelessSetting::NetworkMode NetworkModelItem::mode() const
|
||||
{
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setMode(const NetworkManager::WirelessSetting::NetworkMode mode)
|
||||
{
|
||||
if (m_mode != mode) {
|
||||
m_mode = mode;
|
||||
refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setName(const QString &name)
|
||||
{
|
||||
if (m_name != name) {
|
||||
m_name = name;
|
||||
m_changedRoles << NetworkModel::ItemUniqueNameRole << NetworkModel::NameRole;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::originalName() const
|
||||
{
|
||||
if (m_deviceName.isEmpty()) {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
return QLatin1String("%1 (%2)").arg(m_name).arg(m_deviceName);
|
||||
|
||||
// return m_name % QLatin1String(" (") % m_deviceName % ')';
|
||||
}
|
||||
|
||||
QString NetworkModelItem::sectionType() const
|
||||
{
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Deactivated) {
|
||||
return "Available connections";
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkManager::WirelessSecurityType NetworkModelItem::securityType() const
|
||||
{
|
||||
return m_securityType;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setSecurityType(NetworkManager::WirelessSecurityType type)
|
||||
{
|
||||
if (m_securityType != type) {
|
||||
m_securityType = type;
|
||||
m_changedRoles << NetworkModel::SecurityTypeStringRole << NetworkModel::SecurityTypeRole;
|
||||
refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
int NetworkModelItem::signal() const
|
||||
{
|
||||
return m_signal;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setSignal(int signal)
|
||||
{
|
||||
if (m_signal != signal) {
|
||||
m_signal = signal;
|
||||
m_changedRoles << NetworkModel::SignalRole;
|
||||
refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkModelItem::slave() const
|
||||
{
|
||||
return m_slave;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setSlave(bool slave)
|
||||
{
|
||||
if (m_slave != slave) {
|
||||
m_slave = slave;
|
||||
m_changedRoles << NetworkModel::SlaveRole;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::specificPath() const
|
||||
{
|
||||
return m_specificPath;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setSpecificPath(const QString &path)
|
||||
{
|
||||
if (m_specificPath != path) {
|
||||
m_specificPath = path;
|
||||
m_changedRoles << NetworkModel::SpecificPathRole;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::ssid() const
|
||||
{
|
||||
return m_ssid;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setSsid(const QString &ssid)
|
||||
{
|
||||
if (m_ssid != ssid) {
|
||||
m_ssid = ssid;
|
||||
m_changedRoles << NetworkModel::SsidRole << NetworkModel::UniRole;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkManager::ConnectionSettings::ConnectionType NetworkModelItem::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
QDateTime NetworkModelItem::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setTimestamp(const QDateTime &date)
|
||||
{
|
||||
if (m_timestamp != date) {
|
||||
m_timestamp = date;
|
||||
m_changedRoles << NetworkModel::TimeStampRole;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkModelItem::setType(NetworkManager::ConnectionSettings::ConnectionType type)
|
||||
{
|
||||
if (m_type != type) {
|
||||
m_type = type;
|
||||
m_changedRoles << NetworkModel::TypeRole << NetworkModel::ItemTypeRole << NetworkModel::UniRole;
|
||||
|
||||
refreshIcon();
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::uni() const
|
||||
{
|
||||
if (m_type == NetworkManager::ConnectionSettings::Wireless && m_uuid.isEmpty()) {
|
||||
return m_ssid + '%' + m_devicePath;
|
||||
} else {
|
||||
return m_connectionPath + '%' + m_devicePath;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setUuid(const QString &uuid)
|
||||
{
|
||||
if (m_uuid != uuid) {
|
||||
m_uuid = uuid;
|
||||
m_changedRoles << NetworkModel::UuidRole;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::vpnState() const
|
||||
{
|
||||
return UiUtils::vpnConnectionStateToString(m_vpnState);
|
||||
}
|
||||
|
||||
void NetworkModelItem::setVpnState(NetworkManager::VpnConnection::State state)
|
||||
{
|
||||
if (m_vpnState != state) {
|
||||
m_vpnState = state;
|
||||
m_changedRoles << NetworkModel::VpnState;
|
||||
}
|
||||
}
|
||||
|
||||
QString NetworkModelItem::vpnType() const
|
||||
{
|
||||
return m_vpnType;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setVpnType(const QString &type)
|
||||
{
|
||||
if (m_vpnType != type) {
|
||||
m_vpnType = type;
|
||||
m_changedRoles << NetworkModel::VpnType;
|
||||
}
|
||||
}
|
||||
|
||||
qulonglong NetworkModelItem::rxBytes() const
|
||||
{
|
||||
return m_rxBytes;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setRxBytes(qulonglong bytes)
|
||||
{
|
||||
if (m_rxBytes != bytes) {
|
||||
m_rxBytes = bytes;
|
||||
m_changedRoles << NetworkModel::RxBytesRole;
|
||||
}
|
||||
}
|
||||
|
||||
qulonglong NetworkModelItem::txBytes() const
|
||||
{
|
||||
return m_txBytes;
|
||||
}
|
||||
|
||||
void NetworkModelItem::setTxBytes(qulonglong bytes)
|
||||
{
|
||||
if (m_txBytes != bytes) {
|
||||
m_txBytes = bytes;
|
||||
m_changedRoles << NetworkModel::TxBytesRole;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkModelItem::operator==(const NetworkModelItem *item) const
|
||||
{
|
||||
if (!item->uuid().isEmpty() && !uuid().isEmpty()) {
|
||||
if (item->devicePath() == devicePath() && item->uuid() == uuid()) {
|
||||
return true;
|
||||
}
|
||||
} else if (item->type() == NetworkManager::ConnectionSettings::Wireless && type() == NetworkManager::ConnectionSettings::Wireless) {
|
||||
if (item->ssid() == ssid() && item->devicePath() == devicePath()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkModelItem::invalidateDetails()
|
||||
{
|
||||
m_detailsValid = false;
|
||||
m_changedRoles << NetworkModel::ConnectionDetailsRole;
|
||||
}
|
||||
|
||||
void NetworkModelItem::updateDetails() const
|
||||
{
|
||||
m_detailsValid = true;
|
||||
m_details.clear();
|
||||
|
||||
if (itemType() == NetworkModelItem::UnavailableConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(m_devicePath);
|
||||
|
||||
// Get IPv[46]Address and related nameservers + IPv4 default gateway
|
||||
if (device && device->ipV4Config().isValid() && m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
if (!device->ipV4Config().addresses().isEmpty()) {
|
||||
QHostAddress addr = device->ipV4Config().addresses().first().ip();
|
||||
if (!addr.isNull()) {
|
||||
m_details << tr("IPv4 Address") << addr.toString();
|
||||
}
|
||||
}
|
||||
if (!device->ipV4Config().gateway().isEmpty()) {
|
||||
QString addr = device->ipV4Config().gateway();
|
||||
if (!addr.isNull()) {
|
||||
m_details << tr("IPv4 Default Gateway") << addr;
|
||||
}
|
||||
}
|
||||
if (!device->ipV4Config().nameservers().isEmpty()) {
|
||||
QHostAddress addr = device->ipV4Config().nameservers().first();
|
||||
if (!addr.isNull()) {
|
||||
m_details << tr("IPv4 Nameserver") << addr.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device && device->ipV6Config().isValid() && m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
if (!device->ipV6Config().addresses().isEmpty()) {
|
||||
QHostAddress addr = device->ipV6Config().addresses().first().ip();
|
||||
if (!addr.isNull()) {
|
||||
m_details << tr("IPv6 Address") << addr.toString();
|
||||
}
|
||||
}
|
||||
if (!device->ipV6Config().nameservers().isEmpty()) {
|
||||
QHostAddress addr = device->ipV6Config().nameservers().first();
|
||||
if (!addr.isNull()) {
|
||||
m_details << tr("IPv6 Nameserver") << addr.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_type == NetworkManager::ConnectionSettings::Wired) {
|
||||
NetworkManager::WiredDevice::Ptr wiredDevice = device.objectCast<NetworkManager::WiredDevice>();
|
||||
if (wiredDevice) {
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
m_details << tr("Connection speed") << UiUtils::connectionSpeed(wiredDevice->bitRate());
|
||||
}
|
||||
m_details << tr("MAC Address") << wiredDevice->permanentHardwareAddress();
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Wireless) {
|
||||
NetworkManager::WirelessDevice::Ptr wirelessDevice = device.objectCast<NetworkManager::WirelessDevice>();
|
||||
m_details << tr("Access point (SSID)") << m_ssid;
|
||||
if (m_mode == NetworkManager::WirelessSetting::Infrastructure) {
|
||||
m_details << tr("Signal strength") << QStringLiteral("%1%").arg(m_signal);
|
||||
}
|
||||
m_details << tr("Security type") << UiUtils::labelFromWirelessSecurity(m_securityType);
|
||||
if (wirelessDevice) {
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
m_details << tr("Connection speed") << UiUtils::connectionSpeed(wirelessDevice->bitRate());
|
||||
}
|
||||
m_details << tr("MAC Address") << wirelessDevice->permanentHardwareAddress();
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Gsm || m_type == NetworkManager::ConnectionSettings::Cdma) {
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
NetworkManager::ModemDevice::Ptr modemDevice = device.objectCast<NetworkManager::ModemDevice>();
|
||||
if (modemDevice) {
|
||||
ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(modemDevice->udi());
|
||||
if (modem) {
|
||||
ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
|
||||
|
||||
if (m_type == NetworkManager::ConnectionSettings::Gsm) {
|
||||
ModemManager::Modem3gpp::Ptr gsmNet = modem->interface(ModemManager::ModemDevice::GsmInterface).objectCast<ModemManager::Modem3gpp>();
|
||||
if (gsmNet) {
|
||||
m_details << tr("Operator") << gsmNet->operatorName();
|
||||
}
|
||||
} else {
|
||||
ModemManager::ModemCdma::Ptr cdmaNet = modem->interface(ModemManager::ModemDevice::CdmaInterface).objectCast<ModemManager::ModemCdma>();
|
||||
m_details << tr("Network ID") << QString("%1").arg(cdmaNet->nid());
|
||||
}
|
||||
|
||||
if (modemNetwork) {
|
||||
m_details << tr("Signal Quality") << QString("%1%").arg(modemNetwork->signalQuality().signal);
|
||||
m_details << tr("Access Technology") << UiUtils::convertAccessTechnologyToString(modemNetwork->accessTechnologies());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Vpn) {
|
||||
m_details << tr("VPN plugin") << m_vpnType;
|
||||
|
||||
if (m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
NetworkManager::ActiveConnection::Ptr active = NetworkManager::findActiveConnection(m_activeConnectionPath);
|
||||
NetworkManager::VpnConnection::Ptr vpnConnection;
|
||||
|
||||
if (active) {
|
||||
vpnConnection = NetworkManager::VpnConnection::Ptr(new NetworkManager::VpnConnection(active->path()), &QObject::deleteLater);
|
||||
}
|
||||
|
||||
if (vpnConnection && !vpnConnection->banner().isEmpty()) {
|
||||
m_details << tr("Banner") << vpnConnection->banner().simplified();
|
||||
}
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Bluetooth) {
|
||||
NetworkManager::BluetoothDevice::Ptr bluetoothDevice = device.objectCast<NetworkManager::BluetoothDevice>();
|
||||
if (bluetoothDevice) {
|
||||
m_details << tr("Name") << bluetoothDevice->name();
|
||||
if (bluetoothDevice->bluetoothCapabilities() == NetworkManager::BluetoothDevice::Pan) {
|
||||
m_details << tr("Capabilities") << QStringLiteral("PAN");
|
||||
} else if (bluetoothDevice->bluetoothCapabilities() == NetworkManager::BluetoothDevice::Dun) {
|
||||
m_details << tr("Capabilities") << QStringLiteral("DUN");
|
||||
}
|
||||
m_details << tr("MAC Address") << bluetoothDevice->hardwareAddress();
|
||||
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Infiniband) {
|
||||
NetworkManager::InfinibandDevice::Ptr infinibandDevice = device.objectCast<NetworkManager::InfinibandDevice>();
|
||||
m_details << tr("Type") << tr("Infiniband");
|
||||
if (infinibandDevice) {
|
||||
m_details << tr("MAC Address") << infinibandDevice->hwAddress();
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Bond) {
|
||||
NetworkManager::BondDevice::Ptr bondDevice = device.objectCast<NetworkManager::BondDevice>();
|
||||
m_details << tr("Type") << tr("Bond");
|
||||
if (bondDevice) {
|
||||
m_details << tr("MAC Address") << bondDevice->hwAddress();
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Bridge) {
|
||||
NetworkManager::BridgeDevice::Ptr bridgeDevice = device.objectCast<NetworkManager::BridgeDevice>();
|
||||
m_details << tr("Type") << tr("Bridge");
|
||||
if (bridgeDevice) {
|
||||
m_details << tr("MAC Address") << bridgeDevice->hwAddress();
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Vlan) {
|
||||
NetworkManager::VlanDevice::Ptr vlanDevice = device.objectCast<NetworkManager::VlanDevice>();
|
||||
m_details << tr("Type") << tr("Vlan");
|
||||
if (vlanDevice) {
|
||||
m_details << tr("Vlan ID") << QString("%1").arg(vlanDevice->vlanId());
|
||||
m_details << tr("MAC Address") << vlanDevice->hwAddress();
|
||||
}
|
||||
} else if (m_type == NetworkManager::ConnectionSettings::Adsl) {
|
||||
m_details << tr("Type") << tr("Adsl");
|
||||
}
|
||||
else if (m_type == NetworkManager::ConnectionSettings::Team) {
|
||||
NetworkManager::TeamDevice::Ptr teamDevice = device.objectCast<NetworkManager::TeamDevice>();
|
||||
m_details << tr("Type") << tr("Team");
|
||||
if (teamDevice) {
|
||||
m_details << tr("MAC Address") << teamDevice->hwAddress();
|
||||
}
|
||||
}
|
||||
|
||||
if (device && m_connectionState == NetworkManager::ActiveConnection::Activated) {
|
||||
m_details << tr("Device") << device->interfaceName();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright 2013-2018 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORKMODELITEM_H
|
||||
#define NETWORKMODELITEM_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
|
||||
#include <NetworkManagerQt/ActiveConnection>
|
||||
#include <NetworkManagerQt/Connection>
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
#include <NetworkManagerQt/Device>
|
||||
#include <NetworkManagerQt/Utils>
|
||||
|
||||
#include "networkmodel.h"
|
||||
|
||||
class NETWORKMANAGER_EXPORT NetworkModelItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ItemType { UnavailableConnection, AvailableConnection, AvailableAccessPoint };
|
||||
|
||||
explicit NetworkModelItem(QObject *parent = nullptr);
|
||||
explicit NetworkModelItem(const NetworkModelItem *item, QObject *parent = nullptr);
|
||||
~NetworkModelItem() override;
|
||||
|
||||
QString activeConnectionPath() const;
|
||||
void setActiveConnectionPath(const QString &path);
|
||||
|
||||
QString connectionPath() const;
|
||||
void setConnectionPath(const QString &path);
|
||||
|
||||
NetworkManager::ActiveConnection::State connectionState() const;
|
||||
void setConnectionState(NetworkManager::ActiveConnection::State state);
|
||||
|
||||
QStringList details() const;
|
||||
|
||||
QString deviceName() const;
|
||||
void setDeviceName(const QString &name);
|
||||
|
||||
QString devicePath() const;
|
||||
void setDevicePath(const QString &path);
|
||||
|
||||
QString deviceState() const;
|
||||
void setDeviceState(const NetworkManager::Device::State state);
|
||||
|
||||
bool duplicate() const;
|
||||
|
||||
void setIcon(const QString &icon);
|
||||
QString icon() const { return m_icon; }
|
||||
|
||||
ItemType itemType() const;
|
||||
|
||||
NetworkManager::WirelessSetting::NetworkMode mode() const;
|
||||
void setMode(const NetworkManager::WirelessSetting::NetworkMode mode);
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
QString originalName() const;
|
||||
|
||||
QString sectionType() const;
|
||||
|
||||
NetworkManager::WirelessSecurityType securityType() const;
|
||||
void setSecurityType(NetworkManager::WirelessSecurityType type);
|
||||
|
||||
int signal() const;
|
||||
void setSignal(int signal);
|
||||
|
||||
bool slave() const;
|
||||
void setSlave(bool slave);
|
||||
|
||||
QString specificPath() const;
|
||||
void setSpecificPath(const QString &path);
|
||||
|
||||
QString ssid() const;
|
||||
void setSsid(const QString &ssid);
|
||||
|
||||
QDateTime timestamp() const;
|
||||
void setTimestamp(const QDateTime &date);
|
||||
|
||||
NetworkManager::ConnectionSettings::ConnectionType type() const;
|
||||
void setType(NetworkManager::ConnectionSettings::ConnectionType type);
|
||||
|
||||
QString uni() const;
|
||||
|
||||
QString uuid() const;
|
||||
void setUuid(const QString &uuid);
|
||||
|
||||
QString vpnState() const;
|
||||
void setVpnState(NetworkManager::VpnConnection::State state);
|
||||
|
||||
QString vpnType() const;
|
||||
void setVpnType(const QString &type);
|
||||
|
||||
qulonglong rxBytes() const;
|
||||
void setRxBytes(qulonglong bytes);
|
||||
|
||||
qulonglong txBytes() const;
|
||||
void setTxBytes(qulonglong bytes);
|
||||
|
||||
bool operator==(const NetworkModelItem *item) const;
|
||||
|
||||
QVector<int> changedRoles() const { return m_changedRoles; }
|
||||
void clearChangedRoles() { m_changedRoles.clear(); }
|
||||
|
||||
public Q_SLOTS:
|
||||
void invalidateDetails();
|
||||
|
||||
private:
|
||||
QString computeIcon() const;
|
||||
void refreshIcon();
|
||||
void updateDetails() const;
|
||||
|
||||
QString m_activeConnectionPath;
|
||||
QString m_connectionPath;
|
||||
NetworkManager::ActiveConnection::State m_connectionState;
|
||||
QString m_devicePath;
|
||||
QString m_deviceName;
|
||||
NetworkManager::Device::State m_deviceState;
|
||||
mutable QStringList m_details;
|
||||
mutable bool m_detailsValid;
|
||||
bool m_duplicate;
|
||||
NetworkManager::WirelessSetting::NetworkMode m_mode;
|
||||
QString m_name;
|
||||
NetworkManager::WirelessSecurityType m_securityType;
|
||||
int m_signal;
|
||||
bool m_slave;
|
||||
QString m_specificPath;
|
||||
QString m_ssid;
|
||||
QDateTime m_timestamp;
|
||||
NetworkManager::ConnectionSettings::ConnectionType m_type;
|
||||
QString m_uuid;
|
||||
QString m_vpnType;
|
||||
NetworkManager::VpnConnection::State m_vpnState;
|
||||
qulonglong m_rxBytes;
|
||||
qulonglong m_txBytes;
|
||||
QString m_icon;
|
||||
QVector<int> m_changedRoles;
|
||||
};
|
||||
|
||||
#endif // NETWORKMODELITEM_H
|
||||
@ -0,0 +1,3 @@
|
||||
module Cutefish.NetworkManagement
|
||||
|
||||
plugin cutefishnm_qmlplugins
|
||||
@ -0,0 +1,24 @@
|
||||
#include "qmlplugins.h"
|
||||
#include "networking.h"
|
||||
#include "networkmodel.h"
|
||||
#include "networkmodelitem.h"
|
||||
#include "appletproxymodel.h"
|
||||
#include "technologyproxymodel.h"
|
||||
#include "wiressitemsettings.h"
|
||||
#include "connectionicon.h"
|
||||
#include "network.h"
|
||||
|
||||
#include <QQmlEngine>
|
||||
|
||||
void QmlPlugins::registerTypes(const char* uri)
|
||||
{
|
||||
qmlRegisterUncreatableType<NetworkModelItem>(uri, 1, 0, "NetworkModelItem",
|
||||
QLatin1String("Cannot instantiate NetworkModelItem"));
|
||||
qmlRegisterType<AppletProxyModel>(uri, 1, 0, "AppletProxyModel");
|
||||
qmlRegisterType<Networking>(uri, 1, 0, "Networking");
|
||||
qmlRegisterType<NetworkModel>(uri, 1, 0, "NetworkModel");
|
||||
qmlRegisterType<TechnologyProxyModel>(uri, 1, 0, "TechnologyProxyModel");
|
||||
qmlRegisterType<WirelessItemSettings>(uri, 1, 0, "WirelessItemSettings");
|
||||
qmlRegisterType<ConnectionIcon>(uri, 1, 0, "ConnectionIcon");
|
||||
qmlRegisterType<Network>(uri, 1, 0, "Network");
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
#ifndef QMLPLUGINS_H
|
||||
#define QMLPLUGINS_H
|
||||
|
||||
#include <QQmlExtensionPlugin>
|
||||
|
||||
class QmlPlugins : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
|
||||
|
||||
public:
|
||||
void registerTypes(const char * uri) override;
|
||||
};
|
||||
|
||||
#endif // QMLPLUGINS_H
|
||||
@ -0,0 +1,144 @@
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#include "networkmodel.h"
|
||||
#include "networkmodelitem.h"
|
||||
#include "technologyproxymodel.h"
|
||||
|
||||
static NetworkManager::ConnectionSettings::ConnectionType convertType(TechnologyProxyModel::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case TechnologyProxyModel::UnknownType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Unknown;
|
||||
case TechnologyProxyModel::AdslType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Adsl;
|
||||
case TechnologyProxyModel::BluetoothType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Bluetooth;
|
||||
case TechnologyProxyModel::CdmaType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Cdma;
|
||||
case TechnologyProxyModel::GsmType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Gsm;
|
||||
case TechnologyProxyModel::OLPCMeshType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::OLPCMesh;
|
||||
case TechnologyProxyModel::PppoeType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Pppoe;
|
||||
case TechnologyProxyModel::VpnType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Vpn;
|
||||
case TechnologyProxyModel::WimaxType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Wimax;
|
||||
case TechnologyProxyModel::WiredType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Wired;
|
||||
case TechnologyProxyModel::WirelessType:
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Wireless;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NetworkManager::ConnectionSettings::ConnectionType::Unknown;
|
||||
}
|
||||
|
||||
TechnologyProxyModel::TechnologyProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
setDynamicSortFilter(true);
|
||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
setSortLocaleAware(true);
|
||||
sort(0, Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
TechnologyProxyModel::Type TechnologyProxyModel::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void TechnologyProxyModel::setType(Type type)
|
||||
{
|
||||
if (m_type == type)
|
||||
return;
|
||||
m_type = type;
|
||||
Q_EMIT typeChanged();
|
||||
|
||||
if (type == UnknownType)
|
||||
setFilterRole(0);
|
||||
else
|
||||
setFilterRole(NetworkModel::TypeRole);
|
||||
}
|
||||
|
||||
bool TechnologyProxyModel::showInactiveConnections() const
|
||||
{
|
||||
return m_showInactiveConnections;
|
||||
}
|
||||
|
||||
void TechnologyProxyModel::setShowInactiveConnections(bool value)
|
||||
{
|
||||
if (m_showInactiveConnections == value)
|
||||
return;
|
||||
|
||||
m_showInactiveConnections = value;
|
||||
Q_EMIT showInactiveConnectionsChanged();
|
||||
}
|
||||
|
||||
bool TechnologyProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
const QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
|
||||
|
||||
// Filter out slaves and duplicates
|
||||
const bool isSlave = sourceModel()->data(index, NetworkModel::SlaveRole).toBool();
|
||||
const bool isDuplicate = sourceModel()->data(index, NetworkModel::DuplicateRole).toBool();
|
||||
if (isSlave || isDuplicate)
|
||||
return false;
|
||||
|
||||
// Connection and item type
|
||||
const NetworkManager::ConnectionSettings::ConnectionType type =
|
||||
static_cast<NetworkManager::ConnectionSettings::ConnectionType>(sourceModel()->data(index, NetworkModel::TypeRole).toUInt());
|
||||
const NetworkModelItem::ItemType itemType =
|
||||
static_cast<NetworkModelItem::ItemType>(sourceModel()->data(index, NetworkModel::ItemTypeRole).toUInt());
|
||||
|
||||
// Filter-out certain connection types we are not interested in
|
||||
if (m_type != UnknownType) {
|
||||
if (type != convertType(m_type))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filter-out access points
|
||||
if (itemType != NetworkModelItem::AvailableConnection &&
|
||||
itemType != NetworkModelItem::AvailableAccessPoint)
|
||||
return false;
|
||||
|
||||
// Filter by state
|
||||
const NetworkManager::ActiveConnection::State state =
|
||||
static_cast<NetworkManager::ActiveConnection::State>(sourceModel()->data(index, NetworkModel::ConnectionStateRole).toUInt());
|
||||
if (!m_showInactiveConnections && state == NetworkManager::ActiveConnection::Deactivated)
|
||||
return false;
|
||||
|
||||
// Filter on connection name
|
||||
const QString pattern = filterRegExp().pattern();
|
||||
if (!pattern.isEmpty()) {
|
||||
QString data = sourceModel()->data(index, Qt::DisplayRole).toString();
|
||||
if (data.isEmpty())
|
||||
data = sourceModel()->data(index, NetworkModel::NameRole).toString();
|
||||
return data.contains(pattern, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*
|
||||
* $BEGIN_LICENSE:LGPLv3+$
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* $END_LICENSE$
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TECHNOLOGYPROXYMODEL_H
|
||||
#define TECHNOLOGYPROXYMODEL_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
|
||||
#include <NetworkManagerQt/ConnectionSettings>
|
||||
|
||||
class NETWORKMANAGER_EXPORT TechnologyProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged)
|
||||
Q_PROPERTY(bool showInactiveConnections READ showInactiveConnections WRITE setShowInactiveConnections NOTIFY showInactiveConnectionsChanged)
|
||||
Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setSourceModel)
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
UnknownType = 0,
|
||||
AdslType,
|
||||
BluetoothType,
|
||||
CdmaType,
|
||||
GsmType,
|
||||
OLPCMeshType,
|
||||
PppoeType,
|
||||
VpnType,
|
||||
WimaxType,
|
||||
WiredType,
|
||||
WirelessType
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
TechnologyProxyModel(QObject *parent = nullptr);
|
||||
|
||||
Type type() const;
|
||||
void setType(Type type);
|
||||
|
||||
bool showInactiveConnections() const;
|
||||
void setShowInactiveConnections(bool value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void typeChanged();
|
||||
void showInactiveConnectionsChanged();
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
Type m_type = UnknownType;
|
||||
bool m_showInactiveConnections = false;
|
||||
};
|
||||
|
||||
#endif //TECHNOLOGYPROXYMODEL_H
|
||||
@ -0,0 +1,803 @@
|
||||
/*
|
||||
Copyright 2008-2010 Sebastian Kügler <sebas@kde.org>
|
||||
Copyright 2013-2014 Jan Grulich <jgrulich@redhat.com>
|
||||
Copyright 2015-2016 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
|
||||
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) version 3 or any later version
|
||||
accepted by the membership of KDE e.V. (or its successor approved
|
||||
by the membership of KDE e.V.), which shall act as a proxy
|
||||
defined in Section 14 of version 3 of the license.
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <NetworkManagerQt/BluetoothDevice>
|
||||
#include <NetworkManagerQt/Manager>
|
||||
#include <NetworkManagerQt/Device>
|
||||
#include <NetworkManagerQt/AccessPoint>
|
||||
#include <NetworkManagerQt/WiredDevice>
|
||||
#include <NetworkManagerQt/WirelessDevice>
|
||||
#include <NetworkManagerQt/WirelessSetting>
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
#include <ModemManagerQt/manager.h>
|
||||
#include <ModemManagerQt/modem.h>
|
||||
#include <ModemManagerQt/modemdevice.h>
|
||||
#include <ModemManagerQt/modem3gpp.h>
|
||||
#include <ModemManagerQt/modemcdma.h>
|
||||
#endif
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QSizeF>
|
||||
#include <QString>
|
||||
|
||||
#include "networkmodel.h"
|
||||
#include "uiutils.h"
|
||||
|
||||
using namespace NetworkManager;
|
||||
|
||||
UiUtils::SortedConnectionType UiUtils::connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type)
|
||||
{
|
||||
switch (type) {
|
||||
case NetworkManager::ConnectionSettings::Unknown:
|
||||
return UiUtils::Unknown;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Adsl:
|
||||
return UiUtils::Adsl;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bluetooth:
|
||||
return UiUtils::Bluetooth;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bond:
|
||||
return UiUtils::Bond;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Bridge:
|
||||
return UiUtils::Bridge;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Cdma:
|
||||
return UiUtils::Cdma;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Gsm:
|
||||
return UiUtils::Gsm;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Infiniband:
|
||||
return UiUtils::Infiniband;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::OLPCMesh:
|
||||
return UiUtils::OLPCMesh;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Pppoe:
|
||||
return UiUtils::Pppoe;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Team:
|
||||
return UiUtils::Team;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Vlan:
|
||||
return UiUtils::Vlan;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Vpn:
|
||||
return UiUtils::Vpn;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wired:
|
||||
return UiUtils::Wired;
|
||||
break;
|
||||
case NetworkManager::ConnectionSettings::Wireless:
|
||||
return UiUtils::Wireless;
|
||||
break;
|
||||
default:
|
||||
return UiUtils::Unknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool UiUtils::isConnectionTypeSupported(NetworkManager::ConnectionSettings::ConnectionType type)
|
||||
{
|
||||
if (type == NetworkManager::ConnectionSettings::Generic || type == NetworkManager::ConnectionSettings::Tun) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Implement this setting
|
||||
//bool manageVirtualConnections = Configuration::manageVirtualConnections();
|
||||
bool manageVirtualConnections = false;
|
||||
|
||||
if (type == NetworkManager::ConnectionSettings::Bond ||
|
||||
type == NetworkManager::ConnectionSettings::Bridge ||
|
||||
type == NetworkManager::ConnectionSettings::Infiniband ||
|
||||
type == NetworkManager::ConnectionSettings::Team ||
|
||||
type == NetworkManager::ConnectionSettings::Vlan) {
|
||||
return manageVirtualConnections;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UiUtils::isConnectionTypeVirtual(NetworkManager::ConnectionSettings::ConnectionType type)
|
||||
{
|
||||
if (type == NetworkManager::ConnectionSettings::Bond ||
|
||||
type == NetworkManager::ConnectionSettings::Bridge ||
|
||||
type == NetworkManager::ConnectionSettings::Infiniband ||
|
||||
type == NetworkManager::ConnectionSettings::Team ||
|
||||
type == NetworkManager::ConnectionSettings::Vlan) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString UiUtils::interfaceTypeLabel(const NetworkManager::Device::Type type, const NetworkManager::Device::Ptr iface)
|
||||
{
|
||||
QString deviceText;
|
||||
switch (type) {
|
||||
case NetworkManager::Device::Wifi:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Wi-Fi");
|
||||
break;
|
||||
case NetworkManager::Device::Bluetooth:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Bluetooth");
|
||||
break;
|
||||
case NetworkManager::Device::Wimax:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("WiMAX");
|
||||
break;
|
||||
case NetworkManager::Device::InfiniBand:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Infiniband");
|
||||
break;
|
||||
case NetworkManager::Device::Adsl:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("ADSL");
|
||||
break;
|
||||
case NetworkManager::Device::Bond:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Virtual (bond)");
|
||||
break;
|
||||
case NetworkManager::Device::Bridge:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Virtual (bridge)");
|
||||
break;
|
||||
case NetworkManager::Device::Vlan:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Virtual (vlan)");
|
||||
break;
|
||||
#if NM_CHECK_VERSION(0, 9, 10)
|
||||
case NetworkManager::Device::Team:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Virtual (team)");
|
||||
break;
|
||||
#endif
|
||||
case NetworkManager::Device::Modem: {
|
||||
const NetworkManager::ModemDevice::Ptr nmModemIface = iface.objectCast<NetworkManager::ModemDevice>();
|
||||
if (nmModemIface) {
|
||||
switch(modemSubType(nmModemIface->currentCapabilities())) {
|
||||
case NetworkManager::ModemDevice::Pots:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Serial Modem");
|
||||
break;
|
||||
case NetworkManager::ModemDevice::GsmUmts:
|
||||
case NetworkManager::ModemDevice::CdmaEvdo:
|
||||
case NetworkManager::ModemDevice::Lte:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Mobile Broadband");
|
||||
break;
|
||||
case NetworkManager::ModemDevice::NoCapability:
|
||||
qCWarning(gLcNm) << "Unhandled modem sub type: NetworkManager::ModemDevice::NoCapability";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkManager::Device::Ethernet:
|
||||
default:
|
||||
/*: title of the interface widget in nm's popup */
|
||||
deviceText = QObject::tr("Wired Ethernet");
|
||||
break;
|
||||
}
|
||||
return deviceText;
|
||||
}
|
||||
|
||||
QString UiUtils::iconAndTitleForConnectionSettingsType(NetworkManager::ConnectionSettings::ConnectionType type, QString &title)
|
||||
{
|
||||
QString text;
|
||||
QString icon = QLatin1String("action/settings_ethernet");
|
||||
switch (type) {
|
||||
case ConnectionSettings::Adsl:
|
||||
text = QObject::tr("ADSL");
|
||||
icon = QLatin1String("device/network_cell");
|
||||
break;
|
||||
case ConnectionSettings::Pppoe:
|
||||
text = QObject::tr("DSL");
|
||||
icon = QLatin1String("device/network_cell");
|
||||
break;
|
||||
case ConnectionSettings::Bluetooth:
|
||||
text = QObject::tr("Bluetooth");
|
||||
icon = QLatin1String("device/bluetooth");
|
||||
break;
|
||||
case ConnectionSettings::Bond:
|
||||
text = QObject::tr("Bond");
|
||||
break;
|
||||
case ConnectionSettings::Bridge:
|
||||
text = QObject::tr("Bridge");
|
||||
break;
|
||||
case ConnectionSettings::Gsm:
|
||||
case ConnectionSettings::Cdma:
|
||||
text = QObject::tr("Mobile broadband");
|
||||
icon = QLatin1String("device/network_cell");
|
||||
break;
|
||||
case ConnectionSettings::Infiniband:
|
||||
text = QObject::tr("Infiniband");
|
||||
break;
|
||||
case ConnectionSettings::OLPCMesh:
|
||||
text = QObject::tr("Olpc mesh");
|
||||
break;
|
||||
case ConnectionSettings::Vlan:
|
||||
text = QObject::tr("VLAN");
|
||||
break;
|
||||
case ConnectionSettings::Vpn:
|
||||
text = QObject::tr("VPN");
|
||||
icon = QLatin1String("communication/vpn_key");
|
||||
break;
|
||||
case ConnectionSettings::Wimax:
|
||||
text = QObject::tr("WiMAX");
|
||||
icon = QLatin1String("device/network_wifi");
|
||||
break;
|
||||
case ConnectionSettings::Wired:
|
||||
text = QObject::tr("Wired Ethernet");
|
||||
break;
|
||||
case ConnectionSettings::Wireless:
|
||||
text = QObject::tr("Wi-Fi");
|
||||
icon = QLatin1String("device/network_wifi");
|
||||
break;
|
||||
#if NM_CHECK_VERSION(0, 9, 10)
|
||||
case ConnectionSettings::Team:
|
||||
text = QObject::tr("Team");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
text = QObject::tr("Unknown connection type");
|
||||
break;
|
||||
}
|
||||
title = text;
|
||||
return icon;
|
||||
}
|
||||
|
||||
QString UiUtils::prettyInterfaceName(NetworkManager::Device::Type type, const QString &interfaceName)
|
||||
{
|
||||
QString ret;
|
||||
switch (type) {
|
||||
case NetworkManager::Device::Wifi:
|
||||
ret = QObject::tr("Wireless Interface (%1)").arg(interfaceName);
|
||||
break;
|
||||
case NetworkManager::Device::Ethernet:
|
||||
ret = QObject::tr("Wired Interface (%1)").arg(interfaceName);
|
||||
break;
|
||||
case NetworkManager::Device::Bluetooth:
|
||||
ret = QObject::tr("Bluetooth (%1)").arg(interfaceName);
|
||||
break;
|
||||
case NetworkManager::Device::Modem:
|
||||
ret = QObject::tr("Modem (%1)").arg(interfaceName);
|
||||
break;
|
||||
case NetworkManager::Device::Adsl:
|
||||
ret = QObject::tr("ADSL (%1)").arg(interfaceName);
|
||||
break;
|
||||
case NetworkManager::Device::Vlan:
|
||||
ret = QObject::tr("VLan (%1)").arg(interfaceName);
|
||||
break;
|
||||
case NetworkManager::Device::Bridge:
|
||||
ret = QObject::tr("Bridge (%1)").arg(interfaceName);
|
||||
break;
|
||||
default:
|
||||
ret = interfaceName;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString UiUtils::connectionStateToString(NetworkManager::Device::State state, const QString &connectionName)
|
||||
{
|
||||
QString stateString;
|
||||
switch (state) {
|
||||
case NetworkManager::Device::UnknownState:
|
||||
/*: description of unknown network interface state */
|
||||
stateString = QObject::tr("Unknown");
|
||||
break;
|
||||
case NetworkManager::Device::Unmanaged:
|
||||
/*: description of unmanaged network interface state */
|
||||
stateString = QObject::tr("Unmanaged");
|
||||
break;
|
||||
case NetworkManager::Device::Unavailable:
|
||||
/*: description of unavailable network interface state */
|
||||
stateString = QObject::tr("Unavailable");
|
||||
break;
|
||||
case NetworkManager::Device::Disconnected:
|
||||
/*: description of unconnected network interface state */
|
||||
stateString = QObject::tr("Not connected");
|
||||
break;
|
||||
case NetworkManager::Device::Preparing:
|
||||
/*: description of preparing to connect network interface state */
|
||||
stateString = QObject::tr("Preparing to connect");
|
||||
break;
|
||||
case NetworkManager::Device::ConfiguringHardware:
|
||||
/*: description of configuring hardware network interface state */
|
||||
stateString = QObject::tr("Configuring interface");
|
||||
break;
|
||||
case NetworkManager::Device::NeedAuth:
|
||||
/*: description of waiting for authentication network interface state */
|
||||
stateString = QObject::tr("Waiting for authorization");
|
||||
break;
|
||||
case NetworkManager::Device::ConfiguringIp:
|
||||
/*: network interface doing dhcp request in most cases */
|
||||
stateString = QObject::tr("Setting network address");
|
||||
break;
|
||||
case NetworkManager::Device::CheckingIp:
|
||||
/*: is other action required to fully connect? captive portals, etc. */
|
||||
stateString = QObject::tr("Checking further connectivity");
|
||||
break;
|
||||
case NetworkManager::Device::WaitingForSecondaries:
|
||||
/*: a secondary connection (e.g. VPN) has to be activated first to continue */
|
||||
stateString = QObject::tr("Waiting for a secondary connection");
|
||||
break;
|
||||
case NetworkManager::Device::Activated:
|
||||
if (connectionName.isEmpty()) {
|
||||
/*: network interface connected state label */
|
||||
stateString = QObject::tr("Connected");
|
||||
} else {
|
||||
/*: network interface connected state label */
|
||||
stateString = QObject::tr("Connected to %1").arg(connectionName);
|
||||
}
|
||||
break;
|
||||
case NetworkManager::Device::Deactivating:
|
||||
/*: network interface disconnecting state label */
|
||||
stateString = QObject::tr("Deactivating connection");
|
||||
break;
|
||||
case NetworkManager::Device::Failed:
|
||||
/*: description of unknown network interface state */
|
||||
stateString = QObject::tr("Connection Failed");
|
||||
break;
|
||||
default:
|
||||
/*: interface state */
|
||||
stateString = QObject::tr("Error: Invalid state");
|
||||
}
|
||||
return stateString;
|
||||
}
|
||||
|
||||
QString UiUtils::vpnConnectionStateToString(VpnConnection::State state)
|
||||
{
|
||||
QString stateString;
|
||||
switch (state) {
|
||||
case VpnConnection::Unknown:
|
||||
/*: The state of the VPN connection is unknown */
|
||||
stateString = QObject::tr("Unknown");
|
||||
break;
|
||||
case VpnConnection::Prepare:
|
||||
/*: The VPN connection is preparing to connect */
|
||||
stateString = QObject::tr("Preparing to connect");
|
||||
break;
|
||||
case VpnConnection::NeedAuth:
|
||||
/*: The VPN connection needs authorization credentials */
|
||||
stateString = QObject::tr("Needs authorization");
|
||||
break;
|
||||
case VpnConnection::Connecting:
|
||||
/*: The VPN connection is being established */
|
||||
stateString = QObject::tr("Connecting");
|
||||
break;
|
||||
case VpnConnection::GettingIpConfig:
|
||||
/*: The VPN connection is getting an IP address */
|
||||
stateString = QObject::tr("Setting network address");
|
||||
break;
|
||||
case VpnConnection::Activated:
|
||||
/*: The VPN connection is active */
|
||||
stateString = QObject::tr("Activated");
|
||||
break;
|
||||
case VpnConnection::Failed:
|
||||
/*: The VPN connection failed */
|
||||
stateString = QObject::tr("Failed");
|
||||
break;
|
||||
case VpnConnection::Disconnected:
|
||||
/*: The VPN connection is disconnected */
|
||||
stateString = QObject::tr("Failed");
|
||||
break;
|
||||
default:
|
||||
/*: interface state */
|
||||
stateString = QObject::tr("interface state", "Error: Invalid state");
|
||||
}
|
||||
return stateString;
|
||||
}
|
||||
|
||||
QString UiUtils::operationModeToString(NetworkManager::WirelessDevice::OperationMode mode)
|
||||
{
|
||||
QString modeString;
|
||||
switch (mode) {
|
||||
case NetworkManager::WirelessDevice::WirelessDevice::Unknown:
|
||||
/*: wireless network operation mode */
|
||||
modeString = QObject::tr("Unknown");
|
||||
break;
|
||||
case NetworkManager::WirelessDevice::Adhoc:
|
||||
/*: wireless network operation mode */
|
||||
modeString = QObject::tr("Adhoc");
|
||||
break;
|
||||
case NetworkManager::WirelessDevice::WirelessDevice::Infra:
|
||||
/*: wireless network operation mode */
|
||||
modeString = QObject::tr("Infrastructure");
|
||||
break;
|
||||
case NetworkManager::WirelessDevice::WirelessDevice::ApMode:
|
||||
/*: wireless network operation mode */
|
||||
modeString = QObject::tr("Access point");
|
||||
break;
|
||||
default:
|
||||
modeString = QObject::tr("INCORRECT MODE FIX ME");
|
||||
}
|
||||
return modeString;
|
||||
}
|
||||
|
||||
QStringList UiUtils::wpaFlagsToStringList(NetworkManager::AccessPoint::WpaFlags flags)
|
||||
{
|
||||
/* for testing purposes
|
||||
flags = NetworkManager::AccessPoint::PairWep40
|
||||
| NetworkManager::AccessPoint::PairWep104
|
||||
| NetworkManager::AccessPoint::PairTkip
|
||||
| NetworkManager::AccessPoint::PairCcmp
|
||||
| NetworkManager::AccessPoint::GroupWep40
|
||||
| NetworkManager::AccessPoint::GroupWep104
|
||||
| NetworkManager::AccessPoint::GroupTkip
|
||||
| NetworkManager::AccessPoint::GroupCcmp
|
||||
| NetworkManager::AccessPoint::KeyMgmtPsk
|
||||
| NetworkManager::AccessPoint::KeyMgmt8021x; */
|
||||
|
||||
QStringList flagList;
|
||||
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::PairWep40))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Pairwise WEP40"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::PairWep104))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Pairwise WEP104"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::PairTkip))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Pairwise TKIP"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::PairCcmp))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Pairwise CCMP"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::GroupWep40))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Group WEP40"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::GroupWep104))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Group WEP104"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::GroupTkip))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Group TKIP"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::GroupCcmp))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("Group CCMP"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::KeyMgmtPsk))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("PSK"));
|
||||
if (flags.testFlag(NetworkManager::AccessPoint::KeyMgmt8021x))
|
||||
/*: wireless network cipher */
|
||||
flagList.append(QObject::tr("802.1x"));
|
||||
|
||||
return flagList;
|
||||
}
|
||||
|
||||
|
||||
QString UiUtils::connectionSpeed(double bitrate)
|
||||
{
|
||||
QString out;
|
||||
if (bitrate < 1000) {
|
||||
/*: connection speed */
|
||||
out = QObject::tr("%1 Bit/s").arg(bitrate);
|
||||
} else if (bitrate < 1000000) {
|
||||
/*: connection speed */
|
||||
out = QObject::tr("%1 MBit/s").arg(bitrate/1000);
|
||||
} else {
|
||||
/*: connection speed */
|
||||
out = QObject::tr("%1 GBit/s").arg(bitrate/1000000);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QString UiUtils::wirelessBandToString(NetworkManager::WirelessSetting::FrequencyBand band)
|
||||
{
|
||||
switch (band) {
|
||||
case NetworkManager::WirelessSetting::Automatic:
|
||||
return QLatin1String("automatic");
|
||||
break;
|
||||
case NetworkManager::WirelessSetting::A:
|
||||
return QLatin1String("a");
|
||||
break;
|
||||
case NetworkManager::WirelessSetting::Bg:
|
||||
return QLatin1String("b/g");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
QString UiUtils::convertAllowedModeToString(ModemManager::Modem::ModemModes modes)
|
||||
{
|
||||
if (modes.testFlag(MM_MODEM_MODE_4G)) {
|
||||
/*: Gsm modes (2G/3G/any) */
|
||||
return QObject::tr("LTE");
|
||||
} else if (modes.testFlag(MM_MODEM_MODE_3G)) {
|
||||
/*: Gsm modes (2G/3G/any) */
|
||||
return QObject::tr("UMTS/HSxPA");
|
||||
} else if (modes.testFlag(MM_MODEM_MODE_2G)) {
|
||||
/*: Gsm modes (2G/3G/any) */
|
||||
return QObject::tr("GPRS/EDGE");
|
||||
} else if (modes.testFlag(MM_MODEM_MODE_CS)) {
|
||||
/*: Gsm modes (2G/3G/any) */
|
||||
return QObject::tr("GSM");
|
||||
} else if (modes.testFlag(MM_MODEM_MODE_ANY)) {
|
||||
/*: Gsm modes (2G/3G/any) */
|
||||
return QObject::tr("Any");
|
||||
}
|
||||
|
||||
/*: Gsm modes (2G/3G/any) */
|
||||
return QObject::tr("Any");
|
||||
}
|
||||
|
||||
QString UiUtils::convertAccessTechnologyToString(ModemManager::Modem::AccessTechnologies tech)
|
||||
{
|
||||
if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_LTE)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("LTE");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_EVDOB)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("CDMA2000 EVDO revision B");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_EVDOA)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("CDMA2000 EVDO revision A");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_EVDO0)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("CDMA2000 EVDO revision 0");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("CDMA2000 1xRTT");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("HSPA+");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_HSPA)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("HSPA");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_HSUPA)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("HSUPA");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_HSDPA)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("HSDPA");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_UMTS)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("UMTS");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_EDGE)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("EDGE");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_GPRS)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("GPRS");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("Compact GSM");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_GSM)) {
|
||||
/*: Cellular access technology */
|
||||
return QObject::tr("GSM");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_POTS)) {
|
||||
/*: Analog wireline modem */
|
||||
return QObject::tr("Analog");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN)) {
|
||||
/*: Unknown cellular access technology */
|
||||
return QObject::tr("Unknown");
|
||||
} else if (tech.testFlag(MM_MODEM_ACCESS_TECHNOLOGY_ANY)) {
|
||||
/*: Any cellular access technology */
|
||||
return QObject::tr("Any");
|
||||
}
|
||||
|
||||
/*: Unknown cellular access technology */
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
|
||||
QString UiUtils::convertLockReasonToString(MMModemLock reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case MM_MODEM_LOCK_NONE:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem is unlocked.");
|
||||
case MM_MODEM_LOCK_SIM_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("SIM requires the PIN code.");
|
||||
case MM_MODEM_LOCK_SIM_PIN2:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("SIM requires the PIN2 code.");
|
||||
case MM_MODEM_LOCK_SIM_PUK:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("SIM requires the PUK code.");
|
||||
case MM_MODEM_LOCK_SIM_PUK2:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("SIM requires the PUK2 code.");
|
||||
case MM_MODEM_LOCK_PH_SP_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the service provider PIN code.");
|
||||
case MM_MODEM_LOCK_PH_SP_PUK:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the service provider PUK code.");
|
||||
case MM_MODEM_LOCK_PH_NET_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the network PIN code.");
|
||||
case MM_MODEM_LOCK_PH_NET_PUK:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the network PUK code.");
|
||||
case MM_MODEM_LOCK_PH_SIM_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the PIN code.");
|
||||
case MM_MODEM_LOCK_PH_CORP_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the corporate PIN code.");
|
||||
case MM_MODEM_LOCK_PH_CORP_PUK:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the corporate PUK code.");
|
||||
case MM_MODEM_LOCK_PH_FSIM_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the PH-FSIM PIN code.");
|
||||
case MM_MODEM_LOCK_PH_FSIM_PUK:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the PH-FSIM PUK code.");
|
||||
case MM_MODEM_LOCK_PH_NETSUB_PIN:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the network subset PIN code.");
|
||||
case MM_MODEM_LOCK_PH_NETSUB_PUK:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Modem requires the network subset PUK code.");
|
||||
case MM_MODEM_LOCK_UNKNOWN:
|
||||
default:
|
||||
/*: possible SIM lock reason */
|
||||
return QObject::tr("Lock reason unknown.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !NM_CHECK_VERSION(1, 2, 0)
|
||||
QString UiUtils::convertNspTypeToString(WimaxNsp::NetworkType type)
|
||||
{
|
||||
switch (type) {
|
||||
/*: unknown Wimax NSP type */
|
||||
case WimaxNsp::Unknown: return QObject::tr("Unknown");
|
||||
case WimaxNsp::Home: return QObject::tr("Home");
|
||||
case WimaxNsp::Partner: return QObject::tr("Partner");
|
||||
case WimaxNsp::RoamingPartner: return QObject::tr("Roaming partner");
|
||||
default: break;
|
||||
}
|
||||
|
||||
/*: Unknown */
|
||||
return QObject::tr("Unknown Wimax NSP type");
|
||||
}
|
||||
#endif
|
||||
|
||||
NetworkManager::ModemDevice::Capability UiUtils::modemSubType(NetworkManager::ModemDevice::Capabilities modemCaps)
|
||||
{
|
||||
if (modemCaps & NetworkManager::ModemDevice::Lte) {
|
||||
return NetworkManager::ModemDevice::Lte;
|
||||
} else if (modemCaps & NetworkManager::ModemDevice::CdmaEvdo) {
|
||||
return NetworkManager::ModemDevice::CdmaEvdo;
|
||||
} else if (modemCaps & NetworkManager::ModemDevice::GsmUmts) {
|
||||
return NetworkManager::ModemDevice::GsmUmts;
|
||||
} else if (modemCaps & NetworkManager::ModemDevice::Pots) {
|
||||
return NetworkManager::ModemDevice::Pots;
|
||||
}
|
||||
return NetworkManager::ModemDevice::NoCapability;
|
||||
}
|
||||
|
||||
QString UiUtils::labelFromWirelessSecurity(NetworkManager::WirelessSecurityType type)
|
||||
{
|
||||
QString tip;
|
||||
switch (type) {
|
||||
case NetworkManager::NoneSecurity:
|
||||
/*: @label no security */
|
||||
tip = QObject::tr("Insecure");
|
||||
break;
|
||||
case NetworkManager::StaticWep:
|
||||
/*: @label WEP security */
|
||||
tip = QObject::tr("WEP");
|
||||
break;
|
||||
case NetworkManager::Leap:
|
||||
/*: @label LEAP security */
|
||||
tip = QObject::tr("LEAP");
|
||||
break;
|
||||
case NetworkManager::DynamicWep:
|
||||
/*: @label Dynamic WEP security */
|
||||
tip = QObject::tr("Dynamic WEP");
|
||||
break;
|
||||
case NetworkManager::WpaPsk:
|
||||
/*: @label WPA-PSK security */
|
||||
tip = QObject::tr("WPA-PSK");
|
||||
break;
|
||||
case NetworkManager::WpaEap:
|
||||
/*: @label WPA-EAP security */
|
||||
tip = QObject::tr("WPA-EAP");
|
||||
break;
|
||||
case NetworkManager::Wpa2Psk:
|
||||
/*: @label WPA2-PSK security */
|
||||
tip = QObject::tr("WPA2-PSK");
|
||||
break;
|
||||
case NetworkManager::Wpa2Eap:
|
||||
/*: @label WPA2-EAP security */
|
||||
tip = QObject::tr("WPA2-EAP");
|
||||
break;
|
||||
default:
|
||||
/*: @label unknown security */
|
||||
// tip = QObject::tr("Unknown security type");
|
||||
tip = QObject::tr("Unknown");
|
||||
break;
|
||||
}
|
||||
return tip;
|
||||
}
|
||||
|
||||
QString UiUtils::formatDateRelative(const QDateTime & lastUsed)
|
||||
{
|
||||
QString lastUsedText;
|
||||
if (lastUsed.isValid()) {
|
||||
const QDateTime now = QDateTime::currentDateTime();
|
||||
if (lastUsed.daysTo(now) == 0 ) {
|
||||
const int secondsAgo = lastUsed.secsTo(now);
|
||||
if (secondsAgo < (60 * 60 )) {
|
||||
const int minutesAgo = secondsAgo / 60;
|
||||
/*: Label for last used time for a network connection used in the last hour, as the number of minutes since usage */
|
||||
lastUsedText = QObject::tr("%n minute(s) ago", "", minutesAgo);
|
||||
} else {
|
||||
const int hoursAgo = secondsAgo / (60 * 60);
|
||||
/*: Label for last used time for a network connection used in the last day, as the number of hours since usage */
|
||||
lastUsedText = QObject::tr("%n hour(s) ago", "", hoursAgo);
|
||||
}
|
||||
} else if (lastUsed.daysTo(now) == 1) {
|
||||
/*: Label for last used time for a network connection used the previous day */
|
||||
lastUsedText = QObject::tr("Yesterday");
|
||||
} else {
|
||||
lastUsedText = QLocale().toString(lastUsed.date(), QLocale::ShortFormat);
|
||||
}
|
||||
} else {
|
||||
/*: Label for last used time for a network connection that has never been used */
|
||||
lastUsedText = QObject::tr("Never");
|
||||
}
|
||||
return lastUsedText;
|
||||
}
|
||||
|
||||
QString UiUtils::formatLastUsedDateRelative(const QDateTime & lastUsed)
|
||||
{
|
||||
QString lastUsedText;
|
||||
if (lastUsed.isValid()) {
|
||||
const QDateTime now = QDateTime::currentDateTime();
|
||||
if (lastUsed.daysTo(now) == 0 ) {
|
||||
const int secondsAgo = lastUsed.secsTo(now);
|
||||
if (secondsAgo < (60 * 60 )) {
|
||||
const int minutesAgo = secondsAgo / 60;
|
||||
/*: Label for last used time for a network connection used in the last hour, as the number of minutes since usage */
|
||||
lastUsedText = QObject::tr("Last used %n minute(s) ago", "", minutesAgo);
|
||||
} else {
|
||||
const int hoursAgo = secondsAgo / (60 * 60);
|
||||
/*: Label for last used time for a network connection used in the last day, as the number of hours since usage */
|
||||
lastUsedText = QObject::tr("Last used %n hour(s) ago", "", hoursAgo);
|
||||
}
|
||||
} else if (lastUsed.daysTo(now) == 1) {
|
||||
/*: Label for last used time for a network connection used the previous day */
|
||||
lastUsedText = QObject::tr("Last used yesterday");
|
||||
} else {
|
||||
lastUsedText = QObject::tr("Last used on %1").arg(QLocale().toString(lastUsed.date(), QLocale::ShortFormat));
|
||||
}
|
||||
} else {
|
||||
/*: Label for last used time for a network connection that has never been used */
|
||||
lastUsedText = QObject::tr("Never used");
|
||||
}
|
||||
return lastUsedText;
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
/*
|
||||
Copyright 2008-2010 Sebastian Kügler <sebas@kde.org>
|
||||
Copyright 2013-2014 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
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) version 3 or any later version
|
||||
accepted by the membership of KDE e.V. (or its successor approved
|
||||
by the membership of KDE e.V.), which shall act as a proxy
|
||||
defined in Section 14 of version 3 of the license.
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UIUTILS_H
|
||||
#define UIUTILS_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
|
||||
#include <NetworkManagerQt/Device>
|
||||
#include <NetworkManagerQt/ModemDevice>
|
||||
#include <NetworkManagerQt/WirelessDevice>
|
||||
#include <NetworkManagerQt/WirelessSetting>
|
||||
#include <NetworkManagerQt/AccessPoint>
|
||||
#include <NetworkManagerQt/WimaxNsp>
|
||||
#include <NetworkManagerQt/Utils>
|
||||
#include <NetworkManagerQt/BluetoothDevice>
|
||||
#include <NetworkManagerQt/WimaxDevice>
|
||||
#include <NetworkManagerQt/WiredDevice>
|
||||
#include <NetworkManagerQt/VpnConnection>
|
||||
#include <NetworkManagerQt/VpnSetting>
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
#include <ModemManager/ModemManager.h>
|
||||
#include <ModemManagerQt/modem.h>
|
||||
#endif
|
||||
|
||||
class NETWORKMANAGER_EXPORT UiUtils
|
||||
{
|
||||
public:
|
||||
enum SortedConnectionType {
|
||||
Wired,
|
||||
Wireless,
|
||||
Gsm,
|
||||
Cdma,
|
||||
Pppoe,
|
||||
Adsl,
|
||||
Infiniband,
|
||||
OLPCMesh,
|
||||
Bluetooth,
|
||||
Vpn,
|
||||
Vlan,
|
||||
Bridge,
|
||||
Bond,
|
||||
Team,
|
||||
Unknown
|
||||
};
|
||||
|
||||
/*
|
||||
* @return sorted connection type used to prioritize specific connection types
|
||||
*/
|
||||
static SortedConnectionType connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type);
|
||||
|
||||
/*
|
||||
* @return whether given connection type is supported
|
||||
* Currently ignored connection types: Bond, Bridge, Generic, Infiniband, Team, Vlan, Tun
|
||||
*/
|
||||
static bool isConnectionTypeSupported(NetworkManager::ConnectionSettings::ConnectionType type);
|
||||
|
||||
/**
|
||||
* @return true if the connection is virtual.
|
||||
* @param type Type of the network connection
|
||||
*/
|
||||
static bool isConnectionTypeVirtual(NetworkManager::ConnectionSettings::ConnectionType type);
|
||||
|
||||
/**
|
||||
* @return a human-readable description for the network interface type for use as label
|
||||
* @param type the type of the network interface
|
||||
*/
|
||||
static QString interfaceTypeLabel(const NetworkManager::Device::Type type, const NetworkManager::Device::Ptr iface);
|
||||
|
||||
/**
|
||||
* @return a human-readable name for a given network interface according to the configured
|
||||
* naming style
|
||||
* @param type type of the network interface
|
||||
* @param interfaceName name of the network interface (eg eth0)
|
||||
*/
|
||||
static QString prettyInterfaceName(NetworkManager::Device::Type type, const QString &interfaceName);
|
||||
|
||||
/**
|
||||
* @return a human-readable description of the connection state of a given network interface
|
||||
* @param state The connection state
|
||||
*/
|
||||
static QString connectionStateToString(NetworkManager::Device::State state, const QString &connectionName = QString());
|
||||
|
||||
static QString vpnConnectionStateToString(NetworkManager::VpnConnection::State state);
|
||||
|
||||
static QString iconAndTitleForConnectionSettingsType(NetworkManager::ConnectionSettings::ConnectionType type,
|
||||
QString &title);
|
||||
/**
|
||||
* @return a human-readable description of operation mode.
|
||||
* @param mode the operation mode
|
||||
*/
|
||||
static QString operationModeToString(NetworkManager::WirelessDevice::OperationMode mode);
|
||||
|
||||
/**
|
||||
* @return string list with a human-readable description of wpa flags.
|
||||
* @param flags the wpa flags
|
||||
*/
|
||||
static QStringList wpaFlagsToStringList(NetworkManager::AccessPoint::WpaFlags flags);
|
||||
|
||||
/**
|
||||
* @return localized string showing a human-readable connection speed. 1000 is used as base.
|
||||
* @param bitrate bitrate of the connection per second
|
||||
*/
|
||||
static QString connectionSpeed(double bitrate);
|
||||
|
||||
/**
|
||||
* @param band The band of a wireless network. The value corresponds to the type enum in Knm::WirelessSetting::EnumBand
|
||||
* @return A string representation
|
||||
*/
|
||||
static QString wirelessBandToString(NetworkManager::WirelessSetting::FrequencyBand band);
|
||||
|
||||
#if WITH_MODEMMANAGER_SUPPORT
|
||||
static QString convertAllowedModeToString(ModemManager::Modem::ModemModes mode);
|
||||
static QString convertAccessTechnologyToString(ModemManager::Modem::AccessTechnologies tech);
|
||||
static QString convertLockReasonToString(MMModemLock reason);
|
||||
#endif
|
||||
static NetworkManager::ModemDevice::Capability modemSubType(NetworkManager::ModemDevice::Capabilities modemCaps);
|
||||
#if !NM_CHECK_VERSION(1, 2, 0)
|
||||
static QString convertNspTypeToString(NetworkManager::WimaxNsp::NetworkType type);
|
||||
#endif
|
||||
static QString labelFromWirelessSecurity(NetworkManager::WirelessSecurityType type);
|
||||
|
||||
static QString formatDateRelative(const QDateTime & lastUsed);
|
||||
static QString formatLastUsedDateRelative(const QDateTime & lastUsed);
|
||||
};
|
||||
#endif // UIUTILS_H
|
||||
@ -0,0 +1,131 @@
|
||||
#include <NetworkManagerQt/Settings>
|
||||
#include <NetworkManagerQt/WiredSetting>
|
||||
#include <QDebug>
|
||||
|
||||
#include "wiressitemsettings.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
WirelessItemSettings::WirelessItemSettings(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString WirelessItemSettings::path() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void WirelessItemSettings::setPath(const QString &path)
|
||||
{
|
||||
if (m_path == path)
|
||||
return;
|
||||
|
||||
m_path = path;
|
||||
|
||||
m_connection = NetworkManager::findConnection(m_path);
|
||||
if (m_connection) {
|
||||
m_settings = m_connection->settings();
|
||||
Q_EMIT nameChanged();
|
||||
Q_EMIT autoConnectChanged();
|
||||
Q_EMIT availableToOtherUsersChanged();
|
||||
Q_EMIT settingsAvailable();
|
||||
} else {
|
||||
m_settings.reset();
|
||||
}
|
||||
|
||||
Q_EMIT pathChanged();
|
||||
}
|
||||
|
||||
QString WirelessItemSettings::name() const
|
||||
{
|
||||
if (m_settings)
|
||||
return m_settings->id();
|
||||
else
|
||||
qWarning("NetworkManager settings are invalid");
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void WirelessItemSettings::setName(const QString &name)
|
||||
{
|
||||
if (m_settings) {
|
||||
if (this->name() == name)
|
||||
return;
|
||||
m_settings->setId(name);
|
||||
m_connection->update(m_settings->toMap());
|
||||
Q_EMIT nameChanged();
|
||||
} else {
|
||||
qWarning("NetworkManager settings are invalid");
|
||||
}
|
||||
}
|
||||
|
||||
bool WirelessItemSettings::autoConnect() const
|
||||
{
|
||||
if (m_settings)
|
||||
return m_settings->autoconnect();
|
||||
else
|
||||
qWarning("NetworkManager settings are invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
void WirelessItemSettings::setAutoConnect(bool value)
|
||||
{
|
||||
if (m_settings) {
|
||||
if (this->autoConnect() == value)
|
||||
return;
|
||||
m_settings->setAutoconnect(value);
|
||||
m_connection->update(m_settings->toMap());
|
||||
Q_EMIT autoConnectChanged();
|
||||
} else {
|
||||
qWarning("NetworkManager settings are invalid");
|
||||
}
|
||||
}
|
||||
|
||||
bool WirelessItemSettings::availableToOtherUsers() const
|
||||
{
|
||||
if (m_settings)
|
||||
return m_settings->permissions().isEmpty();
|
||||
else
|
||||
qWarning("NetworkManager settings are invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
void WirelessItemSettings::setAvailableToOtherUsers(bool value)
|
||||
{
|
||||
if (m_settings) {
|
||||
bool availableToOtherUsers = m_settings->permissions().isEmpty();
|
||||
if (availableToOtherUsers == value)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
m_settings->setPermissions(QHash<QString, QString>());
|
||||
else
|
||||
m_settings->addToPermissions(getCurrentUserName(), QString());
|
||||
m_connection->update(m_settings->toMap());
|
||||
Q_EMIT availableToOtherUsersChanged();
|
||||
} else {
|
||||
qWarning("NetworkManager settings are invalid");
|
||||
}
|
||||
}
|
||||
|
||||
void WirelessItemSettings::updateSettings(const QString &type, const QVariantMap &map)
|
||||
{
|
||||
if (!m_settings)
|
||||
return;
|
||||
|
||||
NMVariantMapMap settings = m_settings->toMap();
|
||||
settings.insert(type, map);
|
||||
m_connection->update(settings);
|
||||
}
|
||||
|
||||
QString WirelessItemSettings::getCurrentUserName() const
|
||||
{
|
||||
uid_t uid = ::geteuid();
|
||||
struct passwd *pw = ::getpwuid(uid);
|
||||
if (pw)
|
||||
return QString::fromLocal8Bit(pw->pw_name);
|
||||
return QString();
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
#ifndef WIRELESSITEMSETTINGS_H
|
||||
#define WIRELESSITEMSETTINGS_H
|
||||
|
||||
#include <networkmanager_export.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <NetworkManagerQt/Connection>
|
||||
|
||||
class NETWORKMANAGER_EXPORT WirelessItemSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||
Q_PROPERTY(bool autoConnect READ autoConnect WRITE setAutoConnect NOTIFY autoConnectChanged)
|
||||
Q_PROPERTY(bool availableToOtherUsers READ availableToOtherUsers WRITE setAvailableToOtherUsers NOTIFY availableToOtherUsersChanged)
|
||||
|
||||
public:
|
||||
WirelessItemSettings(QObject *parent = nullptr);
|
||||
|
||||
QString path() const;
|
||||
void setPath(const QString &path);
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
bool autoConnect() const;
|
||||
void setAutoConnect(bool value);
|
||||
|
||||
bool availableToOtherUsers() const;
|
||||
void setAvailableToOtherUsers(bool value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void pathChanged();
|
||||
void settingsAvailable();
|
||||
void nameChanged();
|
||||
void autoConnectChanged();
|
||||
void availableToOtherUsersChanged();
|
||||
|
||||
protected:
|
||||
NetworkManager::Connection::Ptr m_connection;
|
||||
NetworkManager::ConnectionSettings::Ptr m_settings;
|
||||
|
||||
void updateSettings(const QString &type, const QVariantMap &map);
|
||||
|
||||
private:
|
||||
QString m_path;
|
||||
|
||||
QString getCurrentUserName() const;
|
||||
};
|
||||
|
||||
#endif // WIRELESSITEMSETTINGS_H
|
||||
@ -0,0 +1,31 @@
|
||||
set(SCREEN_SRCS
|
||||
common/control.cpp
|
||||
common/globals.cpp
|
||||
common/orientation_sensor.cpp
|
||||
common/utils.cpp
|
||||
confighandler.cpp
|
||||
outputmodel.cpp
|
||||
plugin.cpp
|
||||
screen.cpp
|
||||
)
|
||||
|
||||
find_package(KF5Screen REQUIRED)
|
||||
find_package(KF5KIO REQUIRED)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Test Sensors)
|
||||
|
||||
add_library(cutefishscreen_qmlplugins SHARED ${SCREEN_SRCS})
|
||||
|
||||
target_link_libraries (cutefishscreen_qmlplugins
|
||||
Qt5::Core
|
||||
Qt5::Quick
|
||||
Qt5::Gui
|
||||
Qt5::DBus
|
||||
Qt5::Sensors
|
||||
Qt5::Test
|
||||
|
||||
KF5::Screen
|
||||
KF5::KIOCore
|
||||
)
|
||||
|
||||
install(TARGETS cutefishscreen_qmlplugins DESTINATION ${INSTALL_QMLDIR}/Cutefish/Screen)
|
||||
install(FILES qmldir DESTINATION ${INSTALL_QMLDIR}/Cutefish/Screen)
|
||||
@ -0,0 +1,645 @@
|
||||
/********************************************************************
|
||||
Copyright 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <QStringBuilder>
|
||||
#include <QFile>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QJsonDocument>
|
||||
#include <QDir>
|
||||
|
||||
#include <kscreen/config.h>
|
||||
#include <kscreen/output.h>
|
||||
|
||||
QString Control::s_dirName = QStringLiteral("control/");
|
||||
|
||||
Control::Control(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void Control::activateWatcher()
|
||||
{
|
||||
if (m_watcher) {
|
||||
return;
|
||||
}
|
||||
m_watcher = new QFileSystemWatcher({filePath()}, this);
|
||||
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() {
|
||||
readFile();
|
||||
Q_EMIT changed();
|
||||
});
|
||||
}
|
||||
|
||||
QFileSystemWatcher* Control::watcher() const
|
||||
{
|
||||
return m_watcher;
|
||||
}
|
||||
|
||||
bool Control::writeFile()
|
||||
{
|
||||
const QString path = filePath();
|
||||
const auto infoMap = constInfo();
|
||||
|
||||
if (infoMap.isEmpty()) {
|
||||
// Nothing to write. Default control. Remove file if it exists.
|
||||
QFile::remove(path);
|
||||
return true;
|
||||
}
|
||||
if (!QDir().mkpath(dirPath())) {
|
||||
// TODO: error message
|
||||
return false;
|
||||
}
|
||||
|
||||
// write updated data to file
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
// TODO: logging category?
|
||||
// qCWarning(KSCREEN_COMMON) << "Failed to open config control file for writing! " << file.errorString();
|
||||
return false;
|
||||
}
|
||||
file.write(QJsonDocument::fromVariant(infoMap).toJson());
|
||||
// qCDebug(KSCREEN_COMMON) << "Control saved on: " << file.fileName();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString Control::dirPath() const
|
||||
{
|
||||
return Globals::dirPath() % s_dirName;
|
||||
}
|
||||
|
||||
void Control::readFile()
|
||||
{
|
||||
QFile file(filePath());
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
// This might not be reached, bus this is ok. The control file will
|
||||
// eventually be created on first write later on.
|
||||
QJsonDocument parser;
|
||||
m_info = parser.fromJson(file.readAll()).toVariant().toMap();
|
||||
}
|
||||
}
|
||||
|
||||
QString Control::filePathFromHash(const QString &hash) const
|
||||
{
|
||||
return dirPath() % hash;
|
||||
}
|
||||
|
||||
QVariantMap& Control::info()
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
|
||||
const QVariantMap& Control::constInfo() const
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
|
||||
Control::OutputRetention Control::convertVariantToOutputRetention(QVariant variant)
|
||||
{
|
||||
if (variant.canConvert<int>()) {
|
||||
const auto retention = variant.toInt();
|
||||
if (retention == (int)OutputRetention::Global) {
|
||||
return OutputRetention::Global;
|
||||
}
|
||||
if (retention == (int)OutputRetention::Individual) {
|
||||
return OutputRetention::Individual;
|
||||
}
|
||||
}
|
||||
return OutputRetention::Undefined;
|
||||
}
|
||||
|
||||
ControlConfig::ControlConfig(KScreen::ConfigPtr config, QObject *parent)
|
||||
: Control(parent)
|
||||
, m_config(config)
|
||||
{
|
||||
// qDebug() << "Looking for control file:" << config->connectedOutputsHash();
|
||||
readFile();
|
||||
|
||||
// TODO: use a file watcher in case of changes to the control file while
|
||||
// object exists?
|
||||
|
||||
// As global outputs are indexed by a hash of their edid, which is not unique,
|
||||
// to be able to tell apart multiple identical outputs, these need special treatment
|
||||
QStringList allIds;
|
||||
const auto outputs = config->outputs();
|
||||
allIds.reserve(outputs.count());
|
||||
for (const KScreen::OutputPtr &output : outputs) {
|
||||
const auto outputId = output->hashMd5();
|
||||
if (allIds.contains(outputId) && !m_duplicateOutputIds.contains(outputId)) {
|
||||
m_duplicateOutputIds << outputId;
|
||||
}
|
||||
allIds << outputId;
|
||||
}
|
||||
|
||||
for (auto output : outputs) {
|
||||
m_outputsControls << new ControlOutput(output, this);
|
||||
}
|
||||
|
||||
// TODO: this is same in Output::readInOutputs of the daemon. Combine?
|
||||
|
||||
// TODO: connect to outputs added/removed signals and reevaluate duplicate ids
|
||||
// in case of such a change while object exists?
|
||||
}
|
||||
|
||||
void ControlConfig::activateWatcher()
|
||||
{
|
||||
if (watcher()) {
|
||||
// Watcher was already activated.
|
||||
return;
|
||||
}
|
||||
for (auto *output : m_outputsControls) {
|
||||
output->activateWatcher();
|
||||
connect(output, &ControlOutput::changed, this, &ControlConfig::changed);
|
||||
}
|
||||
}
|
||||
|
||||
QString ControlConfig::dirPath() const
|
||||
{
|
||||
return Control::dirPath() % QStringLiteral("configs/");
|
||||
}
|
||||
|
||||
QString ControlConfig::filePath() const
|
||||
{
|
||||
if (!m_config) {
|
||||
return QString();
|
||||
}
|
||||
return filePathFromHash(m_config->connectedOutputsHash());
|
||||
}
|
||||
|
||||
bool ControlConfig::writeFile()
|
||||
{
|
||||
bool success = true;
|
||||
for (auto *outputControl : m_outputsControls) {
|
||||
if (getOutputRetention(outputControl->id(), outputControl->name())
|
||||
== OutputRetention::Individual) {
|
||||
continue;
|
||||
}
|
||||
success &= outputControl->writeFile();
|
||||
}
|
||||
return success && Control::writeFile();
|
||||
}
|
||||
|
||||
bool ControlConfig::infoIsOutput(const QVariantMap &info, const QString &outputId, const QString &outputName) const
|
||||
{
|
||||
const QString outputIdInfo = info[QStringLiteral("id")].toString();
|
||||
if (outputIdInfo.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (outputId != outputIdInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!outputName.isEmpty() && m_duplicateOutputIds.contains(outputId)) {
|
||||
// We may have identical outputs connected, these will have the same id in the config
|
||||
// in order to find the right one, also check the output's name (usually the connector)
|
||||
const auto metadata = info[QStringLiteral("metadata")].toMap();
|
||||
const auto outputNameInfo = metadata[QStringLiteral("name")].toString();
|
||||
if (outputName != outputNameInfo) {
|
||||
// was a duplicate id, but info not for this output
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Control::OutputRetention ControlConfig::getOutputRetention(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return getOutputRetention(output->hashMd5(), output->name());
|
||||
}
|
||||
|
||||
Control::OutputRetention ControlConfig::getOutputRetention(const QString &outputId, const QString &outputName) const
|
||||
{
|
||||
const QVariantList outputsInfo = getOutputs();
|
||||
for (const auto &variantInfo : outputsInfo) {
|
||||
const QVariantMap info = variantInfo.toMap();
|
||||
if (!infoIsOutput(info, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
return convertVariantToOutputRetention(info[QStringLiteral("retention")]);
|
||||
}
|
||||
// info for output not found
|
||||
return OutputRetention::Undefined;
|
||||
}
|
||||
|
||||
static QVariantMap metadata(const QString &outputName)
|
||||
{
|
||||
QVariantMap metadata;
|
||||
metadata[QStringLiteral("name")] = outputName;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
QVariantMap createOutputInfo(const QString &outputId, const QString &outputName)
|
||||
{
|
||||
QVariantMap outputInfo;
|
||||
outputInfo[QStringLiteral("id")] = outputId;
|
||||
outputInfo[QStringLiteral("metadata")] = metadata(outputName);
|
||||
return outputInfo;
|
||||
}
|
||||
|
||||
void ControlConfig::setOutputRetention(const KScreen::OutputPtr &output, OutputRetention value)
|
||||
{
|
||||
setOutputRetention(output->hashMd5(), output->name(), value);
|
||||
}
|
||||
|
||||
void ControlConfig::setOutputRetention(const QString &outputId, const QString &outputName, OutputRetention value)
|
||||
{
|
||||
QList<QVariant>::iterator it;
|
||||
QVariantList outputsInfo = getOutputs();
|
||||
|
||||
for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) {
|
||||
QVariantMap outputInfo = (*it).toMap();
|
||||
if (!infoIsOutput(outputInfo, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
outputInfo[QStringLiteral("retention")] = (int)value;
|
||||
*it = outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
return;
|
||||
}
|
||||
// no entry yet, create one
|
||||
auto outputInfo = createOutputInfo(outputId, outputName);
|
||||
outputInfo[QStringLiteral("retention")] = (int)value;
|
||||
|
||||
outputsInfo << outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
}
|
||||
|
||||
qreal ControlConfig::getScale(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return getScale(output->hashMd5(), output->name());
|
||||
}
|
||||
|
||||
qreal ControlConfig::getScale(const QString &outputId, const QString &outputName) const
|
||||
{
|
||||
const auto retention = getOutputRetention(outputId, outputName);
|
||||
if (retention == OutputRetention::Individual) {
|
||||
const QVariantList outputsInfo = getOutputs();
|
||||
for (const auto &variantInfo : outputsInfo) {
|
||||
const QVariantMap info = variantInfo.toMap();
|
||||
if (!infoIsOutput(info, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
const auto val = info[QStringLiteral("scale")];
|
||||
return val.canConvert<qreal>() ? val.toReal() : -1;
|
||||
}
|
||||
}
|
||||
// Retention is global or info for output not in config control file.
|
||||
if (auto *outputControl = getOutputControl(outputId, outputName)) {
|
||||
return outputControl->getScale();
|
||||
}
|
||||
|
||||
// Info for output not found.
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ControlConfig::setScale(const KScreen::OutputPtr &output, qreal value)
|
||||
{
|
||||
setScale(output->hashMd5(), output->name(), value);
|
||||
}
|
||||
|
||||
// TODO: combine methods (templated functions)
|
||||
void ControlConfig::setScale(const QString &outputId, const QString &outputName, qreal value)
|
||||
{
|
||||
QList<QVariant>::iterator it;
|
||||
QVariantList outputsInfo = getOutputs();
|
||||
|
||||
auto setOutputScale = [&outputId, &outputName, value, this]() {
|
||||
if (auto *control = getOutputControl(outputId, outputName)) {
|
||||
control->setScale(value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) {
|
||||
QVariantMap outputInfo = (*it).toMap();
|
||||
if (!infoIsOutput(outputInfo, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
outputInfo[QStringLiteral("scale")] = value;
|
||||
*it = outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
setOutputScale();
|
||||
return;
|
||||
}
|
||||
// no entry yet, create one
|
||||
auto outputInfo = createOutputInfo(outputId, outputName);
|
||||
outputInfo[QStringLiteral("scale")] = value;
|
||||
|
||||
outputsInfo << outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
setOutputScale();
|
||||
}
|
||||
|
||||
bool ControlConfig::getAutoRotate(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return getAutoRotate(output->hashMd5(), output->name());
|
||||
}
|
||||
|
||||
bool ControlConfig::getAutoRotate(const QString &outputId, const QString &outputName) const
|
||||
{
|
||||
const auto retention = getOutputRetention(outputId, outputName);
|
||||
if (retention == OutputRetention::Individual) {
|
||||
const QVariantList outputsInfo = getOutputs();
|
||||
for (const auto &variantInfo : outputsInfo) {
|
||||
const QVariantMap info = variantInfo.toMap();
|
||||
if (!infoIsOutput(info, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
const auto val = info[QStringLiteral("autorotate")];
|
||||
return !val.canConvert<bool>() || val.toBool();
|
||||
}
|
||||
}
|
||||
// Retention is global or info for output not in config control file.
|
||||
if (auto *outputControl = getOutputControl(outputId, outputName)) {
|
||||
return outputControl->getAutoRotate();
|
||||
}
|
||||
|
||||
// Info for output not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlConfig::setAutoRotate(const KScreen::OutputPtr &output, bool value)
|
||||
{
|
||||
setAutoRotate(output->hashMd5(), output->name(), value);
|
||||
}
|
||||
|
||||
// TODO: combine methods (templated functions)
|
||||
void ControlConfig::setAutoRotate(const QString &outputId, const QString &outputName, bool value)
|
||||
{
|
||||
QList<QVariant>::iterator it;
|
||||
QVariantList outputsInfo = getOutputs();
|
||||
|
||||
auto setOutputAutoRotate = [&outputId, &outputName, value, this]() {
|
||||
if (auto *control = getOutputControl(outputId, outputName)) {
|
||||
control->setAutoRotate(value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) {
|
||||
QVariantMap outputInfo = (*it).toMap();
|
||||
if (!infoIsOutput(outputInfo, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
outputInfo[QStringLiteral("autorotate")] = value;
|
||||
*it = outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
setOutputAutoRotate();
|
||||
return;
|
||||
}
|
||||
// no entry yet, create one
|
||||
auto outputInfo = createOutputInfo(outputId, outputName);
|
||||
outputInfo[QStringLiteral("autorotate")] = value;
|
||||
|
||||
outputsInfo << outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
setOutputAutoRotate();
|
||||
}
|
||||
|
||||
bool ControlConfig::getAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return getAutoRotateOnlyInTabletMode(output->hashMd5(), output->name());
|
||||
}
|
||||
|
||||
bool ControlConfig::getAutoRotateOnlyInTabletMode(const QString &outputId,
|
||||
const QString &outputName) const
|
||||
{
|
||||
const auto retention = getOutputRetention(outputId, outputName);
|
||||
if (retention == OutputRetention::Individual) {
|
||||
const QVariantList outputsInfo = getOutputs();
|
||||
for (const auto &variantInfo : outputsInfo) {
|
||||
const QVariantMap info = variantInfo.toMap();
|
||||
if (!infoIsOutput(info, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
const auto val = info[QStringLiteral("autorotate-tablet-only")];
|
||||
return !val.canConvert<bool>() || val.toBool();
|
||||
}
|
||||
}
|
||||
// Retention is global or info for output not in config control file.
|
||||
if (auto *outputControl = getOutputControl(outputId, outputName)) {
|
||||
return outputControl->getAutoRotateOnlyInTabletMode();
|
||||
}
|
||||
|
||||
// Info for output not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlConfig::setAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output, bool value)
|
||||
{
|
||||
setAutoRotateOnlyInTabletMode(output->hashMd5(), output->name(), value);
|
||||
}
|
||||
|
||||
// TODO: combine methods (templated functions)
|
||||
void ControlConfig::setAutoRotateOnlyInTabletMode(const QString &outputId,
|
||||
const QString &outputName, bool value)
|
||||
{
|
||||
QList<QVariant>::iterator it;
|
||||
QVariantList outputsInfo = getOutputs();
|
||||
|
||||
auto setOutputAutoRotateOnlyInTabletMode = [&outputId, &outputName, value, this]() {
|
||||
if (auto *control = getOutputControl(outputId, outputName)) {
|
||||
control->setAutoRotateOnlyInTabletMode(value);
|
||||
}
|
||||
};
|
||||
|
||||
for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) {
|
||||
QVariantMap outputInfo = (*it).toMap();
|
||||
if (!infoIsOutput(outputInfo, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
outputInfo[QStringLiteral("autorotate-tablet-only")] = value;
|
||||
*it = outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
setOutputAutoRotateOnlyInTabletMode();
|
||||
return;
|
||||
}
|
||||
// no entry yet, create one
|
||||
auto outputInfo = createOutputInfo(outputId, outputName);
|
||||
outputInfo[QStringLiteral("autorotate-tablet-only")] = value;
|
||||
|
||||
outputsInfo << outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
setOutputAutoRotateOnlyInTabletMode();
|
||||
}
|
||||
|
||||
|
||||
KScreen::OutputPtr ControlConfig::getReplicationSource(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return getReplicationSource(output->hashMd5(), output->name());
|
||||
}
|
||||
|
||||
KScreen::OutputPtr ControlConfig::getReplicationSource(const QString &outputId,
|
||||
const QString &outputName) const
|
||||
{
|
||||
const QVariantList outputsInfo = getOutputs();
|
||||
for (const auto &variantInfo : outputsInfo) {
|
||||
const QVariantMap info = variantInfo.toMap();
|
||||
if (!infoIsOutput(info, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
const QString sourceHash = info[QStringLiteral("replicate-hash")].toString();
|
||||
const QString sourceName = info[QStringLiteral("replicate-name")].toString();
|
||||
|
||||
if (sourceHash.isEmpty() && sourceName.isEmpty()) {
|
||||
// Common case when the replication source has been unset.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const auto &output : m_config->outputs()) {
|
||||
if (output->hashMd5() == sourceHash && output->name() == sourceName) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
// No match.
|
||||
return nullptr;
|
||||
}
|
||||
// Info for output not found.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ControlConfig::setReplicationSource(const KScreen::OutputPtr &output,
|
||||
const KScreen::OutputPtr &source)
|
||||
{
|
||||
setReplicationSource(output->hashMd5(), output->name(), source);
|
||||
}
|
||||
|
||||
void ControlConfig::setReplicationSource(const QString &outputId, const QString &outputName,
|
||||
const KScreen::OutputPtr &source)
|
||||
{
|
||||
QList<QVariant>::iterator it;
|
||||
QVariantList outputsInfo = getOutputs();
|
||||
const QString sourceHash = source ? source->hashMd5() : QStringLiteral("");
|
||||
const QString sourceName = source ? source->name() : QStringLiteral("");
|
||||
|
||||
for (it = outputsInfo.begin(); it != outputsInfo.end(); ++it) {
|
||||
QVariantMap outputInfo = (*it).toMap();
|
||||
if (!infoIsOutput(outputInfo, outputId, outputName)) {
|
||||
continue;
|
||||
}
|
||||
outputInfo[QStringLiteral("replicate-hash")] = sourceHash;
|
||||
outputInfo[QStringLiteral("replicate-name")] = sourceName;
|
||||
*it = outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
// TODO: shall we set this information also as new global value (like with auto-rotate)?
|
||||
return;
|
||||
}
|
||||
// no entry yet, create one
|
||||
auto outputInfo = createOutputInfo(outputId, outputName);
|
||||
outputInfo[QStringLiteral("replicate-hash")] = sourceHash;
|
||||
outputInfo[QStringLiteral("replicate-name")] = sourceName;
|
||||
|
||||
outputsInfo << outputInfo;
|
||||
setOutputs(outputsInfo);
|
||||
// TODO: shall we set this information also as new global value (like with auto-rotate)?
|
||||
}
|
||||
|
||||
QVariantList ControlConfig::getOutputs() const
|
||||
{
|
||||
return constInfo()[QStringLiteral("outputs")].toList();
|
||||
}
|
||||
|
||||
void ControlConfig::setOutputs(QVariantList outputsInfo)
|
||||
{
|
||||
auto &infoMap = info();
|
||||
infoMap[QStringLiteral("outputs")] = outputsInfo;
|
||||
}
|
||||
ControlOutput* ControlConfig::getOutputControl(const QString &outputId,
|
||||
const QString &outputName) const
|
||||
{
|
||||
for (auto *control : m_outputsControls) {
|
||||
if (control->id() == outputId && control->name() == outputName) {
|
||||
return control;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ControlOutput::ControlOutput(KScreen::OutputPtr output, QObject *parent)
|
||||
: Control(parent)
|
||||
, m_output(output)
|
||||
{
|
||||
readFile();
|
||||
}
|
||||
|
||||
QString ControlOutput::id() const
|
||||
{
|
||||
return m_output->hashMd5();
|
||||
}
|
||||
|
||||
QString ControlOutput::name() const
|
||||
{
|
||||
return m_output->name();
|
||||
}
|
||||
|
||||
QString ControlOutput::dirPath() const
|
||||
{
|
||||
return Control::dirPath() % QStringLiteral("outputs/");
|
||||
}
|
||||
|
||||
QString ControlOutput::filePath() const
|
||||
{
|
||||
if (!m_output) {
|
||||
return QString();
|
||||
}
|
||||
return filePathFromHash(m_output->hashMd5());
|
||||
}
|
||||
|
||||
qreal ControlOutput::getScale() const
|
||||
{
|
||||
const auto val = constInfo()[QStringLiteral("scale")];
|
||||
return val.canConvert<qreal>() ? val.toReal() : -1;
|
||||
}
|
||||
|
||||
void ControlOutput::setScale(qreal value)
|
||||
{
|
||||
auto &infoMap = info();
|
||||
if (infoMap.isEmpty()) {
|
||||
infoMap = createOutputInfo(m_output->hashMd5(), m_output->name());
|
||||
}
|
||||
infoMap[QStringLiteral("scale")] = value;
|
||||
}
|
||||
|
||||
bool ControlOutput::getAutoRotate() const
|
||||
{
|
||||
const auto val = constInfo()[QStringLiteral("autorotate")];
|
||||
return !val.canConvert<bool>() || val.toBool();
|
||||
}
|
||||
|
||||
void ControlOutput::setAutoRotate(bool value)
|
||||
{
|
||||
auto &infoMap = info();
|
||||
if (infoMap.isEmpty()) {
|
||||
infoMap = createOutputInfo(m_output->hashMd5(), m_output->name());
|
||||
}
|
||||
infoMap[QStringLiteral("autorotate")] = value;
|
||||
}
|
||||
|
||||
bool ControlOutput::getAutoRotateOnlyInTabletMode() const
|
||||
{
|
||||
const auto val = constInfo()[QStringLiteral("autorotate-tablet-only")];
|
||||
return !val.canConvert<bool>() || val.toBool();
|
||||
}
|
||||
|
||||
void ControlOutput::setAutoRotateOnlyInTabletMode(bool value)
|
||||
{
|
||||
auto &infoMap = info();
|
||||
if (infoMap.isEmpty()) {
|
||||
infoMap = createOutputInfo(m_output->hashMd5(), m_output->name());
|
||||
}
|
||||
infoMap[QStringLiteral("autorotate-tablet-only")] = value;
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
/********************************************************************
|
||||
Copyright 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef COMMON_CONTROL_H
|
||||
#define COMMON_CONTROL_H
|
||||
|
||||
#include <kscreen/types.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QVariantMap>
|
||||
|
||||
class QFileSystemWatcher;
|
||||
|
||||
class Control : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class OutputRetention {
|
||||
Undefined = -1,
|
||||
Global = 0,
|
||||
Individual = 1,
|
||||
};
|
||||
Q_ENUM(OutputRetention)
|
||||
|
||||
explicit Control(QObject *parent = nullptr);
|
||||
|
||||
|
||||
~Control() override = default;
|
||||
|
||||
virtual bool writeFile();
|
||||
virtual void activateWatcher();
|
||||
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
|
||||
protected:
|
||||
virtual QString dirPath() const;
|
||||
virtual QString filePath() const = 0;
|
||||
QString filePathFromHash(const QString &hash) const;
|
||||
void readFile();
|
||||
QVariantMap& info();
|
||||
const QVariantMap& constInfo() const;
|
||||
QFileSystemWatcher* watcher() const;
|
||||
|
||||
static OutputRetention convertVariantToOutputRetention(QVariant variant);
|
||||
|
||||
private:
|
||||
static QString s_dirName;
|
||||
QVariantMap m_info;
|
||||
QFileSystemWatcher *m_watcher = nullptr;
|
||||
};
|
||||
|
||||
class ControlOutput;
|
||||
|
||||
class ControlConfig : public Control
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ControlConfig(KScreen::ConfigPtr config, QObject *parent = nullptr);
|
||||
|
||||
OutputRetention getOutputRetention(const KScreen::OutputPtr &output) const;
|
||||
OutputRetention getOutputRetention(const QString &outputId, const QString &outputName) const;
|
||||
void setOutputRetention(const KScreen::OutputPtr &output, OutputRetention value);
|
||||
void setOutputRetention(const QString &outputId, const QString &outputName, OutputRetention value);
|
||||
|
||||
qreal getScale(const KScreen::OutputPtr &output) const;
|
||||
qreal getScale(const QString &outputId, const QString &outputName) const;
|
||||
void setScale(const KScreen::OutputPtr &output, qreal value);
|
||||
void setScale(const QString &outputId, const QString &outputName, qreal value);
|
||||
|
||||
bool getAutoRotate(const KScreen::OutputPtr &output) const;
|
||||
bool getAutoRotate(const QString &outputId, const QString &outputName) const;
|
||||
void setAutoRotate(const KScreen::OutputPtr &output, bool value);
|
||||
void setAutoRotate(const QString &outputId, const QString &outputName, bool value);
|
||||
|
||||
bool getAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const;
|
||||
bool getAutoRotateOnlyInTabletMode(const QString &outputId, const QString &outputName) const;
|
||||
void setAutoRotateOnlyInTabletMode(const KScreen::OutputPtr &output, bool value);
|
||||
void setAutoRotateOnlyInTabletMode(const QString &outputId, const QString &outputName,
|
||||
bool value);
|
||||
|
||||
KScreen::OutputPtr getReplicationSource(const KScreen::OutputPtr &output) const;
|
||||
KScreen::OutputPtr getReplicationSource(const QString &outputId,
|
||||
const QString &outputName) const;
|
||||
void setReplicationSource(const KScreen::OutputPtr &output, const KScreen::OutputPtr &source);
|
||||
void setReplicationSource(const QString &outputId, const QString &outputName,
|
||||
const KScreen::OutputPtr &source);
|
||||
|
||||
QString dirPath() const override;
|
||||
QString filePath() const override;
|
||||
|
||||
bool writeFile() override;
|
||||
void activateWatcher() override;
|
||||
|
||||
private:
|
||||
QVariantList getOutputs() const;
|
||||
void setOutputs(QVariantList outputsInfo);
|
||||
bool infoIsOutput(const QVariantMap &info, const QString &outputId, const QString &outputName) const;
|
||||
ControlOutput* getOutputControl(const QString &outputId, const QString &outputName) const;
|
||||
|
||||
KScreen::ConfigPtr m_config;
|
||||
QStringList m_duplicateOutputIds;
|
||||
QVector<ControlOutput*> m_outputsControls;
|
||||
};
|
||||
|
||||
class ControlOutput : public Control
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ControlOutput(KScreen::OutputPtr output, QObject *parent = nullptr);
|
||||
|
||||
QString id() const;
|
||||
QString name() const;
|
||||
|
||||
// TODO: scale auto value
|
||||
|
||||
qreal getScale() const;
|
||||
void setScale(qreal value);
|
||||
|
||||
bool getAutoRotate() const;
|
||||
void setAutoRotate(bool value);
|
||||
|
||||
bool getAutoRotateOnlyInTabletMode() const;
|
||||
void setAutoRotateOnlyInTabletMode(bool value);
|
||||
|
||||
QString dirPath() const override;
|
||||
QString filePath() const override;
|
||||
|
||||
private:
|
||||
KScreen::OutputPtr m_output;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,40 @@
|
||||
/********************************************************************
|
||||
Copyright 2018 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "globals.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
|
||||
namespace Globals
|
||||
{
|
||||
|
||||
QString s_dirPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) %
|
||||
QStringLiteral("/kscreen/");
|
||||
|
||||
QString dirPath() {
|
||||
return s_dirPath;
|
||||
}
|
||||
|
||||
void setDirPath(const QString &path)
|
||||
{
|
||||
s_dirPath = path;
|
||||
if (!s_dirPath.endsWith(QLatin1Char('/'))) {
|
||||
s_dirPath += QLatin1Char('/');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/********************************************************************
|
||||
Copyright 2018 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef COMMON_GLOBALS_H
|
||||
#define COMMON_GLOBALS_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace Globals
|
||||
{
|
||||
void setDirPath(const QString &path);
|
||||
QString dirPath();
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,78 @@
|
||||
/********************************************************************
|
||||
Copyright © 2019 Roman Gilg <subdiff@gmail.com>
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "orientation_sensor.h"
|
||||
|
||||
#include <QOrientationSensor>
|
||||
|
||||
OrientationSensor::OrientationSensor(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_sensor(new QOrientationSensor(this))
|
||||
{
|
||||
connect(m_sensor, &QOrientationSensor::activeChanged, this, &OrientationSensor::refresh);
|
||||
}
|
||||
|
||||
OrientationSensor::~OrientationSensor() = default;
|
||||
|
||||
void OrientationSensor::updateState()
|
||||
{
|
||||
const auto orientation = m_sensor->reading()->orientation();
|
||||
if (m_value != orientation) {
|
||||
m_value = orientation;
|
||||
Q_EMIT valueChanged(orientation);
|
||||
}
|
||||
}
|
||||
|
||||
void OrientationSensor::refresh()
|
||||
{
|
||||
if (m_sensor->isActive()) {
|
||||
if (m_enabled) {
|
||||
updateState();
|
||||
}
|
||||
Q_EMIT availableChanged(true);
|
||||
} else {
|
||||
Q_EMIT availableChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
QOrientationReading::Orientation OrientationSensor::value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool OrientationSensor::available() const
|
||||
{
|
||||
return m_sensor->connectToBackend();
|
||||
}
|
||||
|
||||
bool OrientationSensor::enabled() const
|
||||
{
|
||||
return m_sensor->isActive();
|
||||
}
|
||||
|
||||
void OrientationSensor::setEnabled(bool enable)
|
||||
{
|
||||
if (m_enabled == enable) {
|
||||
return;
|
||||
}
|
||||
m_enabled = enable;
|
||||
|
||||
if (enable) {
|
||||
connect(m_sensor, &QOrientationSensor::readingChanged, this, &OrientationSensor::updateState);
|
||||
m_sensor->start();
|
||||
} else {
|
||||
disconnect(m_sensor, &QOrientationSensor::readingChanged, this, &OrientationSensor::updateState);
|
||||
m_value = QOrientationReading::Undefined;
|
||||
}
|
||||
Q_EMIT enabledChanged(enable);
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/********************************************************************
|
||||
Copyright © 2019 Roman Gilg <subdiff@gmail.com>
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QOrientationReading>
|
||||
|
||||
class OrientationSensor final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OrientationSensor(QObject *parent = nullptr);
|
||||
~OrientationSensor() override final;
|
||||
|
||||
QOrientationReading::Orientation value() const;
|
||||
bool available() const;
|
||||
bool enabled() const;
|
||||
|
||||
void setEnabled(bool enable);
|
||||
|
||||
Q_SIGNALS:
|
||||
void valueChanged(QOrientationReading::Orientation orientation);
|
||||
void availableChanged(bool available);
|
||||
void enabledChanged(bool enabled);
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
void updateState();
|
||||
|
||||
QOrientationSensor *m_sensor;
|
||||
QOrientationReading::Orientation m_value = QOrientationReading::Undefined;
|
||||
bool m_enabled = false;
|
||||
};
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2013 Daniel Vrátil <dvratil@redhat.com>
|
||||
*
|
||||
* 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) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <kscreen/output.h>
|
||||
#include <kscreen/edid.h>
|
||||
|
||||
QString Utils::outputName(const KScreen::OutputPtr& output)
|
||||
{
|
||||
return outputName(output.data());
|
||||
}
|
||||
|
||||
QString Utils::outputName(const KScreen::Output *output)
|
||||
{
|
||||
if (output->type() == KScreen::Output::Panel) {
|
||||
return QObject::tr("Laptop Screen");
|
||||
}
|
||||
|
||||
if (output->edid()) {
|
||||
// The name will be "VendorName ModelName (ConnectorName)",
|
||||
// but some components may be empty.
|
||||
QString name;
|
||||
if (!(output->edid()->vendor().isEmpty())) {
|
||||
name = output->edid()->vendor() + QLatin1Char(' ');
|
||||
}
|
||||
if (!output->edid()->name().isEmpty()) {
|
||||
name += output->edid()->name() + QLatin1Char(' ');
|
||||
}
|
||||
if (!name.trimmed().isEmpty()) {
|
||||
return name + QLatin1Char('(') + output->name() + QLatin1Char(')');
|
||||
}
|
||||
}
|
||||
return output->name();
|
||||
}
|
||||
|
||||
QString Utils::sizeToString(const QSize &size)
|
||||
{
|
||||
return QStringLiteral("%1x%2").arg(size.width()).arg(size.height());
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2013 Daniel Vrátil <dvratil@redhat.com>
|
||||
*
|
||||
* 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) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KSCREEN_KCM_UTILS_H
|
||||
#define KSCREEN_KCM_UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QSize>
|
||||
|
||||
#include <kscreen/types.h>
|
||||
#include <kscreen/output.h>
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
|
||||
QString outputName(const KScreen::Output *output);
|
||||
QString outputName(const KScreen::OutputPtr &output);
|
||||
|
||||
QString sizeToString(const QSize &size);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,339 @@
|
||||
/********************************************************************
|
||||
Copyright © 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "confighandler.h"
|
||||
|
||||
#include "outputmodel.h"
|
||||
|
||||
#include <kscreen/configmonitor.h>
|
||||
#include <kscreen/getconfigoperation.h>
|
||||
#include <kscreen/output.h>
|
||||
|
||||
#include <QRect>
|
||||
|
||||
using namespace KScreen;
|
||||
|
||||
ConfigHandler::ConfigHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigHandler::setConfig(KScreen::ConfigPtr config)
|
||||
{
|
||||
m_config = config;
|
||||
m_initialConfig = m_config->clone();
|
||||
m_initialControl.reset(new ControlConfig(m_initialConfig));
|
||||
|
||||
KScreen::ConfigMonitor::instance()->addConfig(m_config);
|
||||
m_control.reset(new ControlConfig(config));
|
||||
|
||||
m_outputs = new OutputModel(this);
|
||||
connect(m_outputs, &OutputModel::positionChanged,
|
||||
this, &ConfigHandler::checkScreenNormalization);
|
||||
connect(m_outputs, &OutputModel::sizeChanged,
|
||||
this, &ConfigHandler::checkScreenNormalization);
|
||||
|
||||
for (const KScreen::OutputPtr &output : config->outputs()) {
|
||||
initOutput(output);
|
||||
}
|
||||
m_lastNormalizedScreenSize = screenSize();
|
||||
|
||||
// TODO: put this into m_initialControl
|
||||
m_initialRetention = getRetention();
|
||||
Q_EMIT retentionChanged();
|
||||
|
||||
connect(m_outputs, &OutputModel::changed,
|
||||
this, [this]() {
|
||||
checkNeedsSave();
|
||||
Q_EMIT changed();
|
||||
});
|
||||
connect(m_config.data(), &KScreen::Config::outputAdded,
|
||||
this, [this]() { Q_EMIT outputConnect(true); });
|
||||
connect(m_config.data(), &KScreen::Config::outputRemoved,
|
||||
this, [this]() { Q_EMIT outputConnect(false); });
|
||||
connect(m_config.data(), &KScreen::Config::primaryOutputChanged,
|
||||
this, &ConfigHandler::primaryOutputChanged);
|
||||
|
||||
Q_EMIT outputModelChanged();
|
||||
}
|
||||
|
||||
void ConfigHandler::resetScale(const KScreen::OutputPtr &output)
|
||||
{
|
||||
// Load scale control (either not set, same or windowing system does not transmit scale).
|
||||
const qreal scale = m_control->getScale(output);
|
||||
if (scale > 0) {
|
||||
output->setScale(scale);
|
||||
for (auto initialOutput : m_initialConfig->outputs()) {
|
||||
if (initialOutput->id() == output->id()) {
|
||||
initialOutput->setScale(scale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigHandler::initOutput(const KScreen::OutputPtr &output)
|
||||
{
|
||||
if (output->isConnected()) {
|
||||
resetScale(output);
|
||||
m_outputs->add(output);
|
||||
}
|
||||
connect(output.data(), &KScreen::Output::isConnectedChanged,
|
||||
this, [this, output]() {
|
||||
Q_EMIT outputConnect(output->isConnected());
|
||||
});
|
||||
}
|
||||
|
||||
void ConfigHandler::updateInitialData()
|
||||
{
|
||||
m_initialRetention = getRetention();
|
||||
connect(new GetConfigOperation(), &GetConfigOperation::finished,
|
||||
this, [this](ConfigOperation *op) {
|
||||
if (op->hasError()) {
|
||||
return;
|
||||
}
|
||||
m_initialConfig = qobject_cast<GetConfigOperation*>(op)->config();
|
||||
for (auto output : m_config->outputs()) {
|
||||
resetScale(output);
|
||||
}
|
||||
m_initialControl.reset(new ControlConfig(m_initialConfig));
|
||||
checkNeedsSave();
|
||||
});
|
||||
}
|
||||
|
||||
void ConfigHandler::checkNeedsSave()
|
||||
{
|
||||
if (m_config->supportedFeatures() &
|
||||
KScreen::Config::Feature::PrimaryDisplay) {
|
||||
if (m_config->primaryOutput() && m_initialConfig->primaryOutput()) {
|
||||
if (m_config->primaryOutput()->hashMd5() !=
|
||||
m_initialConfig->primaryOutput()->hashMd5() ) {
|
||||
Q_EMIT needsSaveChecked(true);
|
||||
return;
|
||||
}
|
||||
} else if ((bool)m_config->primaryOutput() != (bool)m_initialConfig->primaryOutput()) {
|
||||
Q_EMIT needsSaveChecked(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_initialRetention != getRetention()) {
|
||||
Q_EMIT needsSaveChecked(true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &output : m_config->connectedOutputs()) {
|
||||
const QString hash = output->hashMd5();
|
||||
for (const auto &initialOutput : m_initialConfig->outputs()) {
|
||||
if (hash != initialOutput->hashMd5()) {
|
||||
continue;
|
||||
}
|
||||
bool needsSave = false;
|
||||
if (output->isEnabled() != initialOutput->isEnabled()) {
|
||||
needsSave = true;
|
||||
}
|
||||
if (output->isEnabled()) {
|
||||
needsSave |= output->currentModeId() !=
|
||||
initialOutput->currentModeId()
|
||||
|| output->pos() != initialOutput->pos()
|
||||
|| output->scale() != initialOutput->scale()
|
||||
|| output->rotation() != initialOutput->rotation()
|
||||
|| output->replicationSource() != initialOutput->replicationSource()
|
||||
|| autoRotate(output) != m_initialControl->getAutoRotate(output)
|
||||
|| autoRotateOnlyInTabletMode(output)
|
||||
!= m_initialControl->getAutoRotateOnlyInTabletMode(output);
|
||||
}
|
||||
if (needsSave) {
|
||||
Q_EMIT needsSaveChecked(true);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Q_EMIT needsSaveChecked(false);
|
||||
}
|
||||
|
||||
QSize ConfigHandler::screenSize() const
|
||||
{
|
||||
int width = 0, height = 0;
|
||||
QSize size;
|
||||
|
||||
for (const auto &output : m_config->connectedOutputs()) {
|
||||
if (!output->isPositionable()) {
|
||||
continue;
|
||||
}
|
||||
const int outputRight = output->geometry().right();
|
||||
const int outputBottom = output->geometry().bottom();
|
||||
|
||||
if (outputRight > width) {
|
||||
width = outputRight;
|
||||
}
|
||||
if (outputBottom > height) {
|
||||
height = outputBottom;
|
||||
}
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
size = QSize(width, height);
|
||||
} else {
|
||||
size = QSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
QSize ConfigHandler::normalizeScreen()
|
||||
{
|
||||
if (!m_config) {
|
||||
return QSize();
|
||||
}
|
||||
bool changed = m_outputs->normalizePositions();
|
||||
|
||||
const auto currentScreenSize = screenSize();
|
||||
changed |= m_lastNormalizedScreenSize != currentScreenSize;
|
||||
m_lastNormalizedScreenSize = currentScreenSize;
|
||||
|
||||
Q_EMIT screenNormalizationUpdate(true);
|
||||
return currentScreenSize;
|
||||
}
|
||||
|
||||
void ConfigHandler::checkScreenNormalization()
|
||||
{
|
||||
const bool normalized = !m_config ||
|
||||
(m_lastNormalizedScreenSize == screenSize() &&
|
||||
m_outputs->positionsNormalized());
|
||||
|
||||
Q_EMIT screenNormalizationUpdate(normalized);
|
||||
}
|
||||
|
||||
void ConfigHandler::primaryOutputSelected(int index)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
// TODO
|
||||
}
|
||||
|
||||
void ConfigHandler::primaryOutputChanged(const KScreen::OutputPtr &output)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
}
|
||||
|
||||
Control::OutputRetention ConfigHandler::getRetention() const
|
||||
{
|
||||
using Retention = Control::OutputRetention;
|
||||
|
||||
auto ret = Retention::Undefined;
|
||||
if (!m_control) {
|
||||
return ret;
|
||||
}
|
||||
const auto outputs = m_config->connectedOutputs();
|
||||
if (outputs.isEmpty()) {
|
||||
return ret;
|
||||
}
|
||||
ret = m_control->getOutputRetention(outputs.first());
|
||||
|
||||
for (const auto &output : outputs) {
|
||||
const auto outputRet = m_control->getOutputRetention(output);
|
||||
if (ret != outputRet ) {
|
||||
// Control file with different retention values per output.
|
||||
return Retention::Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == Retention::Undefined) {
|
||||
// If all outputs have undefined retention,
|
||||
// this should be displayed as global retention.
|
||||
return Retention::Global;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ConfigHandler::retention() const
|
||||
{
|
||||
return static_cast<int>(getRetention());
|
||||
}
|
||||
|
||||
void ConfigHandler::setRetention(int retention)
|
||||
{
|
||||
using Retention = Control::OutputRetention;
|
||||
|
||||
if (!m_control) {
|
||||
return;
|
||||
}
|
||||
if (retention != static_cast<int>(Retention::Global) &&
|
||||
retention != static_cast<int>(Retention::Individual)) {
|
||||
// We only allow setting to global or individual retention.
|
||||
return;
|
||||
}
|
||||
if (retention == ConfigHandler::retention()) {
|
||||
return;
|
||||
}
|
||||
auto ret = static_cast<Retention>(retention);
|
||||
for (const auto &output : m_config->connectedOutputs()) {
|
||||
m_control->setOutputRetention(output, ret);
|
||||
}
|
||||
checkNeedsSave();
|
||||
Q_EMIT retentionChanged();
|
||||
Q_EMIT changed();
|
||||
}
|
||||
|
||||
qreal ConfigHandler::scale(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return m_control->getScale(output);
|
||||
}
|
||||
|
||||
void ConfigHandler::setScale(KScreen::OutputPtr &output, qreal scale)
|
||||
{
|
||||
m_control->setScale(output, scale);
|
||||
}
|
||||
|
||||
KScreen::OutputPtr ConfigHandler::replicationSource(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return m_control->getReplicationSource(output);
|
||||
}
|
||||
|
||||
void ConfigHandler::setReplicationSource(KScreen::OutputPtr &output,
|
||||
const KScreen::OutputPtr &source)
|
||||
{
|
||||
m_control->setReplicationSource(output, source);
|
||||
}
|
||||
|
||||
bool ConfigHandler::autoRotate(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return m_control->getAutoRotate(output);
|
||||
}
|
||||
|
||||
void ConfigHandler::setAutoRotate(KScreen::OutputPtr &output, bool autoRotate)
|
||||
{
|
||||
m_control->setAutoRotate(output, autoRotate);
|
||||
}
|
||||
|
||||
bool ConfigHandler::autoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
return m_control->getAutoRotateOnlyInTabletMode(output);
|
||||
}
|
||||
|
||||
void ConfigHandler::setAutoRotateOnlyInTabletMode(KScreen::OutputPtr &output, bool value)
|
||||
{
|
||||
m_control->setAutoRotateOnlyInTabletMode(output, value);
|
||||
}
|
||||
|
||||
void ConfigHandler::writeControl()
|
||||
{
|
||||
if (!m_control) {
|
||||
return;
|
||||
}
|
||||
m_control->writeFile();
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
/********************************************************************
|
||||
Copyright © 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "./common/control.h"
|
||||
|
||||
#include <kscreen/config.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class OutputModel;
|
||||
|
||||
class ConfigHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConfigHandler (QObject *parent = nullptr);
|
||||
~ConfigHandler() override = default;
|
||||
|
||||
void setConfig(KScreen::ConfigPtr config);
|
||||
void updateInitialData();
|
||||
|
||||
OutputModel* outputModel() const {
|
||||
return m_outputs;
|
||||
}
|
||||
|
||||
QSize normalizeScreen();
|
||||
|
||||
KScreen::ConfigPtr config() const {
|
||||
return m_config;
|
||||
}
|
||||
|
||||
KScreen::ConfigPtr initialConfig() const {
|
||||
return m_initialConfig;
|
||||
}
|
||||
|
||||
int retention() const;
|
||||
void setRetention(int retention);
|
||||
|
||||
qreal scale(const KScreen::OutputPtr &output) const;
|
||||
void setScale(KScreen::OutputPtr &output, qreal scale);
|
||||
|
||||
KScreen::OutputPtr replicationSource(const KScreen::OutputPtr &output) const;
|
||||
void setReplicationSource(KScreen::OutputPtr &output, const KScreen::OutputPtr &source);
|
||||
|
||||
bool autoRotate(const KScreen::OutputPtr &output) const;
|
||||
void setAutoRotate(KScreen::OutputPtr &output, bool autoRotate);
|
||||
bool autoRotateOnlyInTabletMode(const KScreen::OutputPtr &output) const;
|
||||
void setAutoRotateOnlyInTabletMode(KScreen::OutputPtr &output, bool value);
|
||||
|
||||
void writeControl();
|
||||
|
||||
void checkNeedsSave();
|
||||
|
||||
Q_SIGNALS:
|
||||
void outputModelChanged();
|
||||
void changed();
|
||||
void screenNormalizationUpdate(bool normalized);
|
||||
void needsSaveChecked(bool need);
|
||||
void retentionChanged();
|
||||
void outputConnect(bool connected);
|
||||
|
||||
private:
|
||||
void checkScreenNormalization();
|
||||
QSize screenSize() const;
|
||||
Control::OutputRetention getRetention() const;
|
||||
void primaryOutputSelected(int index);
|
||||
void primaryOutputChanged(const KScreen::OutputPtr &output);
|
||||
void initOutput(const KScreen::OutputPtr &output);
|
||||
void resetScale(const KScreen::OutputPtr &output);
|
||||
|
||||
KScreen::ConfigPtr m_config = nullptr;
|
||||
KScreen::ConfigPtr m_initialConfig;
|
||||
OutputModel *m_outputs = nullptr;
|
||||
|
||||
std::unique_ptr<ControlConfig> m_control;
|
||||
std::unique_ptr<ControlConfig> m_initialControl;
|
||||
Control::OutputRetention m_initialRetention = Control::OutputRetention::
|
||||
Undefined;
|
||||
QSize m_lastNormalizedScreenSize;
|
||||
};
|
||||
@ -0,0 +1,984 @@
|
||||
/********************************************************************
|
||||
Copyright © 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "outputmodel.h"
|
||||
|
||||
#include "./common/utils.h"
|
||||
|
||||
#include "confighandler.h"
|
||||
|
||||
#include <QRect>
|
||||
|
||||
OutputModel::OutputModel(ConfigHandler *configHandler)
|
||||
: QAbstractListModel(configHandler)
|
||||
, m_config(configHandler)
|
||||
{
|
||||
connect(this, &OutputModel::dataChanged, this, &OutputModel::changed);
|
||||
}
|
||||
|
||||
int OutputModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_outputs.count();
|
||||
}
|
||||
|
||||
QVariant OutputModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() < 0 || index.row() >= m_outputs.count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const KScreen::OutputPtr &output = m_outputs[index.row()].ptr;
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return Utils::outputName(output);
|
||||
case EnabledRole:
|
||||
return output->isEnabled();
|
||||
case InternalRole:
|
||||
return output->type() == KScreen::Output::Type::Panel;
|
||||
case PrimaryRole:
|
||||
return output->isPrimary();
|
||||
case SizeRole:
|
||||
return output->geometry().size();
|
||||
case PositionRole:
|
||||
return m_outputs[index.row()].pos;
|
||||
case NormalizedPositionRole:
|
||||
return output->geometry().topLeft();
|
||||
case AutoRotateRole:
|
||||
return m_config->autoRotate(output);
|
||||
case AutoRotateOnlyInTabletModeRole:
|
||||
return m_config->autoRotateOnlyInTabletMode(output);
|
||||
case RotationRole:
|
||||
return output->rotation();
|
||||
case ScaleRole:
|
||||
return output->scale();
|
||||
case ResolutionIndexRole:
|
||||
return resolutionIndex(output);
|
||||
case ResolutionsRole:
|
||||
return resolutionsStrings(output);
|
||||
case RefreshRateIndexRole:
|
||||
return refreshRateIndex(output);
|
||||
case ReplicationSourceModelRole:
|
||||
return replicationSourceModel(output);
|
||||
case ReplicationSourceIndexRole:
|
||||
return replicationSourceIndex(index.row());
|
||||
case ReplicasModelRole:
|
||||
return replicasModel(output);
|
||||
case RefreshRatesRole:
|
||||
QVariantList ret;
|
||||
for (const auto rate : refreshRates(output)) {
|
||||
ret << QString("%1 Hz").arg(int(rate + 0.5));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool OutputModel::setData(const QModelIndex &index,
|
||||
const QVariant &value, int role)
|
||||
{
|
||||
if (index.row() < 0 || index.row() >= m_outputs.count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Output &output = m_outputs[index.row()];
|
||||
switch (role) {
|
||||
case PositionRole:
|
||||
if (value.canConvert<QPoint>()) {
|
||||
QPoint val = value.toPoint();
|
||||
if (output.pos == val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
snap(output, val);
|
||||
m_outputs[index.row()].pos = val;
|
||||
updatePositions();
|
||||
Q_EMIT positionChanged();
|
||||
Q_EMIT dataChanged(index, index, {role});
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case EnabledRole:
|
||||
if (value.canConvert<bool>()) {
|
||||
return setEnabled(index.row(), value.toBool());
|
||||
}
|
||||
break;
|
||||
case PrimaryRole:
|
||||
if (value.canConvert<bool>()) {
|
||||
bool primary = value.toBool();
|
||||
if (output.ptr->isPrimary() == primary) {
|
||||
return false;
|
||||
}
|
||||
m_config->config()->setPrimaryOutput(output.ptr);
|
||||
Q_EMIT dataChanged(index, index, {role});
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ResolutionIndexRole:
|
||||
if (value.canConvert<int>()) {
|
||||
return setResolution(index.row(), value.toInt());
|
||||
}
|
||||
break;
|
||||
case RefreshRateIndexRole:
|
||||
if (value.canConvert<int>()) {
|
||||
return setRefreshRate(index.row(), value.toInt());
|
||||
}
|
||||
break;
|
||||
case AutoRotateRole:
|
||||
if (value.canConvert<bool>()) {
|
||||
return setAutoRotate(index.row(), value.value<bool>());
|
||||
}
|
||||
break;
|
||||
case AutoRotateOnlyInTabletModeRole:
|
||||
if (value.canConvert<bool>()) {
|
||||
return setAutoRotateOnlyInTabletMode(index.row(), value.value<bool>());
|
||||
}
|
||||
break;
|
||||
case RotationRole:
|
||||
if (value.canConvert<KScreen::Output::Rotation>()) {
|
||||
return setRotation(index.row(),
|
||||
value.value<KScreen::Output::Rotation>());
|
||||
}
|
||||
break;
|
||||
case ReplicationSourceIndexRole:
|
||||
if (value.canConvert<int>()) {
|
||||
return setReplicationSourceIndex(index.row(), value.toInt() - 1);
|
||||
}
|
||||
break;
|
||||
case ScaleRole:
|
||||
bool ok;
|
||||
const qreal scale = value.toReal(&ok);
|
||||
if (ok && !qFuzzyCompare(output.ptr->scale(), scale)) {
|
||||
output.ptr->setScale(scale);
|
||||
m_config->setScale(output.ptr, scale);
|
||||
Q_EMIT sizeChanged();
|
||||
Q_EMIT dataChanged(index, index, {role, SizeRole});
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> OutputModel::roleNames() const {
|
||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[EnabledRole] = "enabled";
|
||||
roles[InternalRole] = "internal";
|
||||
roles[PrimaryRole] = "primary";
|
||||
roles[SizeRole] = "size";
|
||||
roles[PositionRole] = "position";
|
||||
roles[NormalizedPositionRole] = "normalizedPosition";
|
||||
roles[AutoRotateRole] = "autoRotate";
|
||||
roles[AutoRotateOnlyInTabletModeRole] = "autoRotateOnlyInTabletMode";
|
||||
roles[RotationRole] = "rotation";
|
||||
roles[ScaleRole] = "scale";
|
||||
roles[ResolutionIndexRole] = "resolutionIndex";
|
||||
roles[ResolutionsRole] = "resolutions";
|
||||
roles[RefreshRateIndexRole] = "refreshRateIndex";
|
||||
roles[RefreshRatesRole] = "refreshRates";
|
||||
roles[ReplicationSourceModelRole] = "replicationSourceModel";
|
||||
roles[ReplicationSourceIndexRole] = "replicationSourceIndex";
|
||||
roles[ReplicasModelRole] = "replicasModel";
|
||||
return roles;
|
||||
}
|
||||
|
||||
void OutputModel::add(const KScreen::OutputPtr &output)
|
||||
{
|
||||
const int insertPos = m_outputs.count();
|
||||
Q_EMIT beginInsertRows(QModelIndex(), insertPos, insertPos);
|
||||
|
||||
int i = 0;
|
||||
while (i < m_outputs.size()) {
|
||||
const QPoint pos = m_outputs[i].ptr->pos();
|
||||
if (output->pos().x() < pos.x()) {
|
||||
break;
|
||||
}
|
||||
if (output->pos().x() == pos.x() &&
|
||||
output->pos().y() < pos.y()) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// Set the initial non-normalized position to be the normalized
|
||||
// position plus the current delta.
|
||||
QPoint pos = output->pos();
|
||||
if (!m_outputs.isEmpty()) {
|
||||
const QPoint delta = m_outputs[0].pos - m_outputs[0].ptr->pos();
|
||||
pos = output->pos() + delta;
|
||||
}
|
||||
m_outputs.insert(i, Output(output, pos));
|
||||
|
||||
connect(output.data(), &KScreen::Output::isPrimaryChanged,
|
||||
this, [this, output](){
|
||||
roleChanged(output->id(), PrimaryRole);
|
||||
});
|
||||
Q_EMIT endInsertRows();
|
||||
|
||||
// Update replications.
|
||||
for (int j = 0; j < m_outputs.size(); j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
QModelIndex index = createIndex(j, 0);
|
||||
// Calling this directly ignores possible optimization when the
|
||||
// refresh rate hasn't changed in fact. But that's ok.
|
||||
Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole,
|
||||
ReplicationSourceIndexRole});
|
||||
}
|
||||
}
|
||||
|
||||
void OutputModel::remove(int outputId)
|
||||
{
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
||||
[outputId](const Output &output) {
|
||||
return output.ptr->id() == outputId;
|
||||
});
|
||||
if (it != m_outputs.end()) {
|
||||
const int index = it - m_outputs.begin();
|
||||
Q_EMIT beginRemoveRows(QModelIndex(), index, index);
|
||||
m_outputs.erase(it);
|
||||
Q_EMIT endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
void OutputModel::resetPosition(const Output &output)
|
||||
{
|
||||
if (output.posReset.x() < 0) {
|
||||
// KCM was closed in between.
|
||||
for (const Output &out : m_outputs) {
|
||||
if (out.ptr->id() == output.ptr->id()) {
|
||||
continue;
|
||||
}
|
||||
if (out.ptr->geometry().right() > output.ptr->pos().x()) {
|
||||
output.ptr->setPos(out.ptr->geometry().topRight());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
output.ptr->setPos(/*output.ptr->pos() - */output.posReset);
|
||||
}
|
||||
}
|
||||
|
||||
bool OutputModel::setEnabled(int outputIndex, bool enable)
|
||||
{
|
||||
Output &output = m_outputs[outputIndex];
|
||||
|
||||
if (output.ptr->isEnabled() == enable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
output.ptr->setEnabled(enable);
|
||||
|
||||
if (enable) {
|
||||
resetPosition(output);
|
||||
|
||||
setResolution(outputIndex, resolutionIndex(output.ptr));
|
||||
reposition();
|
||||
} else {
|
||||
output.posReset = output.ptr->pos();
|
||||
}
|
||||
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {EnabledRole});
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool refreshRateCompare(float rate1, float rate2)
|
||||
{
|
||||
return qAbs(rate1 - rate2) < 0.5;
|
||||
}
|
||||
|
||||
bool OutputModel::setResolution(int outputIndex, int resIndex)
|
||||
{
|
||||
const Output &output = m_outputs[outputIndex];
|
||||
const auto resolutionList = resolutions(output.ptr);
|
||||
if (resIndex < 0 || resIndex >= resolutionList.size()) {
|
||||
return false;
|
||||
}
|
||||
const QSize size = resolutionList[resIndex];
|
||||
|
||||
const float oldRate = output.ptr->currentMode() ? output.ptr->currentMode()->refreshRate() :
|
||||
-1;
|
||||
const auto modes = output.ptr->modes();
|
||||
|
||||
auto modeIt = std::find_if(modes.begin(), modes.end(),
|
||||
[size, oldRate](const KScreen::ModePtr &mode) {
|
||||
// TODO: we don't want to compare against old refresh rate if
|
||||
// refresh rate selection is auto.
|
||||
return mode->size() == size &&
|
||||
refreshRateCompare(mode->refreshRate(), oldRate);
|
||||
});
|
||||
|
||||
if (modeIt == modes.end()) {
|
||||
// New resolution does not support previous refresh rate.
|
||||
// Get the highest one instead.
|
||||
float bestRefreshRate = 0;
|
||||
auto it = modes.begin();
|
||||
while (it != modes.end()) {
|
||||
if ((*it)->size() == size && (*it)->refreshRate() > bestRefreshRate) {
|
||||
modeIt = it;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
Q_ASSERT(modeIt != modes.end());
|
||||
|
||||
const auto id = (*modeIt)->id();
|
||||
if (output.ptr->currentModeId() == id) {
|
||||
return false;
|
||||
}
|
||||
output.ptr->setCurrentModeId(id);
|
||||
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
// Calling this directly ignores possible optimization when the
|
||||
// refresh rate hasn't changed in fact. But that's ok.
|
||||
Q_EMIT dataChanged(index, index, {ResolutionIndexRole,
|
||||
SizeRole,
|
||||
RefreshRateIndexRole});
|
||||
Q_EMIT sizeChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OutputModel::setRefreshRate(int outputIndex, int refIndex)
|
||||
{
|
||||
const Output &output = m_outputs[outputIndex];
|
||||
const auto rates = refreshRates(output.ptr);
|
||||
if (refIndex < 0 || refIndex >= rates.size()) {
|
||||
return false;
|
||||
}
|
||||
const float refreshRate = rates[refIndex];
|
||||
|
||||
const auto modes = output.ptr->modes();
|
||||
const auto oldMode = output.ptr->currentMode();
|
||||
|
||||
auto modeIt = std::find_if(modes.begin(), modes.end(),
|
||||
[oldMode, refreshRate](const KScreen::ModePtr &mode) {
|
||||
// TODO: we don't want to compare against old refresh rate if
|
||||
// refresh rate selection is auto.
|
||||
return mode->size() == oldMode->size() &&
|
||||
refreshRateCompare(mode->refreshRate(), refreshRate);
|
||||
});
|
||||
Q_ASSERT(modeIt != modes.end());
|
||||
|
||||
if (refreshRateCompare(oldMode->refreshRate(), (*modeIt)->refreshRate())) {
|
||||
// no change
|
||||
return false;
|
||||
}
|
||||
output.ptr->setCurrentModeId((*modeIt)->id());
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {RefreshRateIndexRole});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OutputModel::setAutoRotate(int outputIndex, bool value)
|
||||
{
|
||||
Output &output = m_outputs[outputIndex];
|
||||
|
||||
if (m_config->autoRotate(output.ptr) == value) {
|
||||
return false;
|
||||
}
|
||||
m_config->setAutoRotate(output.ptr, value);
|
||||
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {AutoRotateRole});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OutputModel::setAutoRotateOnlyInTabletMode(int outputIndex, bool value)
|
||||
{
|
||||
Output &output = m_outputs[outputIndex];
|
||||
|
||||
if (m_config->autoRotateOnlyInTabletMode(output.ptr) == value) {
|
||||
return false;
|
||||
}
|
||||
m_config->setAutoRotateOnlyInTabletMode(output.ptr, value);
|
||||
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {AutoRotateOnlyInTabletModeRole});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OutputModel::setRotation(int outputIndex, KScreen::Output::Rotation rotation)
|
||||
{
|
||||
const Output &output = m_outputs[outputIndex];
|
||||
|
||||
if (rotation != KScreen::Output::None
|
||||
&& rotation != KScreen::Output::Left
|
||||
&& rotation != KScreen::Output::Inverted
|
||||
&& rotation != KScreen::Output::Right) {
|
||||
return false;
|
||||
}
|
||||
if (output.ptr->rotation() == rotation) {
|
||||
return false;
|
||||
}
|
||||
output.ptr->setRotation(rotation);
|
||||
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {RotationRole, SizeRole});
|
||||
Q_EMIT sizeChanged();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
int OutputModel::resolutionIndex(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
const QSize currentResolution = output->enforcedModeSize();
|
||||
|
||||
if (!currentResolution.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto sizes = resolutions(output);
|
||||
|
||||
const auto it = std::find_if(sizes.begin(),
|
||||
sizes.end(),
|
||||
[currentResolution](const QSize &size) {
|
||||
return size == currentResolution;
|
||||
});
|
||||
if (it == sizes.end()) {
|
||||
return -1;
|
||||
}
|
||||
return it - sizes.begin();
|
||||
}
|
||||
|
||||
int OutputModel::refreshRateIndex(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
if (!output->currentMode()) {
|
||||
return 0;
|
||||
}
|
||||
const auto rates = refreshRates(output);
|
||||
const float currentRate = output->currentMode()->refreshRate();
|
||||
|
||||
const auto it = std::find_if(rates.begin(),
|
||||
rates.end(),
|
||||
[currentRate](float rate) {
|
||||
return refreshRateCompare(rate, currentRate);
|
||||
});
|
||||
if (it == rates.end()) {
|
||||
return 0;
|
||||
}
|
||||
return it - rates.begin();
|
||||
}
|
||||
|
||||
static int greatestCommonDivisor(int a, int b) {
|
||||
if (b == 0) {
|
||||
return a;
|
||||
}
|
||||
return greatestCommonDivisor(b, a % b);
|
||||
}
|
||||
|
||||
QVariantList OutputModel::resolutionsStrings(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
QVariantList ret;
|
||||
for (const QSize &size : resolutions(output)) {
|
||||
int divisor = greatestCommonDivisor(size.width(), size.height());
|
||||
|
||||
// Prefer "16:10" over "8:5"
|
||||
if (size.height() / divisor == 5) {
|
||||
divisor /= 2;
|
||||
}
|
||||
|
||||
const QString text;
|
||||
|
||||
// const QString text = i18nc("Width x height (aspect ratio)", "%1x%2 (%3:%4)",
|
||||
// // Explicitly not have it add thousand-separators.
|
||||
// QString::number(size.width()),
|
||||
// QString::number(size.height()),
|
||||
// size.width() / divisor,
|
||||
// size.height() / divisor);
|
||||
|
||||
ret << text;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<QSize> OutputModel::resolutions(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
QVector<QSize> hits;
|
||||
|
||||
for (const auto &mode : output->modes()) {
|
||||
const QSize size = mode->size();
|
||||
if (!hits.contains(size)) {
|
||||
hits << size;
|
||||
}
|
||||
}
|
||||
std::sort(hits.begin(), hits.end(), [](const QSize &a, const QSize &b) {
|
||||
if (a.width() > b.width()) {
|
||||
return true;
|
||||
}
|
||||
if (a.width() == b.width() && a.height() > b.height()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return hits;
|
||||
}
|
||||
|
||||
QVector<float> OutputModel::refreshRates(const KScreen::OutputPtr
|
||||
&output) const
|
||||
{
|
||||
QVector<float> hits;
|
||||
|
||||
QSize baseSize;
|
||||
if (output->currentMode()) {
|
||||
baseSize = output->currentMode()->size();
|
||||
} else if (output->preferredMode()) {
|
||||
baseSize = output->preferredMode()->size();
|
||||
}
|
||||
if (!baseSize.isValid()) {
|
||||
return hits;
|
||||
}
|
||||
|
||||
for (const auto &mode : output->modes()) {
|
||||
if (mode->size() != baseSize) {
|
||||
continue;
|
||||
}
|
||||
const float rate = mode->refreshRate();
|
||||
if (std::find_if(hits.begin(), hits.end(),
|
||||
[rate](float r) {
|
||||
return refreshRateCompare(r, rate);
|
||||
}) != hits.end()) {
|
||||
continue;
|
||||
}
|
||||
hits << rate;
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
int OutputModel::replicationSourceId(const Output &output) const
|
||||
{
|
||||
const KScreen::OutputPtr source = m_config->replicationSource(output.ptr);
|
||||
if (!source) {
|
||||
return 0;
|
||||
}
|
||||
return source->id();
|
||||
}
|
||||
|
||||
QStringList OutputModel::replicationSourceModel(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
QStringList ret = { QObject::tr("None") };
|
||||
|
||||
for (const auto &out : m_outputs) {
|
||||
if (out.ptr->id() != output->id()) {
|
||||
const int outSourceId = replicationSourceId(out);
|
||||
if (outSourceId == output->id()) {
|
||||
// 'output' is already source for replication, can't be replica itself
|
||||
return { QObject::tr("Replicated by other output") };
|
||||
}
|
||||
if (outSourceId) {
|
||||
// This 'out' is a replica. Can't be a replication source.
|
||||
continue;
|
||||
}
|
||||
ret.append(Utils::outputName(out.ptr));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool OutputModel::setReplicationSourceIndex(int outputIndex, int sourceIndex)
|
||||
{
|
||||
if (outputIndex <= sourceIndex) {
|
||||
sourceIndex++;
|
||||
}
|
||||
if (sourceIndex >= m_outputs.count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Output &output = m_outputs[outputIndex];
|
||||
const int oldSourceId = replicationSourceId(output);
|
||||
|
||||
if (sourceIndex < 0) {
|
||||
if (oldSourceId == 0) {
|
||||
// no change
|
||||
return false;
|
||||
}
|
||||
m_config->setReplicationSource(output.ptr, nullptr);
|
||||
output.ptr->setLogicalSize(QSizeF());
|
||||
resetPosition(output);
|
||||
} else {
|
||||
const auto source = m_outputs[sourceIndex].ptr;
|
||||
if (oldSourceId == source->id()) {
|
||||
// no change
|
||||
return false;
|
||||
}
|
||||
m_config->setReplicationSource(output.ptr, source);
|
||||
output.posReset = output.ptr->pos();
|
||||
output.ptr->setPos(source->pos());
|
||||
output.ptr->setLogicalSize(source->logicalSize());
|
||||
}
|
||||
|
||||
reposition();
|
||||
|
||||
QModelIndex index = createIndex(outputIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {ReplicationSourceIndexRole});
|
||||
|
||||
if (oldSourceId != 0) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
||||
[oldSourceId](const Output &out) {
|
||||
return out.ptr->id() == oldSourceId;
|
||||
});
|
||||
if (it != m_outputs.end()) {
|
||||
QModelIndex index = createIndex(it - m_outputs.begin(), 0);
|
||||
Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicasModelRole});
|
||||
}
|
||||
}
|
||||
if (sourceIndex >= 0) {
|
||||
QModelIndex index = createIndex(sourceIndex, 0);
|
||||
Q_EMIT dataChanged(index, index, {ReplicationSourceModelRole, ReplicasModelRole});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int OutputModel::replicationSourceIndex(int outputIndex) const
|
||||
{
|
||||
const int sourceId = replicationSourceId(m_outputs[outputIndex]);
|
||||
if (!sourceId) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
const Output &output = m_outputs[i];
|
||||
if (output.ptr->id() == sourceId) {
|
||||
return i + (outputIndex > i ? 1 : 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QVariantList OutputModel::replicasModel(const KScreen::OutputPtr &output) const
|
||||
{
|
||||
QVariantList ret;
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
const Output &out = m_outputs[i];
|
||||
if (out.ptr->id() != output->id()) {
|
||||
if (replicationSourceId(out) == output->id()) {
|
||||
ret << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OutputModel::roleChanged(int outputId, OutputRoles role)
|
||||
{
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
Output &output = m_outputs[i];
|
||||
if (output.ptr->id() == outputId) {
|
||||
QModelIndex index = createIndex(i, 0);
|
||||
Q_EMIT dataChanged(index, index, {role});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OutputModel::positionable(const Output &output) const
|
||||
{
|
||||
return output.ptr->isPositionable();
|
||||
}
|
||||
|
||||
void OutputModel::reposition()
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
// Find first valid output.
|
||||
for (const auto &out : m_outputs) {
|
||||
if (positionable(out)) {
|
||||
x = out.ptr->pos().x();
|
||||
y = out.ptr->pos().y();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
if (!positionable(m_outputs[i])) {
|
||||
continue;
|
||||
}
|
||||
const QPoint &cmp = m_outputs[i].ptr->pos();
|
||||
|
||||
if (cmp.x() < x) {
|
||||
x = cmp.x();
|
||||
}
|
||||
if (cmp.y() < y) {
|
||||
y = cmp.y();
|
||||
}
|
||||
}
|
||||
|
||||
if (x == 0 && y == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
auto &out = m_outputs[i];
|
||||
out.ptr->setPos(out.ptr->pos() - QPoint(x, y));
|
||||
QModelIndex index = createIndex(i, 0);
|
||||
Q_EMIT dataChanged(index, index, {NormalizedPositionRole});
|
||||
}
|
||||
m_config->normalizeScreen();
|
||||
}
|
||||
|
||||
QPoint OutputModel::originDelta() const
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
// Find first valid output.
|
||||
for (const auto &out : m_outputs) {
|
||||
if (positionable(out)) {
|
||||
x = out.pos.x();
|
||||
y = out.pos.y();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < m_outputs.size(); i++) {
|
||||
if (!positionable(m_outputs[i])) {
|
||||
continue;
|
||||
}
|
||||
const QPoint &cmp = m_outputs[i].pos;
|
||||
|
||||
if (cmp.x() < x) {
|
||||
x = cmp.x();
|
||||
}
|
||||
if (cmp.y() < y) {
|
||||
y = cmp.y();
|
||||
}
|
||||
}
|
||||
return QPoint(x, y);
|
||||
}
|
||||
|
||||
void OutputModel::updatePositions()
|
||||
{
|
||||
const QPoint delta = originDelta();
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
const auto &out = m_outputs[i];
|
||||
if (!positionable(out)) {
|
||||
continue;
|
||||
}
|
||||
const QPoint set = out.pos - delta;
|
||||
if (out.ptr->pos() != set) {
|
||||
out.ptr->setPos(set);
|
||||
QModelIndex index = createIndex(i, 0);
|
||||
Q_EMIT dataChanged(index, index, {NormalizedPositionRole});
|
||||
}
|
||||
}
|
||||
updateOrder();
|
||||
}
|
||||
|
||||
void OutputModel::updateOrder()
|
||||
{
|
||||
auto order = m_outputs;
|
||||
std::sort(order.begin(), order.end(), [](const Output &a, const Output &b) {
|
||||
const int xDiff = b.ptr->pos().x() - a.ptr->pos().x();
|
||||
const int yDiff = b.ptr->pos().y() - a.ptr->pos().y();
|
||||
if (xDiff > 0) {
|
||||
return true;
|
||||
}
|
||||
if (xDiff == 0 && yDiff > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
for (int i = 0; i < order.size(); i++) {
|
||||
for (int j = 0; j < m_outputs.size(); j++) {
|
||||
if (order[i].ptr->id() != m_outputs[j].ptr->id()) {
|
||||
continue;
|
||||
}
|
||||
if (i != j) {
|
||||
beginMoveRows(QModelIndex(), j, j, QModelIndex(), i);
|
||||
m_outputs.remove(j);
|
||||
m_outputs.insert(i, order[i]);
|
||||
endMoveRows();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Could this be optimized by only outputs updating where replica indices changed?
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
QModelIndex index = createIndex(i, 0);
|
||||
Q_EMIT dataChanged(index, index, { ReplicasModelRole });
|
||||
}
|
||||
}
|
||||
|
||||
bool OutputModel::normalizePositions()
|
||||
{
|
||||
bool changed = false;
|
||||
for (int i = 0; i < m_outputs.size(); i++) {
|
||||
auto &output = m_outputs[i];
|
||||
if (output.pos == output.ptr->pos()) {
|
||||
continue;
|
||||
}
|
||||
if (!positionable(output)) {
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
auto index = createIndex(i, 0);
|
||||
output.pos = output.ptr->pos();
|
||||
Q_EMIT dataChanged(index, index, {PositionRole});
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool OutputModel::positionsNormalized() const
|
||||
{
|
||||
// There might be slight deviations because of snapping.
|
||||
return originDelta().manhattanLength() < 5;
|
||||
}
|
||||
|
||||
const int s_snapArea = 80;
|
||||
|
||||
bool isVerticalClose(const QRect &rect1, const QRect &rect2)
|
||||
{
|
||||
if (rect2.top() - rect1.bottom() > s_snapArea ) {
|
||||
return false;
|
||||
}
|
||||
if (rect1.top() - rect2.bottom() > s_snapArea ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool snapToRight(const QRect &target,
|
||||
const QSize &size,
|
||||
QPoint &dest)
|
||||
{
|
||||
if (qAbs(target.right() - dest.x()) < s_snapArea) {
|
||||
// In snap zone for left to right snap.
|
||||
dest.setX(target.right() + 1);
|
||||
return true;
|
||||
}
|
||||
if (qAbs(target.right() - (dest.x() + size.width())) < s_snapArea) {
|
||||
// In snap zone for right to right snap.
|
||||
dest.setX(target.right() - size.width());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool snapToLeft(const QRect &target,
|
||||
const QSize &size,
|
||||
QPoint &dest)
|
||||
{
|
||||
if (qAbs(target.left() - dest.x()) < s_snapArea) {
|
||||
// In snap zone for left to left snap.
|
||||
dest.setX(target.left());
|
||||
return true;
|
||||
}
|
||||
if (qAbs(target.left() - (dest.x() + size.width())) < s_snapArea) {
|
||||
// In snap zone for right to left snap.
|
||||
dest.setX(target.left() - size.width());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool snapToMiddle(const QRect &target,
|
||||
const QSize &size,
|
||||
QPoint &dest)
|
||||
{
|
||||
const int outputMid = dest.y() + size.height() / 2;
|
||||
const int targetMid = target.top() + target.height() / 2;
|
||||
if (qAbs(targetMid - outputMid) < s_snapArea) {
|
||||
// In snap zone for middle to middle snap.
|
||||
dest.setY(targetMid - size.height() / 2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool snapToTop(const QRect &target,
|
||||
const QSize &size,
|
||||
QPoint &dest)
|
||||
{
|
||||
if (qAbs(target.top() - dest.y()) < s_snapArea) {
|
||||
// In snap zone for bottom to top snap.
|
||||
dest.setY(target.top());
|
||||
return true;
|
||||
}
|
||||
if (qAbs(target.top() - (dest.y() + size.height())) < s_snapArea) {
|
||||
// In snap zone for top to top snap.
|
||||
dest.setY(target.top() - size.height());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool snapToBottom(const QRect &target,
|
||||
const QSize &size,
|
||||
QPoint &dest)
|
||||
{
|
||||
if (qAbs(target.bottom() - dest.y()) < s_snapArea) {
|
||||
// In snap zone for top to bottom snap.
|
||||
dest.setY(target.bottom() + 1);
|
||||
return true;
|
||||
}
|
||||
if (qAbs(target.bottom() - (dest.y() + size.height())) < s_snapArea) {
|
||||
// In snap zone for bottom to bottom snap.
|
||||
dest.setY(target.bottom() - size.height() + 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool snapVertical(const QRect &target,
|
||||
const QSize &size,
|
||||
QPoint &dest)
|
||||
{
|
||||
if (snapToMiddle(target, size, dest)) {
|
||||
return true;
|
||||
}
|
||||
if (snapToBottom(target, size, dest)) {
|
||||
return true;
|
||||
}
|
||||
if (snapToTop(target, size, dest)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void OutputModel::snap(const Output &output, QPoint &dest)
|
||||
{
|
||||
const QSize size = output.ptr->geometry().size();
|
||||
for (const Output &out : m_outputs) {
|
||||
if (out.ptr->id() == output.ptr->id()) {
|
||||
// Can not snap to itself.
|
||||
continue;
|
||||
}
|
||||
if (!positionable(out)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QRect target(out.pos, out.ptr->geometry().size());
|
||||
|
||||
if (!isVerticalClose(target, QRect(dest, size))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// try snap left to right first
|
||||
if (snapToRight(target, size, dest)) {
|
||||
snapVertical(target, size, dest);
|
||||
continue;
|
||||
}
|
||||
if (snapToLeft(target, size, dest)) {
|
||||
snapVertical(target, size, dest);
|
||||
continue;
|
||||
}
|
||||
if (snapVertical(target, size, dest)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,150 @@
|
||||
/********************************************************************
|
||||
Copyright © 2019 Roman Gilg <subdiff@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <kscreen/config.h>
|
||||
#include <kscreen/output.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QPoint>
|
||||
|
||||
class ConfigHandler;
|
||||
|
||||
class OutputModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum OutputRoles {
|
||||
EnabledRole = Qt::UserRole + 1,
|
||||
InternalRole,
|
||||
PrimaryRole,
|
||||
SizeRole,
|
||||
/** Position in the graphical view relative to some arbitrary but fixed origin. */
|
||||
PositionRole,
|
||||
/** Position for backend relative to most northwest display corner. */
|
||||
NormalizedPositionRole,
|
||||
AutoRotateRole,
|
||||
AutoRotateOnlyInTabletModeRole,
|
||||
RotationRole,
|
||||
ScaleRole,
|
||||
ResolutionIndexRole,
|
||||
ResolutionsRole,
|
||||
RefreshRateIndexRole,
|
||||
RefreshRatesRole,
|
||||
ReplicationSourceModelRole,
|
||||
ReplicationSourceIndexRole,
|
||||
ReplicasModelRole
|
||||
};
|
||||
|
||||
explicit OutputModel(ConfigHandler *configHandler);
|
||||
~OutputModel() override = default;
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex &index,
|
||||
const QVariant &value,
|
||||
int role = Qt::EditRole) override;
|
||||
|
||||
void add(const KScreen::OutputPtr &output);
|
||||
void remove(int outputId);
|
||||
|
||||
/**
|
||||
* Resets the origin for calculation of positions to the most northwest display corner
|
||||
* while keeping the normalized positions untouched.
|
||||
*
|
||||
* @return true if some (unnormalized) output position changed on this call, otherwise false.
|
||||
*/
|
||||
bool normalizePositions();
|
||||
bool positionsNormalized() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void positionChanged();
|
||||
void sizeChanged();
|
||||
void changed();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
struct Output {
|
||||
Output() {}
|
||||
Output(const Output &output)
|
||||
: ptr(output.ptr)
|
||||
, pos(output.pos)
|
||||
{}
|
||||
Output(Output &&) noexcept = default;
|
||||
Output(KScreen::OutputPtr _ptr, const QPoint &_pos)
|
||||
: ptr(_ptr)
|
||||
, pos(_pos)
|
||||
{}
|
||||
Output &operator=(const Output &output) {
|
||||
ptr = output.ptr;
|
||||
pos = output.pos;
|
||||
posReset = QPoint(-1, -1);
|
||||
return *this;
|
||||
}
|
||||
Output &operator=(Output &&) noexcept = default;
|
||||
|
||||
KScreen::OutputPtr ptr;
|
||||
QPoint pos;
|
||||
QPoint posReset = QPoint(-1, -1);
|
||||
};
|
||||
|
||||
void roleChanged(int outputId, OutputRoles role);
|
||||
|
||||
void resetPosition(const Output &output);
|
||||
void reposition();
|
||||
void updatePositions();
|
||||
void updateOrder();
|
||||
QPoint originDelta() const;
|
||||
|
||||
/**
|
||||
* @brief Snaps moved output to others
|
||||
* @param output the moved output
|
||||
* @param dest the desired destination to be adjusted by snapping
|
||||
*/
|
||||
void snap(const Output &output, QPoint &dest);
|
||||
|
||||
bool setEnabled(int outputIndex, bool enable);
|
||||
|
||||
bool setResolution(int outputIndex, int resIndex);
|
||||
bool setRefreshRate(int outputIndex, int refIndex);
|
||||
bool setRotation(int outputIndex, KScreen::Output::Rotation rotation);
|
||||
bool setAutoRotate(int outputIndex, bool value);
|
||||
bool setAutoRotateOnlyInTabletMode(int outputIndex, bool value);
|
||||
|
||||
int resolutionIndex(const KScreen::OutputPtr &output) const;
|
||||
int refreshRateIndex(const KScreen::OutputPtr &output) const;
|
||||
QVariantList resolutionsStrings(const KScreen::OutputPtr &output) const;
|
||||
QVector<QSize> resolutions(const KScreen::OutputPtr &output) const;
|
||||
QVector<float> refreshRates(const KScreen::OutputPtr &output) const;
|
||||
|
||||
bool positionable(const Output &output) const;
|
||||
|
||||
QStringList replicationSourceModel(const KScreen::OutputPtr &output) const;
|
||||
bool setReplicationSourceIndex(int outputIndex, int sourceIndex);
|
||||
int replicationSourceIndex(int outputIndex) const;
|
||||
int replicationSourceId(const Output &output) const;
|
||||
|
||||
QVariantList replicasModel(const KScreen::OutputPtr &output) const;
|
||||
|
||||
QVector<Output> m_outputs;
|
||||
|
||||
ConfigHandler *m_config;
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
#include <QQmlExtensionPlugin>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "outputmodel.h"
|
||||
#include "screen.h"
|
||||
|
||||
class QmlPlugins : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
|
||||
|
||||
public:
|
||||
void registerTypes(const char * uri) override {
|
||||
// qmlRegisterType<OutputModel>(uri, 1, 0, "Screen");
|
||||
qmlRegisterType<Screen>(uri, 1, 0, "Screen");
|
||||
qmlRegisterType<KScreen::Output>(uri, 1, 0, "Output");
|
||||
}
|
||||
};
|
||||
|
||||
#include "plugin.moc"
|
||||
@ -0,0 +1,3 @@
|
||||
module Cutefish.Screen
|
||||
|
||||
plugin cutefishscreen_qmlplugins
|
||||
@ -0,0 +1,52 @@
|
||||
#include "screen.h"
|
||||
#include "outputmodel.h"
|
||||
|
||||
#include <QQmlExtensionPlugin>
|
||||
#include <QQmlEngine>
|
||||
|
||||
Screen::Screen(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
qmlRegisterType<OutputModel>();
|
||||
load();
|
||||
}
|
||||
|
||||
void Screen::load()
|
||||
{
|
||||
// Don't pull away the outputModel under QML's feet
|
||||
// signal its disappearance first before deleting and replacing it.
|
||||
// We take the m_config pointer so outputModel() will return null,
|
||||
// gracefully cleaning up the QML side and only then we will delete it.
|
||||
auto *oldConfig = m_config.release();
|
||||
if (oldConfig) {
|
||||
emit outputModelChanged();
|
||||
delete oldConfig;
|
||||
}
|
||||
|
||||
m_config.reset(new ConfigHandler(this));
|
||||
connect(m_config.get(), &ConfigHandler::outputModelChanged, this, &Screen::outputModelChanged);
|
||||
|
||||
connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, &Screen::configReady);
|
||||
}
|
||||
|
||||
OutputModel *Screen::outputModel() const
|
||||
{
|
||||
if (!m_config) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_config->outputModel();
|
||||
}
|
||||
|
||||
void Screen::configReady(KScreen::ConfigOperation *op)
|
||||
{
|
||||
if (op->hasError()) {
|
||||
m_config.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
KScreen::ConfigPtr config = qobject_cast<KScreen::GetConfigOperation *>(op)->config();
|
||||
const bool autoRotationSupported = config->supportedFeatures() & (KScreen::Config::Feature::AutoRotation | KScreen::Config::Feature::TabletMode);
|
||||
|
||||
m_config->setConfig(config);
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
#include <kscreen/getconfigoperation.h>
|
||||
|
||||
#include "confighandler.h"
|
||||
#include "outputmodel.h"
|
||||
|
||||
class ConfigHandler;
|
||||
class OutputModel;
|
||||
class Screen : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(OutputModel *outputModel READ outputModel NOTIFY outputModelChanged)
|
||||
|
||||
public:
|
||||
explicit Screen(QObject *parent = nullptr);
|
||||
|
||||
OutputModel *outputModel() const;
|
||||
|
||||
void load();
|
||||
|
||||
private:
|
||||
void configReady(KScreen::ConfigOperation *op);
|
||||
|
||||
Q_SIGNALS:
|
||||
void outputModelChanged();
|
||||
|
||||
private:
|
||||
std::unique_ptr<ConfigHandler> m_config;
|
||||
};
|
||||
Loading…
Reference in New Issue