mirror of https://github.com/cutefishos/core
init
commit
5273c3c9a0
@ -0,0 +1,55 @@
|
||||
# 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/*
|
||||
.vscode/*
|
||||
@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(system)
|
||||
|
||||
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)
|
||||
|
||||
set(QT Core Gui Widgets Quick QuickControls2 DBus X11Extras LinguistTools)
|
||||
find_package(Qt5 REQUIRED ${QT})
|
||||
find_package(MeuiKit REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(ECM REQUIRED NO_MODULE)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
|
||||
|
||||
add_subdirectory(polkit-agent)
|
||||
add_subdirectory(screen-brightness)
|
||||
add_subdirectory(session)
|
||||
add_subdirectory(settings-daemon)
|
||||
add_subdirectory(shutdown-ui)
|
||||
add_subdirectory(xembed-sni-proxy)
|
||||
@ -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,34 @@
|
||||
# System
|
||||
|
||||
System backend and start session and more.
|
||||
|
||||
## Compile dependencies
|
||||
|
||||
```shell
|
||||
sudo pacman -S extra-cmake-modules pkgconf qt5-base qt5-quickcontrols2 qt5-x11extras qt5-tools kwindowsystem polkit polkit-qt5 pulseaudio polkit-qt5
|
||||
```
|
||||
|
||||
## Runtime
|
||||
|
||||
```shell
|
||||
pulseaudio
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
```shell
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
```shell
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project has been licensed by GPLv3.
|
||||
@ -0,0 +1,53 @@
|
||||
#.rst:
|
||||
# FindXCB
|
||||
# -------
|
||||
#
|
||||
# Find XCB libraries
|
||||
#
|
||||
# Tries to find xcb libraries on unix systems.
|
||||
#
|
||||
# - Be sure to set the COMPONENTS to the components you want to link to
|
||||
# - The XCB_LIBRARIES variable is set ONLY to your COMPONENTS list
|
||||
# - To use only a specific component check the XCB_LIBRARIES_${COMPONENT} variable
|
||||
#
|
||||
# The following values are defined
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# XCB_FOUND - True if xcb is available
|
||||
# XCB_INCLUDE_DIRS - Include directories for xcb
|
||||
# XCB_LIBRARIES - List of libraries for xcb
|
||||
# XCB_DEFINITIONS - List of definitions for xcb
|
||||
#
|
||||
#=============================================================================
|
||||
# Copyright (c) 2015 Jari Vetoniemi
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(XCB PROPERTIES
|
||||
URL "https://xcb.freedesktop.org/"
|
||||
DESCRIPTION "X protocol C-language Binding")
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_XCB xcb ${XCB_FIND_COMPONENTS})
|
||||
|
||||
find_library(XCB_LIBRARIES xcb HINTS ${PC_XCB_LIBRARY_DIRS})
|
||||
find_path(XCB_INCLUDE_DIRS xcb/xcb.h PATH_SUFFIXES xcb HINTS ${PC_XCB_INCLUDE_DIRS})
|
||||
|
||||
foreach(COMPONENT ${XCB_FIND_COMPONENTS})
|
||||
find_library(XCB_LIBRARIES_${COMPONENT} ${COMPONENT} HINTS ${PC_XCB_LIBRARY_DIRS})
|
||||
list(APPEND XCB_LIBRARIES ${XCB_LIBRARIES_${COMPONENT}})
|
||||
mark_as_advanced(XCB_LIBRARIES_${COMPONENT})
|
||||
endforeach(COMPONENT ${XCB_FIND_COMPONENTS})
|
||||
|
||||
set(XCB_DEFINITIONS ${PC_XCB_CFLAGS_OTHER})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(XCB DEFAULT_MSG XCB_LIBRARIES XCB_INCLUDE_DIRS)
|
||||
mark_as_advanced(XCB_INCLUDE_DIRS XCB_LIBRARIES XCB_DEFINITIONS)
|
||||
@ -0,0 +1,48 @@
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(POLKIT_AGENT REQUIRED polkit-agent-1)
|
||||
message(STATUS "polkit agent: ${POLKIT_AGENT_INCLUDE_DIRS} ${POLKIT_AGENT_LIBRARIES}")
|
||||
|
||||
find_package(PolkitQt5-1 REQUIRED)
|
||||
|
||||
include_directories(
|
||||
${POLKIT_AGENT_INCLUDE_DIRS}
|
||||
"${POLKITQT-1_INCLUDE_DIR}"
|
||||
)
|
||||
|
||||
add_executable(cutefish-polkit-agent
|
||||
main.cpp
|
||||
polkitagentlistener.cpp
|
||||
dialog.cpp
|
||||
qml.qrc
|
||||
)
|
||||
|
||||
target_link_libraries(cutefish-polkit-agent
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
|
||||
MeuiKit
|
||||
|
||||
${POLKITQT-1_CORE_LIBRARY}
|
||||
${POLKITQT-1_AGENT_LIBRARY}
|
||||
${POLKIT_AGENT_LDFLAGS}
|
||||
)
|
||||
|
||||
file(GLOB TS_FILES translations/*.ts)
|
||||
qt5_create_translation(QM_FILES ${TS_FILES})
|
||||
add_custom_target(polkit-agent-translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES})
|
||||
add_dependencies(cutefish-polkit-agent polkit-agent-translations)
|
||||
|
||||
install(TARGETS cutefish-polkit-agent
|
||||
DESTINATION /usr/bin
|
||||
COMPONENT Runtime
|
||||
)
|
||||
|
||||
install(FILES
|
||||
cutefish-polkit-agent.desktop
|
||||
DESTINATION "/etc/xdg/autostart"
|
||||
COMPONENT Runtime
|
||||
)
|
||||
|
||||
install(FILES ${QM_FILES} DESTINATION /usr/share/cutefish-polkit-agent/translations)
|
||||
@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=PolicyKit Handler
|
||||
TryExec=cutefish-polkit-agent
|
||||
Exec=cutefish-polkit-agent
|
||||
NoDisplay=true
|
||||
@ -0,0 +1,52 @@
|
||||
#include "dialog.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlContext>
|
||||
#include <QScreen>
|
||||
#include <QDebug>
|
||||
|
||||
Dialog::Dialog(const QString &action, const QString &message,
|
||||
const QString &cookie, const QString &identity,
|
||||
PolkitQt1::Agent::AsyncResult *result)
|
||||
: m_action(action)
|
||||
, m_message(message)
|
||||
, m_cookie(cookie)
|
||||
, m_identity(identity)
|
||||
, m_password(QString())
|
||||
, m_result(result)
|
||||
, m_view(new QQuickView)
|
||||
{
|
||||
qDebug() << "Creating ConfirmationDialog";
|
||||
|
||||
m_view->setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
||||
m_view->rootContext()->setContextProperty("confirmation", this);
|
||||
m_view->rootContext()->setContextProperty("rootWindow", m_view);
|
||||
m_view->setResizeMode(QQuickView::SizeViewToRootObject);
|
||||
m_view->setClearBeforeRendering(true);
|
||||
m_view->setDefaultAlphaBuffer(true);
|
||||
m_view->setColor(Qt::transparent);
|
||||
m_view->setSource(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||
m_view->setVisible(false);
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
qDebug() << "Deleting ConfirmationDialog";
|
||||
|
||||
delete m_view;
|
||||
}
|
||||
|
||||
void Dialog::setConfirmationResult(const QString &passwd)
|
||||
{
|
||||
m_password = passwd;
|
||||
|
||||
emit finished(this);
|
||||
}
|
||||
|
||||
void Dialog::show()
|
||||
{
|
||||
m_view->show();
|
||||
m_view->setScreen(qGuiApp->primaryScreen());
|
||||
m_view->setX((m_view->screen()->geometry().width() - m_view->geometry().width()) / 2);
|
||||
m_view->setY((m_view->screen()->geometry().height() - m_view->geometry().height()) / 2);
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
#ifndef DIALOG_H
|
||||
#define DIALOG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QQuickView>
|
||||
|
||||
#include <PolkitQt1/Agent/Listener>
|
||||
|
||||
class Dialog : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Dialog(const QString &action, const QString &message,
|
||||
const QString &cookie, const QString &identity,
|
||||
PolkitQt1::Agent::AsyncResult *result);
|
||||
~Dialog();
|
||||
|
||||
Q_INVOKABLE void setConfirmationResult(const QString &password = QString());
|
||||
Q_INVOKABLE void show();
|
||||
|
||||
Q_PROPERTY(QString message READ message NOTIFY changed)
|
||||
Q_PROPERTY(QString action READ action NOTIFY changed)
|
||||
Q_PROPERTY(QString cookie READ cookie NOTIFY changed)
|
||||
Q_PROPERTY(QString identity READ identity NOTIFY changed)
|
||||
Q_PROPERTY(QString password READ password NOTIFY changed)
|
||||
|
||||
QString message() { return m_message; }
|
||||
QString action() { return m_action; }
|
||||
QString cookie() { return m_cookie; }
|
||||
QString identity() { return m_identity; }
|
||||
QString password() { return m_password; }
|
||||
|
||||
PolkitQt1::Agent::AsyncResult *result() { return m_result; }
|
||||
|
||||
signals:
|
||||
// This signal is never emitted at the moment, as we don't change the
|
||||
// properties of this window dynamically for now
|
||||
void changed();
|
||||
|
||||
// Send approval to the D-Bus helper daemon
|
||||
void finished(Dialog *dialog);
|
||||
|
||||
private:
|
||||
QString m_action;
|
||||
QString m_message;
|
||||
QVariantMap m_details;
|
||||
QString m_cookie;
|
||||
QString m_identity;
|
||||
QString m_password;
|
||||
PolkitQt1::Agent::AsyncResult *m_result;
|
||||
|
||||
QQuickView *m_view;
|
||||
};
|
||||
|
||||
#endif // DIALOG_H
|
||||
@ -0,0 +1,34 @@
|
||||
#include <QGuiApplication>
|
||||
#include <PolkitQt1/Subject>
|
||||
#include <QFile>
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "polkitagentlistener.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication app(argc, argv);
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
// Translations
|
||||
QLocale locale;
|
||||
QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-polkit-agent/translations/").arg(locale.name());
|
||||
if (QFile::exists(qmFilePath)) {
|
||||
QTranslator *translator = new QTranslator(QGuiApplication::instance());
|
||||
if (translator->load(qmFilePath)) {
|
||||
QGuiApplication::installTranslator(translator);
|
||||
} else {
|
||||
translator->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
PolKitAgentListener listener;
|
||||
PolkitQt1::UnixSessionSubject session(getpid());
|
||||
|
||||
if (!listener.registerListener(session, QStringLiteral("/org/cutefishos/PolicyKit1/AuthenticationAgent")))
|
||||
return -1;
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.5
|
||||
import QtQuick.Layouts 1.3
|
||||
import MeuiKit 1.0 as Meui
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
width: 550
|
||||
height: column.implicitHeight + radius * 4
|
||||
|
||||
radius: Meui.Theme.bigRadius
|
||||
color: Meui.Theme.backgroundColor
|
||||
border.color: Qt.rgba(0, 0, 0, 0.4)
|
||||
border.width: 1
|
||||
|
||||
Meui.WindowShadow {
|
||||
view: rootWindow
|
||||
geometry: Qt.rect(root.x, root.y, root.width, root.height)
|
||||
radius: root.radius
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: mainLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.radius * 2
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
source: "qrc:/svg/emblem-warning.svg"
|
||||
sourceSize.width: 96
|
||||
sourceSize.height: 96
|
||||
smooth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Meui.Units.smallSpacing
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: column
|
||||
|
||||
Label {
|
||||
text: confirmation.message
|
||||
wrapMode: Text.WordWrap
|
||||
font.bold: true
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Meui.Units.smallSpacing
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: userTextField
|
||||
text: confirmation.identity
|
||||
enabled: false
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordInput
|
||||
placeholderText: qsTr("Password")
|
||||
echoMode: TextField.Password
|
||||
Layout.fillWidth: true
|
||||
selectByMouse: true
|
||||
focus: true
|
||||
onAccepted: {
|
||||
if (passwordInput.text)
|
||||
confirmation.setConfirmationResult(passwordInput.text)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Meui.Units.smallSpacing
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Button {
|
||||
text: qsTr("Cancel")
|
||||
Layout.fillWidth: true
|
||||
height: 50
|
||||
onClicked: confirmation.setConfirmationResult("")
|
||||
}
|
||||
|
||||
Button {
|
||||
id: doneButton
|
||||
text: qsTr("Done")
|
||||
Layout.fillWidth: true
|
||||
height: 50
|
||||
onClicked: confirmation.setConfirmationResult(passwordInput.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
#include "polkitagentlistener.h"
|
||||
#include "dialog.h"
|
||||
|
||||
PolKitAgentListener::PolKitAgentListener(QObject *parent)
|
||||
: PolkitQt1::Agent::Listener(parent)
|
||||
, m_dialog(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PolKitAgentListener::initiateAuthentication(const QString &actionId,
|
||||
const QString &message,
|
||||
const QString &iconName,
|
||||
const PolkitQt1::Details &details,
|
||||
const QString &cookie,
|
||||
const PolkitQt1::Identity::List &identities,
|
||||
PolkitQt1::Agent::AsyncResult *result)
|
||||
{
|
||||
Q_UNUSED(iconName);
|
||||
Q_UNUSED(details);
|
||||
|
||||
if (m_dialog) {
|
||||
m_dialog->deleteLater();
|
||||
m_dialog = nullptr;
|
||||
}
|
||||
|
||||
m_dialog = new Dialog(actionId, message, cookie, identities.first().toString(), result);
|
||||
|
||||
for (const PolkitQt1::Identity &i : identities) {
|
||||
PolkitQt1::Agent::Session *session;
|
||||
session = new PolkitQt1::Agent::Session(i, cookie, result);
|
||||
Q_ASSERT(session);
|
||||
m_sessionIdentity[session] = i;
|
||||
connect(session, &PolkitQt1::Agent::Session::request, this, &PolKitAgentListener::request);
|
||||
connect(session, &PolkitQt1::Agent::Session::completed, this, &PolKitAgentListener::completed);
|
||||
session->initiate();
|
||||
}
|
||||
}
|
||||
|
||||
void PolKitAgentListener::request(const QString &request, bool echo)
|
||||
{
|
||||
Q_UNUSED(request);
|
||||
Q_UNUSED(echo);
|
||||
|
||||
PolkitQt1::Agent::Session *session = qobject_cast<PolkitQt1::Agent::Session *>(sender());
|
||||
Q_ASSERT(session);
|
||||
Q_ASSERT(m_dialog);
|
||||
|
||||
PolkitQt1::Identity identity = m_sessionIdentity[session];
|
||||
|
||||
connect(m_dialog, &Dialog::finished, this, [=] {
|
||||
if (m_dialog->identity() == m_sessionIdentity[session].toString() && !m_dialog->password().isEmpty()) {
|
||||
session->setResponse(m_dialog->password());
|
||||
} else {
|
||||
session->cancel();
|
||||
}
|
||||
});
|
||||
|
||||
m_dialog->show();
|
||||
}
|
||||
|
||||
void PolKitAgentListener::completed(bool gainedAuthorization)
|
||||
{
|
||||
Q_UNUSED(gainedAuthorization);
|
||||
|
||||
PolkitQt1::Agent::Session *session = qobject_cast<PolkitQt1::Agent::Session *>(sender());
|
||||
Q_ASSERT(session);
|
||||
Q_ASSERT(m_dialog);
|
||||
|
||||
if (m_dialog->identity() == m_sessionIdentity[session].toString()) {
|
||||
session->result()->setCompleted();
|
||||
|
||||
m_dialog->deleteLater();
|
||||
m_dialog = nullptr;
|
||||
}
|
||||
|
||||
session->deleteLater();
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
#ifndef POLKITAGENTLISTENER_H
|
||||
#define POLKITAGENTLISTENER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <PolkitQt1/Identity>
|
||||
#include <PolkitQt1/Details>
|
||||
#include <PolkitQt1/Agent/Listener>
|
||||
#include <PolkitQt1/Agent/Session>
|
||||
|
||||
class Dialog;
|
||||
class PolKitAgentListener : public PolkitQt1::Agent::Listener
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PolKitAgentListener(QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void initiateAuthentication(const QString &actionId,
|
||||
const QString &message,
|
||||
const QString &iconName,
|
||||
const PolkitQt1::Details &details,
|
||||
const QString &cookie,
|
||||
const PolkitQt1::Identity::List &identities,
|
||||
PolkitQt1::Agent::AsyncResult *result);
|
||||
|
||||
bool initiateAuthenticationFinish() { return true; }
|
||||
void cancelAuthentication() {}
|
||||
|
||||
void request(const QString &request, bool echo);
|
||||
void completed(bool gainedAuthorization);
|
||||
|
||||
private:
|
||||
QHash<PolkitQt1::Agent::Session *,PolkitQt1::Identity> m_sessionIdentity;
|
||||
Dialog *m_dialog;
|
||||
};
|
||||
|
||||
#endif // POLKITAGENTLISTENER_H
|
||||
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
<file>svg/emblem-warning.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 24 24"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="emblem-warning.svg"
|
||||
width="24"
|
||||
height="24">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="640"
|
||||
inkscape:window-height="480"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="18.96875"
|
||||
inkscape:cx="-8.0596809"
|
||||
inkscape:cy="9.3007967"
|
||||
inkscape:current-layer="svg2" />
|
||||
<ellipse
|
||||
style="opacity:1;fill:#ff7900;fill-opacity:1"
|
||||
id="path4136-2"
|
||||
cx="-12.747096"
|
||||
cy="11.203196"
|
||||
transform="matrix(-0.06432929,-0.99792873,0.99792873,-0.06432929,0,0)"
|
||||
rx="11"
|
||||
ry="11.000002" />
|
||||
<g
|
||||
id="g6019"
|
||||
transform="matrix(2.2510955,0,0,2.2510955,12.725538,-2329.9799)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1"
|
||||
d="m -0.32369403,1037.708 0.002778,0 c 0.24533241,0 0.44283851,0.1975 0.44283851,0.4428 l 0,3.1124 c 0,0.2454 -0.1975061,0.4429 -0.44283851,0.4429 l -0.002778,0 c -0.24533263,0 -0.44283851,-0.1975 -0.44283851,-0.4429 l 0,-3.1124 c 0,-0.2453 0.19750588,-0.4428 0.44283851,-0.4428 z"
|
||||
id="rect4217" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1"
|
||||
id="rect4681"
|
||||
width="0.88845634"
|
||||
height="0.88845634"
|
||||
x="-0.7665326"
|
||||
y="1042.5945"
|
||||
ry="3.6083155"
|
||||
rx="3.9090085" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>Passwort</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation>Fertig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Abbrechen</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>Password</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation>Done</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Cancel</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="es" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished">Contraseña</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="es_MX" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>Contraseña</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation>Listo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="it" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>Password</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation type="unfinished">Finito</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Annullare</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="nb_NO" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>Passord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation>Ferdig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Avbryt</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="pl_PL">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>Hasło</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation>Gotowe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Anuluj</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="pt_BR" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished">Senha</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="zh_CN">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation>密码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation>完成</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation>取消</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="zh_HK" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="zh_TW" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="62"/>
|
||||
<source>Password</source>
|
||||
<translation type="unfinished">密碼</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="80"/>
|
||||
<source>Done</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="87"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,19 @@
|
||||
project(cutefish-screen-brightness)
|
||||
set(PROJECT_NAME cutefish-screen-brightness)
|
||||
|
||||
set(SRCS
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
${SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION /usr/bin)
|
||||
install(FILES org.cutefish.brightness.pkexec.policy DESTINATION /usr/share/polkit-1/actions/)
|
||||
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: rekols <rekols@foxmail.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 3 of the License, or
|
||||
* 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 <QCoreApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include <QFile>
|
||||
|
||||
inline QString readFile(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QString data = QString::fromUtf8(file.readAll());
|
||||
file.close();
|
||||
return data;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
inline bool writeFile(const QString &fileName, const QString &data)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream textStream(&file);
|
||||
textStream << data;
|
||||
textStream.flush();
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class ScreenDevice
|
||||
{
|
||||
public:
|
||||
void set(int value) {
|
||||
if (value <= 0)
|
||||
value = 1;
|
||||
else if (value > 100)
|
||||
value = 100;
|
||||
|
||||
const int brightness = static_cast<int>(value * maxValue * 0.01);
|
||||
QString brightnessData = QString::number(brightness, 10);
|
||||
const QString brightnessFile = QDir(name).filePath("brightness");
|
||||
writeFile(brightnessFile, brightnessData);
|
||||
}
|
||||
|
||||
int actual;
|
||||
int maxValue;
|
||||
QString name;
|
||||
};
|
||||
|
||||
inline QList<ScreenDevice> getDeviceList()
|
||||
{
|
||||
const char kSysBrightnessDir[] = "/sys/class/backlight";
|
||||
const char kMaxFile[] = "max_brightness";
|
||||
const char kActualFile[] = "actual_brightness";
|
||||
QList<ScreenDevice> list;
|
||||
QDir sys(kSysBrightnessDir);
|
||||
|
||||
for (const QFileInfo &device : sys.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||
const QString dev_path = device.filePath();
|
||||
QDir dev(dev_path);
|
||||
const QString max_brightness = readFile(dev.filePath(kMaxFile));
|
||||
bool max_ok;
|
||||
const int max = max_brightness.toInt(&max_ok, 10);
|
||||
|
||||
if (!max_ok) {
|
||||
qWarning() << "Failed to read max brightness:" << dev_path;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString actual_brightness = readFile(dev.filePath(kActualFile));
|
||||
bool actual_ok;
|
||||
const int actual = actual_brightness.toInt(&actual_ok, 10);
|
||||
if (!actual_ok) {
|
||||
qWarning() << "Failed to read actual brightness:" << dev_path;
|
||||
continue;
|
||||
}
|
||||
|
||||
ScreenDevice screen;
|
||||
screen.actual = actual;
|
||||
screen.maxValue = max;
|
||||
screen.name = dev_path;
|
||||
list << screen;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
inline void setBrightness(int value)
|
||||
{
|
||||
for (ScreenDevice &device : getDeviceList()) {
|
||||
device.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
inline void increaseBrightness()
|
||||
{
|
||||
for (ScreenDevice &device : getDeviceList()) {
|
||||
int value = static_cast<int>(device.actual * 100.0 / device.maxValue);
|
||||
device.set(value + 20);
|
||||
}
|
||||
}
|
||||
|
||||
inline void decreaseBrightness()
|
||||
{
|
||||
for (ScreenDevice &device : getDeviceList()) {
|
||||
int value = static_cast<int>(device.actual * 100.0 / device.maxValue);
|
||||
device.set(value - 20);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
QCommandLineOption setOption(QStringLiteral("set"), QStringLiteral("Set screen brightness"));
|
||||
parser.addOption(setOption);
|
||||
parser.addPositionalArgument("value", "Value");
|
||||
|
||||
QCommandLineOption increaseOption(QStringLiteral("i"), QStringLiteral("Increase brightness"));
|
||||
parser.addOption(increaseOption);
|
||||
|
||||
QCommandLineOption decreaseOption(QStringLiteral("d"), QStringLiteral("Decrease brightness"));
|
||||
parser.addOption(decreaseOption);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(setOption)) {
|
||||
int value = parser.positionalArguments().value(0).toInt();
|
||||
setBrightness(value);
|
||||
} else if (parser.isSet(increaseOption)){
|
||||
increaseBrightness();
|
||||
} else if (parser.isSet(decreaseOption)) {
|
||||
decreaseBrightness();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE policyconfig PUBLIC
|
||||
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||
<policyconfig>
|
||||
<action id="org.cutefish.brightness.pkexec">
|
||||
<message>Authentication is required to Change Brightness</message>
|
||||
<icon_name>battery</icon_name>
|
||||
<defaults>
|
||||
<allow_any>no</allow_any>
|
||||
<allow_inactive>no</allow_inactive>
|
||||
<allow_active>yes</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/cutefish-screen-brightness</annotate>
|
||||
</action>
|
||||
</policyconfig>
|
||||
@ -0,0 +1,29 @@
|
||||
project(cutefish-session)
|
||||
set(TARGET cutefish-session)
|
||||
|
||||
set(SOURCES
|
||||
application.cpp
|
||||
main.cpp
|
||||
process.cpp
|
||||
processmanager.cpp
|
||||
|
||||
powermanager/power.cpp
|
||||
powermanager/powerproviders.cpp
|
||||
)
|
||||
|
||||
qt5_add_dbus_adaptor(DBUS_SOURCES
|
||||
org.cutefish.Session.xml
|
||||
application.h Application
|
||||
sessionadaptor SessionAdaptor)
|
||||
set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON)
|
||||
|
||||
add_executable(${TARGET} ${SOURCES} ${DBUS_SOURCES})
|
||||
target_link_libraries(${TARGET}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::DBus
|
||||
)
|
||||
|
||||
install(TARGETS ${TARGET} DESTINATION /usr/bin)
|
||||
install(FILES cutefish-xsession.desktop DESTINATION /usr/share/xsessions/)
|
||||
@ -0,0 +1,137 @@
|
||||
#include "application.h"
|
||||
#include "sessionadaptor.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QStandardPaths>
|
||||
#include <QSettings>
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
Application::Application(int &argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, m_processManager(new ProcessManager)
|
||||
{
|
||||
new SessionAdaptor(this);
|
||||
|
||||
// connect to D-Bus and register as an object:
|
||||
QDBusConnection::sessionBus().registerService(QStringLiteral("org.cutefish.Session"));
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Session"), this);
|
||||
|
||||
createConfigDirectory();
|
||||
initEnvironments();
|
||||
initLanguage();
|
||||
initScreenScaleFactors();
|
||||
|
||||
if (!syncDBusEnvironment()) {
|
||||
// Startup error
|
||||
qDebug() << "Could not sync environment to dbus.";
|
||||
}
|
||||
|
||||
QTimer::singleShot(100, m_processManager, &ProcessManager::start);
|
||||
}
|
||||
|
||||
void Application::initEnvironments()
|
||||
{
|
||||
// Set defaults
|
||||
if (qEnvironmentVariableIsEmpty("XDG_DATA_HOME"))
|
||||
qputenv("XDG_DATA_HOME", QDir::home().absoluteFilePath(QStringLiteral(".local/share")).toLocal8Bit());
|
||||
if (qEnvironmentVariableIsEmpty("XDG_DESKTOP_DIR"))
|
||||
qputenv("XDG_DESKTOP_DIR", QDir::home().absoluteFilePath(QStringLiteral("/Desktop")).toLocal8Bit());
|
||||
if (qEnvironmentVariableIsEmpty("XDG_CONFIG_HOME"))
|
||||
qputenv("XDG_CONFIG_HOME", QDir::home().absoluteFilePath(QStringLiteral(".config")).toLocal8Bit());
|
||||
if (qEnvironmentVariableIsEmpty("XDG_CACHE_HOME"))
|
||||
qputenv("XDG_CACHE_HOME", QDir::home().absoluteFilePath(QStringLiteral(".cache")).toLocal8Bit());
|
||||
if (qEnvironmentVariableIsEmpty("XDG_DATA_DIRS"))
|
||||
qputenv("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/");
|
||||
if (qEnvironmentVariableIsEmpty("XDG_CONFIG_DIRS"))
|
||||
qputenv("XDG_CONFIG_DIRS", "/etc/xdg");
|
||||
|
||||
// Environment
|
||||
qputenv("DESKTOP_SESSION", "Cutefish");
|
||||
qputenv("XDG_CURRENT_DESKTOP", "Cutefish");
|
||||
qputenv("XDG_SESSION_DESKTOP", "Cutefish");
|
||||
|
||||
qputenv("QT_QPA_PLATFORMTHEME", "cutefish");
|
||||
qputenv("QT_PLATFORM_PLUGIN", "cutefish");
|
||||
|
||||
// IM Config
|
||||
qputenv("GTK_IM_MODULE", "fcitx");
|
||||
qputenv("QT4_IM_MODULE", "fcitx");
|
||||
qputenv("QT_IM_MODULE", "fcitx");
|
||||
qputenv("CLUTTER_IM_MODULE", "fcitx");
|
||||
qputenv("XMODIFIERS", "@im=fcitx");
|
||||
}
|
||||
|
||||
void Application::initLanguage()
|
||||
{
|
||||
QSettings settings(QSettings::UserScope, "cutefishos", "language");
|
||||
QString value = settings.value("language", "en_US").toString();
|
||||
QString str = QString("%1.UTF-8").arg(value);
|
||||
|
||||
const auto lcValues = {
|
||||
"LANG", "LC_NUMERIC", "LC_TIME", "LC_MONETARY", "LC_MEASUREMENT", "LC_COLLATE", "LC_CTYPE"
|
||||
};
|
||||
|
||||
for (auto lc : lcValues) {
|
||||
const QString value = str;
|
||||
if (!value.isEmpty()) {
|
||||
qputenv(lc, value.toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
if (!value.isEmpty()) {
|
||||
qputenv("LANGUAGE", value.toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::initScreenScaleFactors()
|
||||
{
|
||||
QSettings settings(QSettings::UserScope, "cutefishos", "theme");
|
||||
qreal scaleFactor = settings.value("PixelRatio", 1.0).toReal();
|
||||
|
||||
qputenv("QT_SCREEN_SCALE_FACTORS", QByteArray::number(scaleFactor));
|
||||
|
||||
if (std::floor(scaleFactor) > 1) {
|
||||
qputenv("GDK_SCALE", QByteArray::number(scaleFactor, 'g', 0));
|
||||
qputenv("GDK_DPI_SCALE", QByteArray::number(1.0 / scaleFactor, 'g', 3));
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::syncDBusEnvironment()
|
||||
{
|
||||
int exitCode = 0;
|
||||
|
||||
// At this point all environment variables are set, let's send it to the DBus session server to update the activation environment
|
||||
if (!QStandardPaths::findExecutable(QStringLiteral("dbus-update-activation-environment")).isEmpty()) {
|
||||
exitCode = runSync(QStringLiteral("dbus-update-activation-environment"), { QStringLiteral("--systemd"), QStringLiteral("--all") });
|
||||
}
|
||||
|
||||
return exitCode == 0;
|
||||
}
|
||||
|
||||
void Application::createConfigDirectory()
|
||||
{
|
||||
const QString configDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
|
||||
|
||||
if (!QDir().mkpath(configDir))
|
||||
qDebug() << "Could not create config directory XDG_CONFIG_HOME: " << configDir;
|
||||
}
|
||||
|
||||
int Application::runSync(const QString &program, const QStringList &args, const QStringList &env)
|
||||
{
|
||||
QProcess p;
|
||||
|
||||
if (!env.isEmpty())
|
||||
p.setEnvironment(QProcess::systemEnvironment() << env);
|
||||
|
||||
p.setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
p.start(program, args);
|
||||
p.waitForFinished(-1);
|
||||
|
||||
if (p.exitCode()) {
|
||||
qWarning() << program << args << "exited with code" << p.exitCode();
|
||||
}
|
||||
|
||||
return p.exitCode();
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
#ifndef APPLICATION_H
|
||||
#define APPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "processmanager.h"
|
||||
#include "powermanager/power.h"
|
||||
|
||||
class Application : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Application(int &argc, char **argv);
|
||||
|
||||
|
||||
public slots:
|
||||
void logout()
|
||||
{
|
||||
m_processManager->logout();
|
||||
}
|
||||
|
||||
void reboot()
|
||||
{
|
||||
m_power.reboot();
|
||||
QCoreApplication::exit(0);
|
||||
}
|
||||
|
||||
void powerOff()
|
||||
{
|
||||
m_power.shutdown();
|
||||
QCoreApplication::exit(0);
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
m_power.suspend();
|
||||
}
|
||||
|
||||
private:
|
||||
void initEnvironments();
|
||||
void initLanguage();
|
||||
void initScreenScaleFactors();
|
||||
bool syncDBusEnvironment();
|
||||
void createConfigDirectory();
|
||||
int runSync(const QString &program, const QStringList &args, const QStringList &env = {});
|
||||
|
||||
private:
|
||||
ProcessManager *m_processManager;
|
||||
Power m_power;
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
||||
@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=cutefish-session
|
||||
TryExec=cutefish-session
|
||||
Name=Cutefish Desktop
|
||||
Keywords=session
|
||||
Comment=session
|
||||
@ -0,0 +1,8 @@
|
||||
#include "application.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Application a(argc, argv);
|
||||
a.setQuitOnLastWindowClosed(false);
|
||||
return a.exec();
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.cutefish.Session">
|
||||
<method name="logout">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="reboot">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="powerOff">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
<method name="suspend">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,80 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#include "power.h"
|
||||
#include "powerproviders.h"
|
||||
|
||||
#include <QtAlgorithms>
|
||||
#include <QDebug>
|
||||
|
||||
Power::Power(bool useSessionProvider, QObject * parent /*= nullptr*/) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_providers.append(new SystemdProvider(this));
|
||||
m_providers.append(new UPowerProvider(this));
|
||||
m_providers.append(new ConsoleKitProvider(this));
|
||||
}
|
||||
|
||||
Power::Power(QObject * parent /*= nullptr*/)
|
||||
: Power(true, parent)
|
||||
{
|
||||
}
|
||||
|
||||
Power::~Power()
|
||||
{
|
||||
}
|
||||
|
||||
bool Power::canAction(Power::Action action) const
|
||||
{
|
||||
for(const PowerProvider* provider : qAsConst(m_providers))
|
||||
if (provider->canAction(action))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Power::doAction(Power::Action action)
|
||||
{
|
||||
for(PowerProvider* provider : qAsConst(m_providers)) {
|
||||
if (provider->canAction(action) &&
|
||||
provider->doAction(action)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Power::canLogout() const { return canAction(PowerLogout); }
|
||||
bool Power::canHibernate() const { return canAction(PowerHibernate); }
|
||||
bool Power::canReboot() const { return canAction(PowerReboot); }
|
||||
bool Power::canShutdown() const { return canAction(PowerShutdown); }
|
||||
bool Power::canSuspend() const { return canAction(PowerSuspend); }
|
||||
bool Power::canMonitorOff() const { return canAction(PowerMonitorOff); }
|
||||
bool Power::canShowLeaveDialog() const { return canAction(PowerShowLeaveDialog); }
|
||||
|
||||
bool Power::logout() { return doAction(PowerLogout); }
|
||||
bool Power::hibernate() { return doAction(PowerHibernate); }
|
||||
bool Power::reboot() { return doAction(PowerReboot); }
|
||||
bool Power::shutdown() { return doAction(PowerShutdown); }
|
||||
bool Power::suspend() { return doAction(PowerSuspend); }
|
||||
bool Power::monitorOff() { return doAction(PowerMonitorOff); }
|
||||
bool Power::showLeaveDialog() { return doAction(PowerShowLeaveDialog); }
|
||||
@ -0,0 +1,118 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#ifndef POWER_H
|
||||
#define POWER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
class PowerProvider;
|
||||
|
||||
/*! Power class provides an interface to control system-wide power and session management.
|
||||
It allows logout from the user session, hibernate, reboot, shutdown and suspend computer.
|
||||
This is a wrapper class. All the real work is done in the PowerWorker classes.
|
||||
*/
|
||||
class Power : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// Power can perform next actions:
|
||||
enum Action{
|
||||
PowerLogout, /// Close the current user session.
|
||||
PowerHibernate, /// Hibernate the comupter
|
||||
PowerReboot, /// Reboot the computer
|
||||
PowerShutdown, /// Shutdown the computer
|
||||
PowerSuspend, /// Suspend the computer
|
||||
PowerMonitorOff, /// Turn off the monitor(s)
|
||||
PowerShowLeaveDialog /// Show the lxqt-leave dialog
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs the Power object.
|
||||
* \param useLxqtSessionProvider indicates if the DBus methods
|
||||
* provided by lxqt-session should be considered. This is useful to
|
||||
* avoid recursion if the lxqt-session wants to provide some of the
|
||||
* methods by itself with internal use of this object.
|
||||
*/
|
||||
explicit Power(bool useSessionProvider, QObject *parent = nullptr);
|
||||
/// Constructs a Power with using the lxqt-session provider.
|
||||
explicit Power(QObject *parent = nullptr);
|
||||
|
||||
/// Destroys the object.
|
||||
~Power() override;
|
||||
|
||||
/// Returns true if the Power can perform action.
|
||||
bool canAction(Action action) const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerLogout).
|
||||
bool canLogout() const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerHibernate).
|
||||
bool canHibernate() const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerReboot).
|
||||
bool canReboot() const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerShutdown).
|
||||
bool canShutdown() const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerSuspend).
|
||||
bool canSuspend() const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerMonitorOff).
|
||||
bool canMonitorOff() const;
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling canAction(PowerShowLeaveDialog).
|
||||
bool canShowLeaveDialog() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/// Performs the requested action.
|
||||
bool doAction(Action action);
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerLogout).
|
||||
bool logout();
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerHibernate).
|
||||
bool hibernate();
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerReboot).
|
||||
bool reboot();
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerShutdown).
|
||||
bool shutdown();
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerSuspend).
|
||||
bool suspend();
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerMonitorOff).
|
||||
bool monitorOff();
|
||||
|
||||
//! This function is provided for convenience. It's equivalent to calling doAction(PowerShowLeaveDialog).
|
||||
bool showLeaveDialog();
|
||||
|
||||
private:
|
||||
QList<PowerProvider*> m_providers;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,448 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
* Petr Vanek <petr@scribus.info>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#include "powerproviders.h"
|
||||
#include <QDBusInterface>
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <signal.h> // for kill()
|
||||
|
||||
#define UPOWER_SERVICE "org.freedesktop.UPower"
|
||||
#define UPOWER_PATH "/org/freedesktop/UPower"
|
||||
#define UPOWER_INTERFACE UPOWER_SERVICE
|
||||
|
||||
#define CONSOLEKIT_SERVICE "org.freedesktop.ConsoleKit"
|
||||
#define CONSOLEKIT_PATH "/org/freedesktop/ConsoleKit/Manager"
|
||||
#define CONSOLEKIT_INTERFACE "org.freedesktop.ConsoleKit.Manager"
|
||||
|
||||
#define SYSTEMD_SERVICE "org.freedesktop.login1"
|
||||
#define SYSTEMD_PATH "/org/freedesktop/login1"
|
||||
#define SYSTEMD_INTERFACE "org.freedesktop.login1.Manager"
|
||||
|
||||
#define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
|
||||
|
||||
/************************************************
|
||||
Helper func
|
||||
************************************************/
|
||||
void printDBusMsg(const QDBusMessage &msg)
|
||||
{
|
||||
qWarning() << "** Dbus error **************************";
|
||||
qWarning() << "Error name " << msg.errorName();
|
||||
qWarning() << "Error msg " << msg.errorMessage();
|
||||
qWarning() << "****************************************";
|
||||
}
|
||||
|
||||
/************************************************
|
||||
Helper func
|
||||
************************************************/
|
||||
static bool dbusCall(const QString &service,
|
||||
const QString &path,
|
||||
const QString &interface,
|
||||
const QDBusConnection &connection,
|
||||
const QString & method,
|
||||
PowerProvider::DbusErrorCheck errorCheck = PowerProvider::CheckDBUS
|
||||
)
|
||||
{
|
||||
QDBusInterface dbus(service, path, interface, connection);
|
||||
|
||||
if (!dbus.isValid()) {
|
||||
qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method;
|
||||
if (errorCheck == PowerProvider::CheckDBUS)
|
||||
{
|
||||
// Notification::notify(
|
||||
// QObject::tr("Power Manager Error"),
|
||||
// QObject::tr("QDBusInterface is invalid") + QStringLiteral("\n\n") + service + QStringLiteral(' ') + path + QStringLiteral(' ') + interface + QStringLiteral(' ') + method,
|
||||
// QStringLiteral("logo.png"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusMessage msg = dbus.call(method);
|
||||
if (!msg.errorName().isEmpty()) {
|
||||
printDBusMsg(msg);
|
||||
if (errorCheck == PowerProvider::CheckDBUS)
|
||||
{
|
||||
// Notification::notify(
|
||||
// QObject::tr("Power Manager Error (D-BUS call)"),
|
||||
// msg.errorName() + QStringLiteral("\n\n") + msg.errorMessage(),
|
||||
// QStringLiteral("logo.png"));
|
||||
}
|
||||
}
|
||||
|
||||
// If the method no returns value, we believe that it was successful.
|
||||
return msg.arguments().isEmpty() ||
|
||||
msg.arguments().constFirst().isNull() ||
|
||||
msg.arguments().constFirst().toBool();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
Helper func
|
||||
|
||||
Just like dbusCall(), except that systemd
|
||||
returns a string instead of a bool, and it takes
|
||||
an "interactivity boolean" as an argument.
|
||||
************************************************/
|
||||
static bool dbusCallSystemd(const QString &service,
|
||||
const QString &path,
|
||||
const QString &interface,
|
||||
const QDBusConnection &connection,
|
||||
const QString &method,
|
||||
bool needBoolArg,
|
||||
PowerProvider::DbusErrorCheck errorCheck = PowerProvider::CheckDBUS
|
||||
)
|
||||
{
|
||||
QDBusInterface dbus(service, path, interface, connection);
|
||||
if (!dbus.isValid()) {
|
||||
qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method;
|
||||
if (errorCheck == PowerProvider::CheckDBUS) {
|
||||
// Notification::notify(
|
||||
// QObject::tr("Power Manager Error"),
|
||||
// QObject::tr("QDBusInterface is invalid") + QStringLiteral("\n\n") + service + QStringLiteral(' ') + path + QStringLiteral(' ')+ interface + QStringLiteral(' ') + method,
|
||||
// QStringLiteral("logo.png"));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusMessage msg = dbus.call(method, needBoolArg ? QVariant(true) : QVariant());
|
||||
|
||||
if (!msg.errorName().isEmpty()) {
|
||||
printDBusMsg(msg);
|
||||
if (errorCheck == PowerProvider::CheckDBUS) {
|
||||
// Notification::notify(
|
||||
// QObject::tr("Power Manager Error (D-BUS call)"),
|
||||
// msg.errorName() + QStringLiteral("\n\n") + msg.errorMessage(),
|
||||
// QStringLiteral("logo.png"));
|
||||
}
|
||||
}
|
||||
|
||||
// If the method no returns value, we believe that it was successful.
|
||||
if (msg.arguments().isEmpty() || msg.arguments().constFirst().isNull())
|
||||
return true;
|
||||
|
||||
QString response = msg.arguments().constFirst().toString();
|
||||
qDebug() << "systemd:" << method << "=" << response;
|
||||
return response == QStringLiteral("yes") || response == QStringLiteral("challenge");
|
||||
}
|
||||
|
||||
/************************************************
|
||||
Helper func
|
||||
************************************************/
|
||||
bool dbusGetProperty(const QString &service,
|
||||
const QString &path,
|
||||
const QString &interface,
|
||||
const QDBusConnection &connection,
|
||||
const QString & property
|
||||
)
|
||||
{
|
||||
QDBusInterface dbus(service, path, interface, connection);
|
||||
if (!dbus.isValid())
|
||||
{
|
||||
qWarning() << "dbusGetProperty: QDBusInterface is invalid" << service << path << interface << property;
|
||||
// Notification::notify(QObject::tr("Power Manager"),
|
||||
// "logo.png",
|
||||
// QObject::tr("Power Manager Error"),
|
||||
// QObject::tr("QDBusInterface is invalid")+ "\n\n" + service +" " + path +" " + interface +" " + property);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusMessage msg = dbus.call(QStringLiteral("Get"), dbus.interface(), property);
|
||||
|
||||
if (!msg.errorName().isEmpty())
|
||||
{
|
||||
printDBusMsg(msg);
|
||||
// Notification::notify(QObject::tr("Power Manager"),
|
||||
// "logo.png",
|
||||
// QObject::tr("Power Manager Error (Get Property)"),
|
||||
// msg.errorName() + "\n\n" + msg.errorMessage());
|
||||
}
|
||||
|
||||
return !msg.arguments().isEmpty() &&
|
||||
msg.arguments().constFirst().value<QDBusVariant>().variant().toBool();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
PowerProvider
|
||||
************************************************/
|
||||
PowerProvider::PowerProvider(QObject *parent):
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
PowerProvider::~PowerProvider()
|
||||
{
|
||||
}
|
||||
|
||||
/************************************************
|
||||
UPowerProvider
|
||||
************************************************/
|
||||
UPowerProvider::UPowerProvider(QObject *parent):
|
||||
PowerProvider(parent)
|
||||
{
|
||||
}
|
||||
|
||||
UPowerProvider::~UPowerProvider()
|
||||
{
|
||||
}
|
||||
|
||||
bool UPowerProvider::canAction(Power::Action action) const
|
||||
{
|
||||
QString command;
|
||||
QString property;
|
||||
switch (action) {
|
||||
case Power::PowerHibernate:
|
||||
property = QStringLiteral("CanHibernate");
|
||||
command = QStringLiteral("HibernateAllowed");
|
||||
break;
|
||||
case Power::PowerSuspend:
|
||||
property = QStringLiteral("CanSuspend");
|
||||
command = QStringLiteral("SuspendAllowed");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return dbusGetProperty( // Whether the system is able to hibernate.
|
||||
QStringLiteral(UPOWER_SERVICE),
|
||||
QStringLiteral(UPOWER_PATH),
|
||||
QStringLiteral(PROPERTIES_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
property
|
||||
)
|
||||
&&
|
||||
dbusCall( // Check if the caller has (or can get) the PolicyKit privilege to call command.
|
||||
QStringLiteral(UPOWER_SERVICE),
|
||||
QStringLiteral(UPOWER_PATH),
|
||||
QStringLiteral(UPOWER_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
command,
|
||||
// canAction should be always silent because it can freeze
|
||||
// g_main_context_iteration Qt event loop in QMessageBox
|
||||
// on panel startup if there is no DBUS running.
|
||||
PowerProvider::DontCheckDBUS
|
||||
);
|
||||
}
|
||||
|
||||
bool UPowerProvider::doAction(Power::Action action)
|
||||
{
|
||||
QString command;
|
||||
|
||||
switch (action) {
|
||||
case Power::PowerHibernate:
|
||||
command = QStringLiteral("Hibernate");
|
||||
break;
|
||||
case Power::PowerSuspend:
|
||||
command = QStringLiteral("Suspend");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return dbusCall(QStringLiteral(UPOWER_SERVICE),
|
||||
QStringLiteral(UPOWER_PATH),
|
||||
QStringLiteral(UPOWER_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
command );
|
||||
}
|
||||
|
||||
/************************************************
|
||||
ConsoleKitProvider
|
||||
************************************************/
|
||||
ConsoleKitProvider::ConsoleKitProvider(QObject *parent):
|
||||
PowerProvider(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ConsoleKitProvider::~ConsoleKitProvider()
|
||||
{
|
||||
}
|
||||
|
||||
bool ConsoleKitProvider::canAction(Power::Action action) const
|
||||
{
|
||||
QString command;
|
||||
switch (action) {
|
||||
case Power::PowerReboot:
|
||||
command = QStringLiteral("CanReboot");
|
||||
break;
|
||||
|
||||
case Power::PowerShutdown:
|
||||
command = QStringLiteral("CanPowerOff");
|
||||
break;
|
||||
|
||||
case Power::PowerHibernate:
|
||||
command = QStringLiteral("CanHibernate");
|
||||
break;
|
||||
|
||||
case Power::PowerSuspend:
|
||||
command = QStringLiteral("CanSuspend");
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return dbusCallSystemd(QStringLiteral(CONSOLEKIT_SERVICE),
|
||||
QStringLiteral(CONSOLEKIT_PATH),
|
||||
QStringLiteral(CONSOLEKIT_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
command,
|
||||
false,
|
||||
// canAction should be always silent because it can freeze
|
||||
// g_main_context_iteration Qt event loop in QMessageBox
|
||||
// on panel startup if there is no DBUS running.
|
||||
PowerProvider::DontCheckDBUS
|
||||
);
|
||||
}
|
||||
|
||||
bool ConsoleKitProvider::doAction(Power::Action action)
|
||||
{
|
||||
QString command;
|
||||
switch (action) {
|
||||
case Power::PowerReboot:
|
||||
command = QStringLiteral("Reboot");
|
||||
break;
|
||||
case Power::PowerShutdown:
|
||||
command = QStringLiteral("PowerOff");
|
||||
break;
|
||||
case Power::PowerHibernate:
|
||||
command = QStringLiteral("Hibernate");
|
||||
break;
|
||||
case Power::PowerSuspend:
|
||||
command = QStringLiteral("Suspend");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return dbusCallSystemd(QStringLiteral(CONSOLEKIT_SERVICE),
|
||||
QStringLiteral(CONSOLEKIT_PATH),
|
||||
QStringLiteral(CONSOLEKIT_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
command,
|
||||
true);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
SystemdProvider
|
||||
|
||||
http://www.freedesktop.org/wiki/Software/systemd/logind
|
||||
************************************************/
|
||||
|
||||
SystemdProvider::SystemdProvider(QObject *parent):
|
||||
PowerProvider(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SystemdProvider::~SystemdProvider()
|
||||
{
|
||||
}
|
||||
|
||||
bool SystemdProvider::canAction(Power::Action action) const
|
||||
{
|
||||
QString command;
|
||||
|
||||
switch (action) {
|
||||
case Power::PowerReboot:
|
||||
command = QStringLiteral("CanReboot");
|
||||
break;
|
||||
case Power::PowerShutdown:
|
||||
command = QStringLiteral("CanPowerOff");
|
||||
break;
|
||||
case Power::PowerSuspend:
|
||||
command = QStringLiteral("CanSuspend");
|
||||
break;
|
||||
case Power::PowerHibernate:
|
||||
command = QStringLiteral("CanHibernate");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return dbusCallSystemd(QStringLiteral(SYSTEMD_SERVICE),
|
||||
QStringLiteral(SYSTEMD_PATH),
|
||||
QStringLiteral(SYSTEMD_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
command,
|
||||
false,
|
||||
// canAction should be always silent because it can freeze
|
||||
// g_main_context_iteration Qt event loop in QMessageBox
|
||||
// on panel startup if there is no DBUS running.
|
||||
PowerProvider::DontCheckDBUS
|
||||
);
|
||||
}
|
||||
|
||||
bool SystemdProvider::doAction(Power::Action action)
|
||||
{
|
||||
QString command;
|
||||
|
||||
switch (action) {
|
||||
case Power::PowerReboot:
|
||||
command = QStringLiteral("Reboot");
|
||||
break;
|
||||
case Power::PowerShutdown:
|
||||
command = QStringLiteral("PowerOff");
|
||||
break;
|
||||
case Power::PowerSuspend:
|
||||
command = QStringLiteral("Suspend");
|
||||
break;
|
||||
case Power::PowerHibernate:
|
||||
command = QStringLiteral("Hibernate");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return dbusCallSystemd(QStringLiteral(SYSTEMD_SERVICE),
|
||||
QStringLiteral(SYSTEMD_PATH),
|
||||
QStringLiteral(SYSTEMD_INTERFACE),
|
||||
QDBusConnection::systemBus(),
|
||||
command,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
HalProvider
|
||||
************************************************/
|
||||
HalProvider::HalProvider(QObject *parent):
|
||||
PowerProvider(parent)
|
||||
{
|
||||
}
|
||||
|
||||
HalProvider::~HalProvider()
|
||||
{
|
||||
}
|
||||
|
||||
bool HalProvider::canAction(Power::Action action) const
|
||||
{
|
||||
Q_UNUSED(action)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HalProvider::doAction(Power::Action action)
|
||||
{
|
||||
Q_UNUSED(action)
|
||||
return false;
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* Authors:
|
||||
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
|
||||
#ifndef POWERPROVIDERS_H
|
||||
#define POWERPROVIDERS_H
|
||||
|
||||
#include "power.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess> // for PID_T
|
||||
|
||||
class PowerProvider: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DbusErrorCheck {
|
||||
CheckDBUS,
|
||||
DontCheckDBUS
|
||||
};
|
||||
|
||||
explicit PowerProvider(QObject *parent = nullptr);
|
||||
~PowerProvider() override;
|
||||
|
||||
/*! Returns true if the Power can perform action.
|
||||
This is a pure virtual function, and must be reimplemented in subclasses. */
|
||||
virtual bool canAction(Power::Action action) const = 0 ;
|
||||
|
||||
public Q_SLOTS:
|
||||
/*! Performs the requested action.
|
||||
This is a pure virtual function, and must be reimplemented in subclasses. */
|
||||
virtual bool doAction(Power::Action action) = 0;
|
||||
};
|
||||
|
||||
|
||||
class UPowerProvider: public PowerProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UPowerProvider(QObject *parent = nullptr);
|
||||
~UPowerProvider() override;
|
||||
bool canAction(Power::Action action) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool doAction(Power::Action action) override;
|
||||
};
|
||||
|
||||
|
||||
class ConsoleKitProvider: public PowerProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConsoleKitProvider(QObject *parent = nullptr);
|
||||
~ConsoleKitProvider() override;
|
||||
bool canAction(Power::Action action) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool doAction(Power::Action action) override;
|
||||
};
|
||||
|
||||
|
||||
class SystemdProvider: public PowerProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SystemdProvider(QObject *parent = nullptr);
|
||||
~SystemdProvider() override;
|
||||
bool canAction(Power::Action action) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool doAction(Power::Action action) override;
|
||||
};
|
||||
|
||||
class HalProvider: public PowerProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HalProvider(QObject *parent = nullptr);
|
||||
~HalProvider() override;
|
||||
bool canAction(Power::Action action) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool doAction(Power::Action action) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
#include "process.h"
|
||||
|
||||
Process::Process(QObject *parent)
|
||||
: QProcess(parent)
|
||||
{
|
||||
QProcess::setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
}
|
||||
|
||||
Process::~Process()
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
#ifndef PROCESS_H
|
||||
#define PROCESS_H
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
class Process : public QProcess
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Process(QObject *parent = nullptr);
|
||||
~Process();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,131 @@
|
||||
#include "processmanager.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfoList>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include <QDir>
|
||||
|
||||
ProcessManager::ProcessManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ProcessManager::~ProcessManager()
|
||||
{
|
||||
QMapIterator<QString, QProcess *> i(m_systemProcess);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
QProcess *p = i.value();
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessManager::start()
|
||||
{
|
||||
loadSystemProcess();
|
||||
|
||||
QTimer::singleShot(100, this, &ProcessManager::loadAutoStartProcess);
|
||||
}
|
||||
|
||||
void ProcessManager::logout()
|
||||
{
|
||||
QMapIterator<QString, QProcess *> i(m_systemProcess);
|
||||
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
QProcess *p = i.value();
|
||||
p->terminate();
|
||||
}
|
||||
i.toFront();
|
||||
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
QProcess *p = i.value();
|
||||
if (p->state() != QProcess::NotRunning && !p->waitForFinished(2000)) {
|
||||
p->kill();
|
||||
}
|
||||
}
|
||||
|
||||
QCoreApplication::exit(0);
|
||||
}
|
||||
|
||||
void ProcessManager::loadSystemProcess()
|
||||
{
|
||||
QList<QPair<QString, QStringList>> list;
|
||||
list << qMakePair(QString("kwin_x11"), QStringList());
|
||||
list << qMakePair(QString("cutefish-settings-daemon"), QStringList());
|
||||
list << qMakePair(QString("cutefish-xembedsniproxy"), QStringList());
|
||||
|
||||
// Desktop components
|
||||
list << qMakePair(QString("cutefish-fm"), QStringList("--desktop"));
|
||||
list << qMakePair(QString("cutefish-dock"), QStringList());
|
||||
list << qMakePair(QString("cutefish-launcher"), QStringList());
|
||||
|
||||
for (QPair<QString, QStringList> pair : list) {
|
||||
QProcess *process = new QProcess;
|
||||
process->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
process->setProgram(pair.first);
|
||||
process->setArguments(pair.second);
|
||||
process->start();
|
||||
process->waitForStarted();
|
||||
|
||||
if (pair.first == "cutefish-settings-daemon") {
|
||||
QThread::msleep(800);
|
||||
}
|
||||
|
||||
qDebug() << "Load DE components: " << pair.first << pair.second;
|
||||
|
||||
// Add to map
|
||||
if (process->exitCode() == 0) {
|
||||
m_autoStartProcess.insert(pair.first, process);
|
||||
} else {
|
||||
process->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessManager::loadAutoStartProcess()
|
||||
{
|
||||
QStringList execList;
|
||||
QStringList xdgDesktopList;
|
||||
xdgDesktopList << "/etc/xdg/autostart";
|
||||
|
||||
for (const QString &dirName : xdgDesktopList) {
|
||||
QDir dir(dirName);
|
||||
if (!dir.exists())
|
||||
continue;
|
||||
|
||||
const QFileInfoList files = dir.entryInfoList(QStringList("*.desktop"), QDir::Files | QDir::Readable);
|
||||
for (const QFileInfo &fi : files) {
|
||||
QSettings desktop(fi.filePath(), QSettings::IniFormat);
|
||||
desktop.setIniCodec("UTF-8");
|
||||
desktop.beginGroup("Desktop Entry");
|
||||
|
||||
if (desktop.contains("OnlyShowIn"))
|
||||
continue;
|
||||
|
||||
const QString execValue = desktop.value("Exec").toString();
|
||||
|
||||
if (!execValue.isEmpty()) {
|
||||
execList << execValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &exec : execList) {
|
||||
QProcess *process = new QProcess;
|
||||
process->setProgram(exec);
|
||||
process->start();
|
||||
process->waitForStarted();
|
||||
|
||||
if (process->exitCode() == 0) {
|
||||
m_autoStartProcess.insert(exec, process);
|
||||
} else {
|
||||
process->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
#ifndef PROCESSMANAGER_H
|
||||
#define PROCESSMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QMap>
|
||||
|
||||
class ProcessManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProcessManager(QObject *parent = nullptr);
|
||||
~ProcessManager();
|
||||
|
||||
void start();
|
||||
void logout();
|
||||
|
||||
void loadSystemProcess();
|
||||
void loadAutoStartProcess();
|
||||
|
||||
private:
|
||||
QMap<QString, QProcess *> m_systemProcess;
|
||||
QMap<QString, QProcess *> m_autoStartProcess;
|
||||
};
|
||||
|
||||
#endif // PROCESSMANAGER_H
|
||||
@ -0,0 +1,61 @@
|
||||
project(cutefish-settings-daemon)
|
||||
set(TARGET cutefish-settings-daemon)
|
||||
|
||||
find_package(PulseAudio)
|
||||
|
||||
file (GLOB_RECURSE SRCS
|
||||
"*.cpp"
|
||||
"*.h"
|
||||
"audio/*.cpp"
|
||||
"audio/*.h"
|
||||
"theme/*.h"
|
||||
"theme/*.cpp"
|
||||
"brightness/*.h"
|
||||
"brightness/*.cpp"
|
||||
"brightness/*.c"
|
||||
"battery/*.cpp"
|
||||
"battery/*.h"
|
||||
"language/*.cpp"
|
||||
"language/*.h"
|
||||
)
|
||||
|
||||
set(SOURCES ${SRCS})
|
||||
set(HEADERS "")
|
||||
set(FORMS "")
|
||||
set(RESOURCES "")
|
||||
|
||||
qt5_add_dbus_adaptor(DBUS_SOURCES
|
||||
audio/org.cutefish.Audio.xml
|
||||
audio/audiomanager.h AudioManager)
|
||||
qt5_add_dbus_adaptor(DBUS_SOURCES
|
||||
brightness/org.cutefish.Brightness.xml
|
||||
brightness/brightnessmanager.h BrightnessManager)
|
||||
qt5_add_dbus_adaptor(DBUS_SOURCES
|
||||
theme/org.cutefish.Theme.xml
|
||||
theme/thememanager.h ThemeManager)
|
||||
qt5_add_dbus_adaptor(DBUS_SOURCES
|
||||
battery/org.cutefish.PrimaryBattery.xml
|
||||
battery/battery.h Battery)
|
||||
qt5_add_dbus_adaptor(DBUS_SOURCES
|
||||
language/org.cutefish.Language.xml
|
||||
language/language.h Language)
|
||||
|
||||
set_source_files_properties(${DBUS_SOURCES} PROPERTIES SKIP_AUTOGEN ON)
|
||||
|
||||
add_executable(${TARGET} ${SOURCES} ${DBUS_SOURCES} ${HEADERS} ${FORMS} ${RESOURCES})
|
||||
target_link_libraries(${TARGET}
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
Qt5::DBus
|
||||
Qt5::X11Extras
|
||||
${PULSEAUDIO_LIBRARY}
|
||||
)
|
||||
|
||||
file(GLOB TS_FILES translations/*.ts)
|
||||
qt5_create_translation(QM_FILES ${TS_FILES})
|
||||
add_custom_target(translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES})
|
||||
add_dependencies(${TARGET} translations)
|
||||
|
||||
install(TARGETS ${TARGET} DESTINATION /usr/bin)
|
||||
install(FILES ${QM_FILES} DESTINATION /usr/share/${TARGET}/translations)
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 "application.h"
|
||||
#include "dbusadaptor.h"
|
||||
#include <QStandardPaths>
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
|
||||
Application::Application(int &argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, m_audioManager(new AudioManager(this))
|
||||
, m_themeManager(new ThemeManager(this))
|
||||
, m_brightnessManager(new BrightnessManager(this))
|
||||
, m_upowerManager(new UPowerManager(this))
|
||||
, m_language(new Language(this))
|
||||
{
|
||||
new DBusAdaptor(this);
|
||||
// connect to D-Bus and register as an object:
|
||||
QDBusConnection::sessionBus().registerService(QStringLiteral("org.cutefish.Settings"));
|
||||
|
||||
// Translations
|
||||
QLocale locale;
|
||||
QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-settings-daemon/translations/").arg(locale.name());
|
||||
if (QFile::exists(qmFilePath)) {
|
||||
QTranslator *translator = new QTranslator(QApplication::instance());
|
||||
if (translator->load(qmFilePath)) {
|
||||
QApplication::installTranslator(translator);
|
||||
} else {
|
||||
translator->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 APPLICATION_H
|
||||
#define APPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
#include "audio/audiomanager.h"
|
||||
#include "theme/thememanager.h"
|
||||
#include "brightness/brightnessmanager.h"
|
||||
#include "battery/upowermanager.h"
|
||||
#include "language/language.h"
|
||||
|
||||
class Application : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Application(int &argc, char **argv);
|
||||
|
||||
AudioManager *audioManager() { return m_audioManager; }
|
||||
|
||||
private:
|
||||
AudioManager *m_audioManager;
|
||||
ThemeManager *m_themeManager;
|
||||
BrightnessManager *m_brightnessManager;
|
||||
UPowerManager *m_upowerManager;
|
||||
Language *m_language;
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
||||
@ -0,0 +1,117 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include "audiodevice.h"
|
||||
#include "audioengine.h"
|
||||
|
||||
AudioDevice::AudioDevice(AudioDeviceType t, AudioEngine *engine, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_engine(engine),
|
||||
m_volume(0),
|
||||
m_mute(false),
|
||||
m_type(t),
|
||||
m_index(0)
|
||||
{
|
||||
}
|
||||
|
||||
AudioDevice::~AudioDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void AudioDevice::setName(const QString &name)
|
||||
{
|
||||
if (m_name == name)
|
||||
return;
|
||||
|
||||
m_name = name;
|
||||
emit nameChanged(m_name);
|
||||
}
|
||||
|
||||
void AudioDevice::setDescription(const QString &description)
|
||||
{
|
||||
if (m_description == description)
|
||||
return;
|
||||
|
||||
m_description = description;
|
||||
emit descriptionChanged(m_description);
|
||||
}
|
||||
|
||||
void AudioDevice::setIndex(uint index)
|
||||
{
|
||||
if (m_index == index)
|
||||
return;
|
||||
|
||||
m_index = index;
|
||||
emit indexChanged(index);
|
||||
}
|
||||
|
||||
// this is just for setting the internal volume
|
||||
void AudioDevice::setVolumeNoCommit(int volume)
|
||||
{
|
||||
if (m_engine)
|
||||
volume = m_engine->volumeBounded(volume, this);
|
||||
|
||||
if (m_volume == volume)
|
||||
return;
|
||||
|
||||
m_volume = volume;
|
||||
emit volumeChanged(m_volume);
|
||||
}
|
||||
|
||||
void AudioDevice::toggleMute()
|
||||
{
|
||||
setMute(!m_mute);
|
||||
}
|
||||
|
||||
void AudioDevice::setMute(bool state)
|
||||
{
|
||||
if (m_mute == state)
|
||||
return;
|
||||
|
||||
setMuteNoCommit(state);
|
||||
|
||||
if (m_engine)
|
||||
m_engine->setMute(this, state);
|
||||
}
|
||||
|
||||
void AudioDevice::setMuteNoCommit(bool state)
|
||||
{
|
||||
if (m_mute == state)
|
||||
return;
|
||||
|
||||
m_mute = state;
|
||||
emit muteChanged(m_mute);
|
||||
}
|
||||
|
||||
// this performs a volume change on the device
|
||||
void AudioDevice::setVolume(int volume)
|
||||
{
|
||||
if (m_volume == volume)
|
||||
return;
|
||||
|
||||
setVolumeNoCommit(volume);
|
||||
|
||||
if (m_engine)
|
||||
m_engine->commitDeviceVolume(this);
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#ifndef AUDIODEVICE_H
|
||||
#define AUDIODEVICE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AudioEngine;
|
||||
|
||||
typedef enum AudioDeviceType {
|
||||
Sink = 0,
|
||||
Source = 1,
|
||||
PulseAudioDeviceTypeLength
|
||||
} AudioDeviceType;
|
||||
|
||||
class AudioDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
Q_PROPERTY(AudioDeviceType type READ type CONSTANT)
|
||||
|
||||
public:
|
||||
AudioDevice(AudioDeviceType t, AudioEngine *engine, QObject *parent = nullptr);
|
||||
~AudioDevice();
|
||||
|
||||
// the volume can range from 0 to 100.
|
||||
int volume() const { return m_volume; }
|
||||
bool mute() const { return m_mute; }
|
||||
AudioDeviceType type() const { return m_type; }
|
||||
const QString &name() const { return m_name; }
|
||||
const QString &description() const { return m_description; }
|
||||
uint index() const { return m_index; }
|
||||
|
||||
void setName(const QString &name);
|
||||
void setDescription(const QString &description);
|
||||
void setIndex(uint index);
|
||||
|
||||
AudioEngine* engine() { return m_engine; }
|
||||
|
||||
public slots:
|
||||
// the volume can range from 0 to 100.
|
||||
void setVolume(int volume);
|
||||
void setVolumeNoCommit(int volume);
|
||||
void toggleMute();
|
||||
void setMute(bool state);
|
||||
void setMuteNoCommit(bool state);
|
||||
|
||||
signals:
|
||||
void volumeChanged(int volume);
|
||||
void muteChanged(bool state);
|
||||
void nameChanged(const QString &name);
|
||||
void descriptionChanged(const QString &description);
|
||||
void indexChanged(uint index);
|
||||
|
||||
private:
|
||||
AudioEngine *m_engine;
|
||||
int m_volume; // the volume can range from 0 to 100.
|
||||
bool m_mute;
|
||||
AudioDeviceType m_type;
|
||||
QString m_name;
|
||||
uint m_index;
|
||||
QString m_description;
|
||||
};
|
||||
|
||||
#endif // AUDIODEVICE_H
|
||||
@ -0,0 +1,65 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include "audioengine.h"
|
||||
|
||||
#include "audiodevice.h"
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QtDebug>
|
||||
|
||||
AudioEngine::AudioEngine(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
AudioEngine::~AudioEngine()
|
||||
{
|
||||
qDeleteAll(m_sinks);
|
||||
m_sinks.clear();
|
||||
}
|
||||
|
||||
int AudioEngine::volumeBounded(int volume, AudioDevice* device) const
|
||||
{
|
||||
int maximum = volumeMax(device);
|
||||
double v = ((double) volume / 100.0) * maximum;
|
||||
double bounded = qBound<double>(0, v, maximum);
|
||||
return qRound((bounded / maximum) * 100);
|
||||
}
|
||||
|
||||
|
||||
void AudioEngine::mute(AudioDevice *device)
|
||||
{
|
||||
setMute(device, true);
|
||||
}
|
||||
|
||||
void AudioEngine::unmute(AudioDevice *device)
|
||||
{
|
||||
setMute(device, false);
|
||||
}
|
||||
|
||||
void AudioEngine::setIgnoreMaxVolume(bool ignore)
|
||||
{
|
||||
Q_UNUSED(ignore)
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#ifndef AUDIOENGINE_H
|
||||
#define AUDIOENGINE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
class AudioDevice;
|
||||
|
||||
class AudioEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioEngine(QObject *parent = nullptr);
|
||||
~AudioEngine();
|
||||
|
||||
const QList<AudioDevice *> &sinks() const { return m_sinks; }
|
||||
virtual int volumeMax(AudioDevice *device) const = 0;
|
||||
virtual int volumeBounded(int volume, AudioDevice *device) const;
|
||||
virtual const QString backendName() const = 0;
|
||||
|
||||
public slots:
|
||||
virtual void commitDeviceVolume(AudioDevice *device) = 0;
|
||||
virtual void setMute(AudioDevice *device, bool state) = 0;
|
||||
void mute(AudioDevice *device);
|
||||
void unmute(AudioDevice *device);
|
||||
virtual void setIgnoreMaxVolume(bool ignore);
|
||||
|
||||
signals:
|
||||
void sinkListChanged();
|
||||
|
||||
protected:
|
||||
QList<AudioDevice*> m_sinks;
|
||||
};
|
||||
|
||||
#endif // AUDIOENGINE_H
|
||||
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 PandaOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 "audiomanager.h"
|
||||
#include "audioadaptor.h"
|
||||
#include <QDebug>
|
||||
|
||||
AudioManager::AudioManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_engine(new PulseAudioEngine(this)),
|
||||
m_defaultSink(nullptr),
|
||||
m_defaultSinkIndex(0)
|
||||
{
|
||||
if (m_engine->sinks().count() > 0) {
|
||||
m_defaultSink = m_engine->sinks().at(qBound(0, m_defaultSinkIndex, m_engine->sinks().count() - 1));
|
||||
|
||||
new AudioAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Audio"), this);
|
||||
|
||||
connect(m_defaultSink, &AudioDevice::volumeChanged, this, &AudioManager::volumeChanged);
|
||||
connect(m_defaultSink, &AudioDevice::muteChanged, this, &AudioManager::muteChanged);
|
||||
}
|
||||
}
|
||||
|
||||
int AudioManager::volume()
|
||||
{
|
||||
if (!m_defaultSink)
|
||||
return 0;
|
||||
|
||||
return m_defaultSink->volume();
|
||||
}
|
||||
|
||||
bool AudioManager::mute()
|
||||
{
|
||||
if (!m_defaultSink)
|
||||
return false;
|
||||
|
||||
return m_defaultSink->mute();
|
||||
}
|
||||
|
||||
void AudioManager::setVolume(int volume)
|
||||
{
|
||||
if (!m_defaultSink)
|
||||
return;
|
||||
|
||||
m_defaultSink->setVolume(volume);
|
||||
}
|
||||
|
||||
void AudioManager::toggleMute()
|
||||
{
|
||||
if (!m_defaultSink)
|
||||
return;
|
||||
|
||||
m_defaultSink->toggleMute();
|
||||
}
|
||||
|
||||
void AudioManager::setMute(bool state)
|
||||
{
|
||||
if (!m_defaultSink)
|
||||
return;
|
||||
|
||||
m_defaultSink->setMute(state);
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2020 PandaOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 AUDIOMANAGER_H
|
||||
#define AUDIOMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include "audio/pulseaudioengine.h"
|
||||
#include "audio/audiodevice.h"
|
||||
|
||||
class AudioManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int volume READ volume WRITE setVolume)
|
||||
Q_PROPERTY(bool mute READ mute WRITE setMute)
|
||||
|
||||
public:
|
||||
AudioManager(QObject *parent = nullptr);
|
||||
|
||||
int volume();
|
||||
bool mute();
|
||||
void setVolume(int volume);
|
||||
void toggleMute();
|
||||
void setMute(bool state);
|
||||
|
||||
Q_SIGNALS:
|
||||
void volumeChanged(int volume);
|
||||
void muteChanged(bool state);
|
||||
|
||||
private:
|
||||
PulseAudioEngine *m_engine;
|
||||
AudioDevice *m_defaultSink;
|
||||
int m_defaultSinkIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.cutefish.Audio">
|
||||
<method name="setVolume">
|
||||
<arg name="volume" type="i" direction="in"/>
|
||||
</method>
|
||||
<method name="toggleMute"></method>
|
||||
<method name="setMute">
|
||||
<arg name="state" type="b" direction="in"/>
|
||||
</method>
|
||||
|
||||
<property name="volume" type="i" access="read"/>
|
||||
<property name="mute" type="b" access="read"/>
|
||||
|
||||
<signal name="volumeChanged">
|
||||
<arg type="i"/>
|
||||
</signal>
|
||||
<signal name="muteChanged">
|
||||
<arg type="b"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,124 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2014 LXQt team
|
||||
* Authors:
|
||||
* Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include "ossengine.h"
|
||||
#include "audiodevice.h"
|
||||
#include <QDebug>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/soundcard.h>
|
||||
#elif defined(__linux__) || defined(__Linux__)
|
||||
#include <linux/soundcard.h>
|
||||
#else
|
||||
#error "Not supported platform"
|
||||
#endif
|
||||
|
||||
OssEngine::OssEngine(QObject *parent) :
|
||||
AudioEngine(parent),
|
||||
m_mixer(-1),
|
||||
m_device(nullptr),
|
||||
m_leftVolume(0),
|
||||
m_rightVolume(0)
|
||||
{
|
||||
qDebug() << "OssEngine";
|
||||
initMixer();
|
||||
}
|
||||
|
||||
OssEngine::~OssEngine()
|
||||
{
|
||||
if(m_mixer >= 0)
|
||||
close(m_mixer);
|
||||
}
|
||||
|
||||
void OssEngine::initMixer() {
|
||||
m_mixer = open ("/dev/mixer", O_RDWR, 0);
|
||||
if (m_mixer < 0) {
|
||||
qDebug() << "/dev/mixer cannot be opened";
|
||||
return;
|
||||
}
|
||||
qDebug() << "InitMixer:" << m_mixer;
|
||||
|
||||
m_device = new AudioDevice(Sink, this);
|
||||
m_device->setName(QStringLiteral("Master"));
|
||||
m_device->setIndex(0);
|
||||
m_device->setDescription(QStringLiteral("Master Volume"));
|
||||
m_device->setMuteNoCommit(false);
|
||||
updateVolume();
|
||||
|
||||
m_sinks.append(m_device);
|
||||
emit sinkListChanged();
|
||||
}
|
||||
|
||||
void OssEngine::updateVolume() {
|
||||
if(m_mixer < 0 || !m_device)
|
||||
return;
|
||||
int volumes;
|
||||
if(ioctl(m_mixer, MIXER_READ(SOUND_MIXER_VOLUME), &volumes) < 0) {
|
||||
qDebug() << "updateVolume() failed" << errno;
|
||||
}
|
||||
m_leftVolume = volumes & 0xff; // left
|
||||
m_rightVolume = (volumes >> 8) & 0xff; // right
|
||||
qDebug() << "volume:" << m_leftVolume << m_rightVolume;
|
||||
|
||||
m_device->setVolumeNoCommit(m_leftVolume);
|
||||
}
|
||||
|
||||
void OssEngine::setVolume(int volume) {
|
||||
if(m_mixer < 0)
|
||||
return;
|
||||
int volumes = (volume << 8) + volume;
|
||||
if(ioctl(m_mixer, MIXER_WRITE(SOUND_MIXER_VOLUME), &volumes) < 0) {
|
||||
qDebug() << "setVolume() failed" << errno;
|
||||
}
|
||||
else {
|
||||
qDebug() << "setVolume()" << volume;
|
||||
}
|
||||
}
|
||||
|
||||
void OssEngine::commitDeviceVolume(AudioDevice *device)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
setVolume(device->volume());
|
||||
}
|
||||
|
||||
void OssEngine::setMute(AudioDevice * /*device*/, bool state)
|
||||
{
|
||||
if(state)
|
||||
setVolume(0);
|
||||
else
|
||||
setVolume(m_leftVolume);
|
||||
}
|
||||
|
||||
void OssEngine::setIgnoreMaxVolume(bool /*ignore*/)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#ifndef OSSENGINE_H
|
||||
#define OSSENGINE_H
|
||||
|
||||
#include "audioengine.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
class AudioDevice;
|
||||
|
||||
class OssEngine : public AudioEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OssEngine(QObject *parent = nullptr);
|
||||
~OssEngine();
|
||||
|
||||
virtual const QString backendName() const { return QLatin1String("Oss"); }
|
||||
virtual int volumeMax(AudioDevice */*device*/) const { return 100; }
|
||||
|
||||
virtual void commitDeviceVolume(AudioDevice *device);
|
||||
virtual void setMute(AudioDevice *device, bool state);
|
||||
virtual void setIgnoreMaxVolume(bool ignore);
|
||||
|
||||
signals:
|
||||
void sinkInfoChanged(AudioDevice *device);
|
||||
void readyChanged(bool ready);
|
||||
|
||||
private:
|
||||
void initMixer();
|
||||
void updateVolume();
|
||||
void setVolume(int volume);
|
||||
|
||||
private:
|
||||
int m_mixer; // oss mixer fd
|
||||
AudioDevice* m_device;
|
||||
int m_leftVolume;
|
||||
int m_rightVolume;
|
||||
};
|
||||
|
||||
#endif // OSSENGINE_H
|
||||
@ -0,0 +1,427 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#include "pulseaudioengine.h"
|
||||
|
||||
#include "audiodevice.h"
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QtDebug>
|
||||
|
||||
//#define PULSEAUDIO_ENGINE_DEBUG
|
||||
|
||||
static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int isLast, void *userdata)
|
||||
{
|
||||
PulseAudioEngine *pulseEngine = static_cast<PulseAudioEngine*>(userdata);
|
||||
QMap<pa_sink_state, QString> stateMap;
|
||||
stateMap[PA_SINK_INVALID_STATE] = QLatin1String("n/a");
|
||||
stateMap[PA_SINK_RUNNING] = QLatin1String("RUNNING");
|
||||
stateMap[PA_SINK_IDLE] = QLatin1String("IDLE");
|
||||
stateMap[PA_SINK_SUSPENDED] = QLatin1String("SUSPENDED");
|
||||
|
||||
if (isLast < 0) {
|
||||
pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
|
||||
qWarning() << QStringLiteral("Failed to get sink information: %1").arg(QString::fromUtf8(pa_strerror(pa_context_errno(context))));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLast) {
|
||||
pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pulseEngine->addOrUpdateSink(info);
|
||||
}
|
||||
|
||||
static void contextEventCallback(pa_context * /*context*/, const char *
|
||||
#ifdef PULSEAUDIO_ENGINE_DEBUG
|
||||
name
|
||||
#endif
|
||||
, pa_proplist * /*p*/, void * /*userdata*/)
|
||||
{
|
||||
#ifdef PULSEAUDIO_ENGINE_DEBUG
|
||||
qWarning("event received %s", name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void contextStateCallback(pa_context *context, void *userdata)
|
||||
{
|
||||
PulseAudioEngine *pulseEngine = reinterpret_cast<PulseAudioEngine*>(userdata);
|
||||
|
||||
// update internal state
|
||||
pa_context_state_t state = pa_context_get_state(context);
|
||||
pulseEngine->setContextState(state);
|
||||
|
||||
#ifdef PULSEAUDIO_ENGINE_DEBUG
|
||||
switch (state) {
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
qWarning("context unconnected");
|
||||
break;
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
qWarning("context connecting");
|
||||
break;
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
qWarning("context authorizing");
|
||||
break;
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
qWarning("context setting name");
|
||||
break;
|
||||
case PA_CONTEXT_READY:
|
||||
qWarning("context ready");
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
qWarning("context failed");
|
||||
break;
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
qWarning("context terminated");
|
||||
break;
|
||||
default:
|
||||
qWarning("we should never hit this state");
|
||||
}
|
||||
#endif
|
||||
|
||||
pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
|
||||
}
|
||||
|
||||
static void contextSuccessCallback(pa_context *context, int success, void *userdata)
|
||||
{
|
||||
Q_UNUSED(context);
|
||||
Q_UNUSED(success);
|
||||
Q_UNUSED(userdata);
|
||||
|
||||
PulseAudioEngine *pulseEngine = reinterpret_cast<PulseAudioEngine*>(userdata);
|
||||
pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
|
||||
}
|
||||
|
||||
static void contextSubscriptionCallback(pa_context * /*context*/, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
|
||||
{
|
||||
PulseAudioEngine *pulseEngine = reinterpret_cast<PulseAudioEngine*>(userdata);
|
||||
if (PA_SUBSCRIPTION_EVENT_REMOVE == t)
|
||||
pulseEngine->removeSink(idx);
|
||||
else
|
||||
pulseEngine->requestSinkInfoUpdate(idx);
|
||||
}
|
||||
|
||||
|
||||
PulseAudioEngine::PulseAudioEngine(QObject *parent) :
|
||||
AudioEngine(parent),
|
||||
m_context(0),
|
||||
m_contextState(PA_CONTEXT_UNCONNECTED),
|
||||
m_ready(false),
|
||||
m_maximumVolume(PA_VOLUME_UI_MAX)
|
||||
{
|
||||
qRegisterMetaType<pa_context_state_t>("pa_context_state_t");
|
||||
|
||||
m_reconnectionTimer.setSingleShot(true);
|
||||
m_reconnectionTimer.setInterval(100);
|
||||
connect(&m_reconnectionTimer, SIGNAL(timeout()), this, SLOT(connectContext()));
|
||||
|
||||
m_mainLoop = pa_threaded_mainloop_new();
|
||||
if (m_mainLoop == 0) {
|
||||
qWarning("Unable to create pulseaudio mainloop");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pa_threaded_mainloop_start(m_mainLoop) != 0) {
|
||||
qWarning("Unable to start pulseaudio mainloop");
|
||||
pa_threaded_mainloop_free(m_mainLoop);
|
||||
m_mainLoop = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop);
|
||||
|
||||
connect(this, SIGNAL(contextStateChanged(pa_context_state_t)), this, SLOT(handleContextStateChanged()));
|
||||
|
||||
connectContext();
|
||||
}
|
||||
|
||||
PulseAudioEngine::~PulseAudioEngine()
|
||||
{
|
||||
if (m_context) {
|
||||
pa_context_unref(m_context);
|
||||
m_context = 0;
|
||||
}
|
||||
|
||||
if (m_mainLoop) {
|
||||
pa_threaded_mainloop_free(m_mainLoop);
|
||||
m_mainLoop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioEngine::removeSink(uint32_t idx)
|
||||
{
|
||||
auto dev_i = std::find_if(m_sinks.begin(), m_sinks.end(), [idx] (AudioDevice * dev) { return dev->index() == idx; });
|
||||
if (m_sinks.end() == dev_i)
|
||||
return;
|
||||
|
||||
QScopedPointer<AudioDevice> dev{*dev_i};
|
||||
m_cVolumeMap.remove(dev.data());
|
||||
m_sinks.erase(dev_i);
|
||||
emit sinkListChanged();
|
||||
}
|
||||
|
||||
void PulseAudioEngine::addOrUpdateSink(const pa_sink_info *info)
|
||||
{
|
||||
AudioDevice *dev = 0;
|
||||
bool newSink = false;
|
||||
QString name = QString::fromUtf8(info->name);
|
||||
|
||||
for (AudioDevice *device : qAsConst(m_sinks)) {
|
||||
if (device->name() == name) {
|
||||
dev = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev) {
|
||||
dev = new AudioDevice(Sink, this);
|
||||
newSink = true;
|
||||
}
|
||||
|
||||
dev->setName(name);
|
||||
dev->setIndex(info->index);
|
||||
dev->setDescription(QString::fromUtf8(info->description));
|
||||
dev->setMuteNoCommit(info->mute);
|
||||
|
||||
// TODO: save separately? alsa does not have it
|
||||
m_cVolumeMap.insert(dev, info->volume);
|
||||
|
||||
pa_volume_t v = pa_cvolume_avg(&(info->volume));
|
||||
// convert real volume to percentage
|
||||
dev->setVolumeNoCommit(qRound((static_cast<double>(v) * 100.0) / m_maximumVolume));
|
||||
|
||||
if (newSink) {
|
||||
//keep the sinks sorted by index()
|
||||
m_sinks.insert(
|
||||
std::lower_bound(m_sinks.begin(), m_sinks.end(), dev, [] (AudioDevice const * const a, AudioDevice const * const b) {
|
||||
return a->name() < b->name();
|
||||
})
|
||||
, dev
|
||||
);
|
||||
emit sinkListChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioEngine::requestSinkInfoUpdate(uint32_t idx)
|
||||
{
|
||||
emit sinkInfoChanged(idx);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::commitDeviceVolume(AudioDevice *device)
|
||||
{
|
||||
if (!device || !m_ready)
|
||||
return;
|
||||
|
||||
// convert from percentage to real volume value
|
||||
pa_volume_t v = ((double)device->volume() / 100.0) * m_maximumVolume;
|
||||
pa_cvolume tmpVolume = m_cVolumeMap.value(device);
|
||||
pa_cvolume *volume = pa_cvolume_set(&tmpVolume, tmpVolume.channels, v);
|
||||
// qDebug() << "PulseAudioEngine::commitDeviceVolume" << v;
|
||||
pa_threaded_mainloop_lock(m_mainLoop);
|
||||
|
||||
pa_operation *operation;
|
||||
if (device->type() == Sink)
|
||||
operation = pa_context_set_sink_volume_by_index(m_context, device->index(), volume, contextSuccessCallback, this);
|
||||
else
|
||||
operation = pa_context_set_source_volume_by_index(m_context, device->index(), volume, contextSuccessCallback, this);
|
||||
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
pa_threaded_mainloop_wait(m_mainLoop);
|
||||
pa_operation_unref(operation);
|
||||
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::retrieveSinks()
|
||||
{
|
||||
if (!m_ready)
|
||||
return;
|
||||
|
||||
pa_threaded_mainloop_lock(m_mainLoop);
|
||||
|
||||
pa_operation *operation;
|
||||
operation = pa_context_get_sink_info_list(m_context, sinkInfoCallback, this);
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
pa_threaded_mainloop_wait(m_mainLoop);
|
||||
pa_operation_unref(operation);
|
||||
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::setupSubscription()
|
||||
{
|
||||
if (!m_ready)
|
||||
return;
|
||||
|
||||
connect(this, &PulseAudioEngine::sinkInfoChanged, this, &PulseAudioEngine::retrieveSinkInfo, Qt::QueuedConnection);
|
||||
pa_context_set_subscribe_callback(m_context, contextSubscriptionCallback, this);
|
||||
|
||||
pa_threaded_mainloop_lock(m_mainLoop);
|
||||
|
||||
pa_operation *operation;
|
||||
operation = pa_context_subscribe(m_context, PA_SUBSCRIPTION_MASK_SINK, contextSuccessCallback, this);
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
pa_threaded_mainloop_wait(m_mainLoop);
|
||||
pa_operation_unref(operation);
|
||||
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::handleContextStateChanged()
|
||||
{
|
||||
if (m_contextState == PA_CONTEXT_FAILED || m_contextState == PA_CONTEXT_TERMINATED) {
|
||||
qWarning("LXQt-Volume: Context connection failed or terminated lets try to reconnect");
|
||||
m_reconnectionTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioEngine::connectContext()
|
||||
{
|
||||
bool keepGoing = true;
|
||||
bool ok = false;
|
||||
|
||||
m_reconnectionTimer.stop();
|
||||
|
||||
if (!m_mainLoop)
|
||||
return;
|
||||
|
||||
pa_threaded_mainloop_lock(m_mainLoop);
|
||||
|
||||
if (m_context) {
|
||||
pa_context_unref(m_context);
|
||||
m_context = 0;
|
||||
}
|
||||
|
||||
m_context = pa_context_new(m_mainLoopApi, "lxqt-volume");
|
||||
pa_context_set_state_callback(m_context, contextStateCallback, this);
|
||||
pa_context_set_event_callback(m_context, contextEventCallback, this);
|
||||
|
||||
if (!m_context) {
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
m_reconnectionTimer.start();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pa_context_connect(m_context, nullptr, (pa_context_flags_t)0, nullptr) < 0) {
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
m_reconnectionTimer.start();
|
||||
return;
|
||||
}
|
||||
|
||||
while (keepGoing) {
|
||||
switch (m_contextState) {
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_READY:
|
||||
keepGoing = false;
|
||||
ok = true;
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
keepGoing = false;
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_FAILED:
|
||||
default:
|
||||
qWarning() << QStringLiteral("Connection failure: %1").arg(QString::fromUtf8(pa_strerror(pa_context_errno(m_context))));
|
||||
keepGoing = false;
|
||||
}
|
||||
|
||||
if (keepGoing)
|
||||
pa_threaded_mainloop_wait(m_mainLoop);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
|
||||
if (ok) {
|
||||
retrieveSinks();
|
||||
setupSubscription();
|
||||
} else {
|
||||
m_reconnectionTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioEngine::retrieveSinkInfo(uint32_t idx)
|
||||
{
|
||||
if (!m_ready)
|
||||
return;
|
||||
|
||||
pa_threaded_mainloop_lock(m_mainLoop);
|
||||
|
||||
pa_operation *operation;
|
||||
operation = pa_context_get_sink_info_by_index(m_context, idx, sinkInfoCallback, this);
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
pa_threaded_mainloop_wait(m_mainLoop);
|
||||
pa_operation_unref(operation);
|
||||
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::setMute(AudioDevice *device, bool state)
|
||||
{
|
||||
if (!m_ready)
|
||||
return;
|
||||
|
||||
pa_threaded_mainloop_lock(m_mainLoop);
|
||||
|
||||
pa_operation *operation;
|
||||
operation = pa_context_set_sink_mute_by_index(m_context, device->index(), state, contextSuccessCallback, this);
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
pa_threaded_mainloop_wait(m_mainLoop);
|
||||
pa_operation_unref(operation);
|
||||
|
||||
pa_threaded_mainloop_unlock(m_mainLoop);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::setContextState(pa_context_state_t state)
|
||||
{
|
||||
if (m_contextState == state)
|
||||
return;
|
||||
|
||||
m_contextState = state;
|
||||
|
||||
// update ready member as it depends on state
|
||||
if (m_ready == (m_contextState == PA_CONTEXT_READY))
|
||||
return;
|
||||
|
||||
m_ready = (m_contextState == PA_CONTEXT_READY);
|
||||
|
||||
emit contextStateChanged(m_contextState);
|
||||
emit readyChanged(m_ready);
|
||||
}
|
||||
|
||||
void PulseAudioEngine::setIgnoreMaxVolume(bool ignore)
|
||||
{
|
||||
if (ignore)
|
||||
m_maximumVolume = PA_VOLUME_UI_MAX;
|
||||
else
|
||||
m_maximumVolume = pa_sw_volume_from_dB(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
||||
* (c)LGPL2+
|
||||
*
|
||||
* Copyright: 2012 Razor team
|
||||
* Authors:
|
||||
* Johannes Zellner <webmaster@nebulon.de>
|
||||
*
|
||||
* This program or library is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
* END_COMMON_COPYRIGHT_HEADER */
|
||||
|
||||
#ifndef PULSEAUDIOENGINE_H
|
||||
#define PULSEAUDIOENGINE_H
|
||||
|
||||
#include "audioengine.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QMap>
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <pulse/volume.h>
|
||||
#include <pulse/context.h>
|
||||
#include <pulse/thread-mainloop.h>
|
||||
|
||||
// PA_VOLUME_UI_MAX is only supported since pulseaudio 0.9.23
|
||||
#ifndef PA_VOLUME_UI_MAX
|
||||
#define PA_VOLUME_UI_MAX (pa_sw_volume_from_dB(+11.0))
|
||||
#endif
|
||||
|
||||
class AudioDevice;
|
||||
|
||||
class PulseAudioEngine : public AudioEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PulseAudioEngine(QObject *parent = nullptr);
|
||||
~PulseAudioEngine();
|
||||
|
||||
virtual const QString backendName() const { return QLatin1String("PulseAudio"); }
|
||||
|
||||
int volumeMax(AudioDevice */*device*/) const { return m_maximumVolume; }
|
||||
|
||||
void requestSinkInfoUpdate(uint32_t idx);
|
||||
void removeSink(uint32_t idx);
|
||||
void addOrUpdateSink(const pa_sink_info *info);
|
||||
|
||||
pa_context_state_t contextState() const { return m_contextState; }
|
||||
bool ready() const { return m_ready; }
|
||||
pa_threaded_mainloop *mainloop() const { return m_mainLoop; }
|
||||
|
||||
public slots:
|
||||
void commitDeviceVolume(AudioDevice *device);
|
||||
void retrieveSinkInfo(uint32_t idx);
|
||||
void setMute(AudioDevice *device, bool state);
|
||||
void setContextState(pa_context_state_t state);
|
||||
void setIgnoreMaxVolume(bool ignore);
|
||||
|
||||
signals:
|
||||
void sinkInfoChanged(uint32_t idx);
|
||||
void contextStateChanged(pa_context_state_t state);
|
||||
void readyChanged(bool ready);
|
||||
|
||||
private slots:
|
||||
void handleContextStateChanged();
|
||||
void connectContext();
|
||||
|
||||
private:
|
||||
void retrieveSinks();
|
||||
void setupSubscription();
|
||||
|
||||
pa_mainloop_api *m_mainLoopApi;
|
||||
pa_threaded_mainloop *m_mainLoop;
|
||||
pa_context *m_context;
|
||||
|
||||
pa_context_state_t m_contextState;
|
||||
bool m_ready;
|
||||
QTimer m_reconnectionTimer;
|
||||
int m_maximumVolume;
|
||||
|
||||
QMap<AudioDevice *, pa_cvolume> m_cVolumeMap;
|
||||
};
|
||||
|
||||
#endif // PULSEAUDIOENGINE_H
|
||||
@ -0,0 +1,412 @@
|
||||
#include "battery.h"
|
||||
#include "power.h"
|
||||
#include "primarybatteryadaptor.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
enum TimeConstants {
|
||||
SecsInDay = 86400,
|
||||
SecsInHour = 3600,
|
||||
SecsInMinute = 60
|
||||
};
|
||||
|
||||
// ref: https://upower.freedesktop.org/docs/Device.html
|
||||
// kf5solid
|
||||
|
||||
Battery::Battery(UPowerDevice *device, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_device(device)
|
||||
, m_settings(nullptr)
|
||||
, m_lastChargedPercent(0)
|
||||
, m_lastChargedSecs(0)
|
||||
{
|
||||
connect(device, SIGNAL(changed()), this, SLOT(slotChanged()));
|
||||
|
||||
updateCache();
|
||||
init();
|
||||
}
|
||||
|
||||
void Battery::updateCache()
|
||||
{
|
||||
m_chargeState = chargeState();
|
||||
m_isPresent = isPresent();
|
||||
m_chargePercent = chargePercent();
|
||||
m_capacity = capacity();
|
||||
m_isPowerSupply = isPowerSupply();
|
||||
m_timeToEmpty = timeToEmpty();
|
||||
m_timeToFull = timeToFull();
|
||||
m_energy = energy();
|
||||
m_energyFull = energyFull();
|
||||
m_energyFullDesign = energyFullDesign();
|
||||
m_energyRate = energyRate();
|
||||
m_voltage = voltage();
|
||||
m_temperature = temperature();
|
||||
}
|
||||
|
||||
void Battery::init()
|
||||
{
|
||||
if (type() == Battery::PrimaryBattery) {
|
||||
new PrimaryBatteryAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/PrimaryBattery"), this);
|
||||
|
||||
m_settings = new QSettings(QStringLiteral("cutefishos"), QStringLiteral("PrimaryBattery"));
|
||||
m_lastChargedPercent = m_settings->value("LastChargedPercent", 0).toInt();
|
||||
m_lastChargedSecs = m_settings->value("LastChargedSecs").toLongLong();
|
||||
}
|
||||
}
|
||||
|
||||
void Battery::refresh()
|
||||
{
|
||||
QDBusInterface iface(UP_DBUS_SERVICE, m_device->udi(),
|
||||
UP_DBUS_INTERFACE_DEVICE, QDBusConnection::systemBus());
|
||||
if (iface.isValid())
|
||||
iface.call("Refresh");
|
||||
}
|
||||
|
||||
bool Battery::isPresent() const
|
||||
{
|
||||
return m_device->prop("IsPresent").toBool();
|
||||
}
|
||||
|
||||
Battery::BatteryType Battery::type() const
|
||||
{
|
||||
Battery::BatteryType result = Battery::UnknownBattery;
|
||||
const uint t = m_device->prop("Type").toUInt();
|
||||
|
||||
switch (t) {
|
||||
case UP_DEVICE_KIND_LINE_POWER: // TODO
|
||||
break;
|
||||
case UP_DEVICE_KIND_BATTERY:
|
||||
result = Battery::PrimaryBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_UPS:
|
||||
result = Battery::UpsBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_MONITOR:
|
||||
result = Battery::MonitorBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_MOUSE:
|
||||
result = Battery::MouseBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_KEYBOARD:
|
||||
result = Battery::KeyboardBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_PDA:
|
||||
result = Battery::PdaBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_PHONE:
|
||||
result = Battery::PhoneBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_GAMING_INPUT:
|
||||
result = Battery::GamingInputBattery;
|
||||
break;
|
||||
case UP_DEVICE_KIND_UNKNOWN: {
|
||||
// There is currently no "Bluetooth battery" type, so check if it comes from Bluez
|
||||
if (m_device->prop("NativePath").toString().startsWith(QLatin1String("/org/bluez/"))) {
|
||||
result = Battery::BluetoothBattery;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int Battery::chargePercent() const
|
||||
{
|
||||
return qRound(m_device->prop("Percentage").toDouble());
|
||||
}
|
||||
|
||||
int Battery::capacity() const
|
||||
{
|
||||
return m_device->prop("Capacity").toDouble();
|
||||
}
|
||||
|
||||
bool Battery::isRechargeable() const
|
||||
{
|
||||
return m_device->prop("IsRechargeable").toBool();
|
||||
}
|
||||
|
||||
bool Battery::isPowerSupply() const
|
||||
{
|
||||
return m_device->prop("PowerSupply").toBool();
|
||||
}
|
||||
|
||||
Battery::ChargeState Battery::chargeState() const
|
||||
{
|
||||
Battery::ChargeState result = Battery::NoCharge;
|
||||
const uint state = m_device->prop("State").toUInt();
|
||||
switch (state) {
|
||||
case 0:
|
||||
result = Battery::NoCharge; // stable or unknown
|
||||
break;
|
||||
case 1:
|
||||
result = Battery::Charging;
|
||||
break;
|
||||
case 2:
|
||||
result = Battery::Discharging;
|
||||
break;
|
||||
case 3: // TODO "Empty"
|
||||
break;
|
||||
case 4:
|
||||
result = Battery::FullyCharged;
|
||||
break;
|
||||
case 5: // TODO "Pending charge"
|
||||
break;
|
||||
case 6: // TODO "Pending discharge"
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
qlonglong Battery::timeToEmpty() const
|
||||
{
|
||||
return m_device->prop("TimeToEmpty").toLongLong();
|
||||
}
|
||||
|
||||
qlonglong Battery::timeToFull() const
|
||||
{
|
||||
return m_device->prop("TimeToFull").toLongLong();
|
||||
}
|
||||
|
||||
Battery::Technology Battery::technology() const
|
||||
{
|
||||
const uint tech = m_device->prop("Technology").toUInt();
|
||||
switch (tech) {
|
||||
case 1:
|
||||
return Battery::LithiumIon;
|
||||
case 2:
|
||||
return Battery::LithiumPolymer;
|
||||
case 3:
|
||||
return Battery::LithiumIronPhosphate;
|
||||
case 4:
|
||||
return Battery::LeadAcid;
|
||||
case 5:
|
||||
return Battery::NickelCadmium;
|
||||
case 6:
|
||||
return Battery::NickelMetalHydride;
|
||||
default:
|
||||
return Battery::UnknownTechnology;
|
||||
}
|
||||
}
|
||||
|
||||
double Battery::energy() const
|
||||
{
|
||||
return m_device->prop("Energy").toDouble();
|
||||
}
|
||||
|
||||
double Battery::energyFull() const
|
||||
{
|
||||
return m_device->prop("EnergyFull").toDouble();
|
||||
}
|
||||
|
||||
double Battery::energyFullDesign() const
|
||||
{
|
||||
return m_device->prop("EnergyFullDesign").toDouble();
|
||||
}
|
||||
|
||||
double Battery::energyRate() const
|
||||
{
|
||||
return m_device->prop("EnergyRate").toDouble();
|
||||
}
|
||||
|
||||
double Battery::voltage() const
|
||||
{
|
||||
return m_device->prop("Voltage").toDouble();
|
||||
}
|
||||
|
||||
double Battery::temperature() const
|
||||
{
|
||||
return m_device->prop("Temperature").toDouble();
|
||||
}
|
||||
|
||||
bool Battery::isRecalled() const
|
||||
{
|
||||
return m_device->prop("RecallNotice").toBool();
|
||||
}
|
||||
|
||||
QString Battery::recallVendor() const
|
||||
{
|
||||
return m_device->prop("RecallVendor").toString();
|
||||
}
|
||||
|
||||
QString Battery::recallUrl() const
|
||||
{
|
||||
return m_device->prop("RecallUrl").toString();
|
||||
}
|
||||
|
||||
QString Battery::serial() const
|
||||
{
|
||||
return m_device->prop("Serial").toString();
|
||||
}
|
||||
|
||||
qlonglong Battery::remainingTime() const
|
||||
{
|
||||
if (chargeState() == Battery::Charging) {
|
||||
return timeToFull();
|
||||
} else if (chargeState() == Battery::Discharging) {
|
||||
return timeToEmpty();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString Battery::formatDuration(qlonglong seconds) const
|
||||
{
|
||||
QString result;
|
||||
quint64 secs = seconds;
|
||||
|
||||
int days = secs / SecsInDay;
|
||||
secs = secs % SecsInDay;
|
||||
int hours = secs / SecsInHour;
|
||||
secs = secs % SecsInHour;
|
||||
int minutes = secs / SecsInMinute;
|
||||
|
||||
if (days > 0)
|
||||
result.push_back(QString("%1%2").arg(days).arg(tr("d")));
|
||||
|
||||
if (hours > 0) {
|
||||
if (days > 0)
|
||||
result.push_back(" ");
|
||||
|
||||
result.push_back(QString("%1%2").arg(hours).arg(tr("h")));
|
||||
}
|
||||
|
||||
if (minutes > 0) {
|
||||
if (hours > 0)
|
||||
result.push_back(" ");
|
||||
|
||||
result.push_back(QString("%1%2").arg(minutes).arg(tr("m")));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString Battery::statusString() const
|
||||
{
|
||||
if (chargeState() == Battery::Charging) {
|
||||
return QString("%1 ").arg(formatDuration(remainingTime())) + tr("until fully charged.");
|
||||
} else if (chargeState() == Battery::Discharging) {
|
||||
return QString("%1 ").arg(formatDuration(remainingTime())) + tr("remaining.");
|
||||
} else if (chargeState() == Battery::FullyCharged) {
|
||||
return tr("Fully charged.");
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
int Battery::lastChargedPercent() const
|
||||
{
|
||||
return m_lastChargedPercent;
|
||||
}
|
||||
|
||||
quint64 Battery::lastChargedSecs() const
|
||||
{
|
||||
return m_lastChargedSecs;
|
||||
}
|
||||
|
||||
QString Battery::lastChargedTime() const
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QDateTime time = QDateTime::fromSecsSinceEpoch(m_lastChargedSecs);
|
||||
qint64 minutes = qRound64(time.secsTo(now) / 60.0f);
|
||||
|
||||
if (minutes == 0)
|
||||
return tr("now");
|
||||
|
||||
return QString("%1 %2").arg(formatDuration(time.secsTo(now))).arg(tr("ago"));
|
||||
}
|
||||
|
||||
void Battery::slotChanged()
|
||||
{
|
||||
if (m_device) {
|
||||
const bool old_isPresent = m_isPresent;
|
||||
const int old_chargePercent = m_chargePercent;
|
||||
const int old_capacity = m_capacity;
|
||||
const bool old_isPowerSupply = m_isPowerSupply;
|
||||
const Battery::ChargeState old_chargeState = m_chargeState;
|
||||
const qlonglong old_timeToEmpty = m_timeToEmpty;
|
||||
const qlonglong old_timeToFull = m_timeToFull;
|
||||
const double old_energy = m_energy;
|
||||
const double old_energyFull = m_energyFull;
|
||||
const double old_energyFullDesign = m_energyFullDesign;
|
||||
const double old_energyRate = m_energyRate;
|
||||
const double old_voltage = m_voltage;
|
||||
const double old_temperature = m_temperature;
|
||||
|
||||
updateCache();
|
||||
|
||||
if (old_isPresent != m_isPresent) {
|
||||
emit presentStateChanged(m_isPresent);
|
||||
}
|
||||
|
||||
if (old_chargePercent != m_chargePercent) {
|
||||
emit chargePercentChanged(m_chargePercent);
|
||||
}
|
||||
|
||||
if (old_capacity != m_capacity) {
|
||||
emit capacityChanged(m_capacity);
|
||||
}
|
||||
|
||||
if (old_isPowerSupply != m_isPowerSupply) {
|
||||
emit powerSupplyStateChanged(m_isPowerSupply);
|
||||
}
|
||||
|
||||
if (old_chargeState != m_chargeState) {
|
||||
emit chargeStateChanged(m_chargeState);
|
||||
}
|
||||
|
||||
// Save last charge percentage
|
||||
if ((old_chargeState == Battery::Charging || old_chargeState == Battery::FullyCharged) &&
|
||||
m_chargeState == Battery::Discharging) {
|
||||
m_lastChargedPercent = m_chargePercent;
|
||||
m_lastChargedSecs = QDateTime::currentSecsSinceEpoch();
|
||||
|
||||
if (m_settings) {
|
||||
m_settings->setValue("LastChargedPercent", m_lastChargedPercent);
|
||||
m_settings->setValue("LastChargedSecs", m_lastChargedSecs);
|
||||
}
|
||||
|
||||
emit lastChargedPercentChanged();
|
||||
emit lastChargedSecsChanged();
|
||||
}
|
||||
|
||||
if (old_timeToEmpty != m_timeToEmpty) {
|
||||
emit timeToEmptyChanged(m_timeToEmpty);
|
||||
}
|
||||
|
||||
if (old_timeToFull != m_timeToFull) {
|
||||
emit timeToFullChanged(m_timeToFull);
|
||||
}
|
||||
|
||||
if (old_energy != m_energy) {
|
||||
emit energyChanged(m_energy);
|
||||
}
|
||||
|
||||
if (old_energyFull != m_energyFull) {
|
||||
emit energyFullChanged(m_energyFull);
|
||||
}
|
||||
|
||||
if (old_energyFullDesign != m_energyFullDesign) {
|
||||
emit energyFullChanged(m_energyFullDesign);
|
||||
}
|
||||
|
||||
if (old_energyRate != m_energyRate) {
|
||||
emit energyRateChanged(m_energyRate);
|
||||
}
|
||||
|
||||
if (old_voltage != m_voltage) {
|
||||
emit voltageChanged(m_voltage);
|
||||
}
|
||||
|
||||
if (old_temperature != m_temperature) {
|
||||
emit temperatureChanged(m_temperature);
|
||||
}
|
||||
|
||||
if (old_timeToFull != m_timeToFull || old_timeToEmpty != m_timeToEmpty) {
|
||||
emit remainingTimeChanged(remainingTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,187 @@
|
||||
#ifndef BATTERY_H
|
||||
#define BATTERY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
#include "upowerdevice.h"
|
||||
|
||||
class Battery : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int isPresent READ isPresent)
|
||||
Q_PROPERTY(int type READ type)
|
||||
Q_PROPERTY(int chargePercent READ chargePercent NOTIFY chargePercentChanged)
|
||||
Q_PROPERTY(int capacity READ capacity NOTIFY capacityChanged)
|
||||
Q_PROPERTY(int voltage READ voltage NOTIFY voltageChanged)
|
||||
Q_PROPERTY(int isRechargeable READ isRechargeable)
|
||||
Q_PROPERTY(int isPowerSupply READ isPowerSupply)
|
||||
Q_PROPERTY(int chargeState READ chargeState NOTIFY chargeStateChanged)
|
||||
Q_PROPERTY(qlonglong remainingTime READ remainingTime NOTIFY remainingTimeChanged)
|
||||
Q_PROPERTY(QString statusString READ statusString NOTIFY remainingTimeChanged)
|
||||
Q_PROPERTY(int lastChargedPercent READ lastChargedPercent NOTIFY lastChargedPercentChanged)
|
||||
Q_PROPERTY(quint64 lastChargedSecs READ lastChargedSecs NOTIFY lastChargedSecsChanged)
|
||||
Q_PROPERTY(QString lastChargedTime READ lastChargedTime NOTIFY lastChargedSecsChanged)
|
||||
Q_PROPERTY(QString udi READ udi)
|
||||
|
||||
public:
|
||||
/**
|
||||
* This enum type defines the type of the device holding the battery
|
||||
*
|
||||
* - PdaBattery : A battery in a Personal Digital Assistant
|
||||
* - UpsBattery : A battery in an Uninterruptible Power Supply
|
||||
* - PrimaryBattery : A primary battery for the system (for example laptop battery)
|
||||
* - MouseBattery : A battery in a mouse
|
||||
* - KeyboardBattery : A battery in a keyboard
|
||||
* - KeyboardMouseBattery : A battery in a combined keyboard and mouse
|
||||
* - CameraBattery : A battery in a camera
|
||||
* - PhoneBattery : A battery in a phone
|
||||
* - MonitorBattery : A battery in a monitor
|
||||
* - GamingInputBattery : A battery in a gaming input device (for example a wireless game pad)
|
||||
* - BluetoothBattery: A generic Bluetooth device battery (if its type isn't known, a Bluetooth
|
||||
* mouse would normally show up as a MouseBattery), @since 5.54
|
||||
* - UnknownBattery : A battery in an unknown device
|
||||
*/
|
||||
enum BatteryType { UnknownBattery, PdaBattery, UpsBattery,
|
||||
PrimaryBattery, MouseBattery, KeyboardBattery,
|
||||
KeyboardMouseBattery, CameraBattery,
|
||||
PhoneBattery, MonitorBattery, GamingInputBattery,
|
||||
BluetoothBattery
|
||||
};
|
||||
Q_ENUM(BatteryType)
|
||||
|
||||
/**
|
||||
* This enum type defines charge state of a battery
|
||||
*
|
||||
* - NoCharge : Battery charge is stable, not charging or discharging or
|
||||
* the state is Unknown
|
||||
* - Charging : Battery is charging
|
||||
* - Discharging : Battery is discharging
|
||||
* - FullyCharged: The battery is fully charged; a battery not necessarily
|
||||
* charges up to 100%
|
||||
*/
|
||||
enum ChargeState { NoCharge, Charging, Discharging, FullyCharged };
|
||||
Q_ENUM(ChargeState)
|
||||
|
||||
/**
|
||||
* Technology used in the battery
|
||||
*
|
||||
* 0: Unknown
|
||||
* 1: Lithium ion
|
||||
* 2: Lithium polymer
|
||||
* 3: Lithium iron phosphate
|
||||
* 4: Lead acid
|
||||
* 5: Nickel cadmium
|
||||
* 6: Nickel metal hydride
|
||||
*/
|
||||
enum Technology { UnknownTechnology = 0, LithiumIon, LithiumPolymer, LithiumIronPhosphate,
|
||||
LeadAcid, NickelCadmium, NickelMetalHydride
|
||||
};
|
||||
Q_ENUM(Technology)
|
||||
|
||||
// Begin
|
||||
|
||||
explicit Battery(UPowerDevice *device, QObject *parent = nullptr);
|
||||
|
||||
void updateCache();
|
||||
void init();
|
||||
void refresh();
|
||||
|
||||
bool isPresent() const;
|
||||
Battery::BatteryType type() const;
|
||||
|
||||
int chargePercent() const;
|
||||
int capacity() const;
|
||||
|
||||
bool isRechargeable() const;
|
||||
|
||||
bool isPowerSupply() const;
|
||||
|
||||
Battery::ChargeState chargeState() const;
|
||||
|
||||
// Number of seconds until the power source is considered empty. Is set to 0 if unknown.
|
||||
// This property is only valid if the property type has the value "battery".
|
||||
qlonglong timeToEmpty() const;
|
||||
// Number of seconds until the power source is considered full. Is set to 0 if unknown.
|
||||
// This property is only valid if the property type has the value "battery".
|
||||
qlonglong timeToFull() const;
|
||||
|
||||
Battery::Technology technology() const;
|
||||
|
||||
double energy() const;
|
||||
|
||||
double energyFull() const;
|
||||
|
||||
double energyFullDesign() const;
|
||||
|
||||
double energyRate() const;
|
||||
|
||||
double voltage() const;
|
||||
|
||||
double temperature() const;
|
||||
|
||||
bool isRecalled() const;
|
||||
|
||||
QString recallVendor() const;
|
||||
|
||||
QString recallUrl() const;
|
||||
|
||||
QString serial() const;
|
||||
|
||||
qlonglong remainingTime() const;
|
||||
|
||||
QString formatDuration(qlonglong seconds) const;
|
||||
QString statusString() const;
|
||||
int lastChargedPercent() const;
|
||||
quint64 lastChargedSecs() const;
|
||||
|
||||
QString lastChargedTime() const;
|
||||
|
||||
QString udi() const { return m_device->udi(); }
|
||||
|
||||
signals:
|
||||
void presentStateChanged(bool newState);
|
||||
void chargePercentChanged(int value);
|
||||
void capacityChanged(int value);
|
||||
void powerSupplyStateChanged(bool newState);
|
||||
void chargeStateChanged(int newState);
|
||||
void timeToEmptyChanged(qlonglong time);
|
||||
void timeToFullChanged(qlonglong time);
|
||||
void energyChanged(double energy);
|
||||
void energyFullChanged(double energyFull);
|
||||
void energyFullDesignChanged(double energyFullDesign);
|
||||
void energyRateChanged(double energyRate);
|
||||
void voltageChanged(double voltage);
|
||||
void temperatureChanged(double temperature);
|
||||
void remainingTimeChanged(qlonglong time);
|
||||
void lastChargedPercentChanged();
|
||||
void lastChargedSecsChanged();
|
||||
|
||||
private slots:
|
||||
void slotChanged();
|
||||
|
||||
private:
|
||||
UPowerDevice *m_device;
|
||||
|
||||
bool m_isPresent;
|
||||
int m_chargePercent;
|
||||
int m_capacity;
|
||||
bool m_isPowerSupply;
|
||||
Battery::ChargeState m_chargeState;
|
||||
qlonglong m_timeToEmpty;
|
||||
qlonglong m_timeToFull;
|
||||
double m_energy;
|
||||
double m_energyFull;
|
||||
double m_energyFullDesign;
|
||||
double m_energyRate;
|
||||
double m_voltage;
|
||||
double m_temperature;
|
||||
|
||||
QSettings *m_settings;
|
||||
int m_lastChargedPercent;
|
||||
quint64 m_lastChargedSecs;
|
||||
|
||||
// QTimer m_refreshTimer;
|
||||
};
|
||||
|
||||
#endif // BATTERY_H
|
||||
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.cutefish.PrimaryBattery">
|
||||
<method name="refresh"></method>
|
||||
|
||||
<property name="chargeState" type="i" access="read"/>
|
||||
<property name="chargePercent" type="i" access="read"/>
|
||||
<property name="capacity" type="i" access="read"/>
|
||||
<property name="voltage" type="d" access="read"/>
|
||||
<property name="remainingTime" type="x" access="read"/>
|
||||
<property name="statusString" type="s" access="read"/>
|
||||
<property name="lastChargedPercent" type="i" access="read"/>
|
||||
<property name="lastChargedSecs" type="x" access="read"/>
|
||||
<property name="lastChargedTime" type="s" access="read"/>
|
||||
<property name="udi" type="s" access="read"/>
|
||||
|
||||
<signal name="chargeStateChanged">
|
||||
<arg name="value" type="i"/>
|
||||
</signal>
|
||||
<signal name="chargePercentChanged">
|
||||
<arg name="value" type="i"/>
|
||||
</signal>
|
||||
<signal name="capacityChanged">
|
||||
<arg name="value" type="i"/>
|
||||
</signal>
|
||||
<signal name="voltageChanged">
|
||||
<arg name="value" type="d"/>
|
||||
</signal>
|
||||
<signal name="remainingTimeChanged">
|
||||
<arg name="value" type="x"/>
|
||||
</signal>
|
||||
<signal name="lastChargedPercentChanged">
|
||||
</signal>
|
||||
<signal name="lastChargedSecsChanged">
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,28 @@
|
||||
#ifndef POWER_H
|
||||
#define POWER_H
|
||||
|
||||
/* UPower */
|
||||
#define UP_DBUS_SERVICE "org.freedesktop.UPower"
|
||||
#define UP_DBUS_PATH "/org/freedesktop/UPower"
|
||||
#define UP_DBUS_INTERFACE "org.freedesktop.UPower"
|
||||
#define UP_DBUS_INTERFACE_DEVICE UP_DBUS_INTERFACE ".Device"
|
||||
#define UP_UDI_PREFIX "/org/freedesktop/UPower"
|
||||
|
||||
typedef enum {
|
||||
UP_DEVICE_KIND_UNKNOWN,
|
||||
UP_DEVICE_KIND_LINE_POWER,
|
||||
UP_DEVICE_KIND_BATTERY,
|
||||
UP_DEVICE_KIND_UPS,
|
||||
UP_DEVICE_KIND_MONITOR,
|
||||
UP_DEVICE_KIND_MOUSE,
|
||||
UP_DEVICE_KIND_KEYBOARD,
|
||||
UP_DEVICE_KIND_PDA,
|
||||
UP_DEVICE_KIND_PHONE,
|
||||
UP_DEVICE_KIND_MEDIA_PLAYER,
|
||||
UP_DEVICE_KIND_TABLET,
|
||||
UP_DEVICE_KIND_COMPUTER,
|
||||
UP_DEVICE_KIND_GAMING_INPUT,
|
||||
UP_DEVICE_KIND_LAST
|
||||
} UpDeviceKind;
|
||||
|
||||
#endif // POWER_H
|
||||
@ -0,0 +1,196 @@
|
||||
#include "upowerdevice.h"
|
||||
#include "power.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QDBusReply>
|
||||
|
||||
UPowerDevice::UPowerDevice(const QString &udi, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_device(UP_DBUS_SERVICE,
|
||||
udi,
|
||||
UP_DBUS_INTERFACE_DEVICE,
|
||||
QDBusConnection::systemBus())
|
||||
, m_udi(udi)
|
||||
{
|
||||
if (m_device.isValid()) {
|
||||
if (m_device.metaObject()->indexOfSignal("Changed()") != -1) {
|
||||
connect(&m_device, SIGNAL(Changed()), this, SLOT(slotChanged()));
|
||||
} else {
|
||||
// for UPower >= 0.99.0, missing Changed() signal
|
||||
QDBusConnection::systemBus().connect(UP_DBUS_SERVICE, m_udi, "org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged", this,
|
||||
SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
|
||||
}
|
||||
|
||||
// TODO port this to Solid::Power, we can't link against kdelibs4support for this signal
|
||||
// older upower versions not affected
|
||||
QDBusConnection::systemBus().connect("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForSleep",
|
||||
this, SLOT(login1Resuming(bool)));
|
||||
}
|
||||
}
|
||||
|
||||
bool UPowerDevice::queryDeviceInterface(UPowerDevice::Type type) const
|
||||
{
|
||||
const uint uptype = prop("Type").toUInt();
|
||||
switch (type) {
|
||||
case GenericInterface:
|
||||
return true;
|
||||
case Battery:
|
||||
switch (uptype) {
|
||||
case UP_DEVICE_KIND_BATTERY:
|
||||
case UP_DEVICE_KIND_UPS:
|
||||
case UP_DEVICE_KIND_MOUSE:
|
||||
case UP_DEVICE_KIND_KEYBOARD:
|
||||
case UP_DEVICE_KIND_PDA:
|
||||
case UP_DEVICE_KIND_PHONE:
|
||||
case UP_DEVICE_KIND_GAMING_INPUT:
|
||||
return true;
|
||||
case UP_DEVICE_KIND_UNKNOWN:
|
||||
// There is currently no "Bluetooth battery" type, so check if it comes from Bluez
|
||||
if (prop("NativePath").toString().startsWith(QLatin1String("/org/bluez/"))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case UP_DEVICE_KIND_LINE_POWER:
|
||||
case UP_DEVICE_KIND_MONITOR:
|
||||
case UP_DEVICE_KIND_MEDIA_PLAYER:
|
||||
case UP_DEVICE_KIND_TABLET:
|
||||
case UP_DEVICE_KIND_COMPUTER:
|
||||
case UP_DEVICE_KIND_LAST:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString UPowerDevice::description() const
|
||||
{
|
||||
if (queryDeviceInterface(Battery)) {
|
||||
return tr("%1 Battery", "%1 is battery technology").arg(batteryTechnology());
|
||||
} else {
|
||||
QString result = prop("Model").toString();
|
||||
if (result.isEmpty()) {
|
||||
return vendor();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
QString UPowerDevice::batteryTechnology() const
|
||||
{
|
||||
const uint tech = prop("Technology").toUInt();
|
||||
|
||||
switch (tech) {
|
||||
case 1:
|
||||
return tr("Lithium-ion", "battery technology");
|
||||
case 2:
|
||||
return tr("Lithium Polymer", "battery technology");
|
||||
case 3:
|
||||
return tr("Lithium Iron Phosphate", "battery technology");
|
||||
case 4:
|
||||
return tr("Lead Acid", "battery technology");
|
||||
case 5:
|
||||
return tr("Nickel Cadmium", "battery technology");
|
||||
case 6:
|
||||
return tr("Nickel Metal Hydride", "battery technology");
|
||||
default:
|
||||
return tr("Unknown", "battery technology");
|
||||
}
|
||||
}
|
||||
|
||||
QString UPowerDevice::product() const
|
||||
{
|
||||
QString result = prop("Model").toString();
|
||||
|
||||
if (result.isEmpty()) {
|
||||
result = description();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString UPowerDevice::vendor() const
|
||||
{
|
||||
return prop("Vendor").toString();
|
||||
}
|
||||
|
||||
QString UPowerDevice::udi() const
|
||||
{
|
||||
return m_udi;
|
||||
}
|
||||
|
||||
QVariant UPowerDevice::prop(const QString &key) const
|
||||
{
|
||||
checkCache(key);
|
||||
return m_cache.value(key);
|
||||
}
|
||||
|
||||
bool UPowerDevice::propertyExists(const QString &key) const
|
||||
{
|
||||
checkCache(key);
|
||||
return m_cache.contains(key);
|
||||
}
|
||||
|
||||
QMap<QString, QVariant> UPowerDevice::allProperties() const
|
||||
{
|
||||
QDBusMessage call = QDBusMessage::createMethodCall(m_device.service(), m_device.path(),
|
||||
"org.freedesktop.DBus.Properties", "GetAll");
|
||||
call << m_device.interface();
|
||||
QDBusPendingReply< QVariantMap > reply = QDBusConnection::systemBus().asyncCall(call);
|
||||
reply.waitForFinished();
|
||||
|
||||
if (reply.isValid()) {
|
||||
m_cache = reply.value();
|
||||
} else {
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
return m_cache;
|
||||
}
|
||||
|
||||
void UPowerDevice::onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps)
|
||||
{
|
||||
Q_UNUSED(changedProps);
|
||||
Q_UNUSED(invalidatedProps);
|
||||
|
||||
if (ifaceName == UP_DBUS_INTERFACE_DEVICE) {
|
||||
slotChanged(); // TODO maybe process the properties separately?
|
||||
}
|
||||
}
|
||||
|
||||
void UPowerDevice::login1Resuming(bool active)
|
||||
{
|
||||
if (!active) {
|
||||
QDBusReply<void> refreshCall = m_device.asyncCall("Refresh");
|
||||
if (refreshCall.isValid()) {
|
||||
slotChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UPowerDevice::slotChanged()
|
||||
{
|
||||
m_cache.clear();
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void UPowerDevice::checkCache(const QString &key) const
|
||||
{
|
||||
if (m_cache.isEmpty()) { // recreate the cache
|
||||
allProperties();
|
||||
}
|
||||
|
||||
if (m_cache.contains(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant reply = m_device.property(key.toUtf8());
|
||||
|
||||
if (reply.isValid()) {
|
||||
m_cache[key] = reply;
|
||||
} else {
|
||||
m_cache[key] = QVariant();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
#ifndef UPOWERDEVICE_H
|
||||
#define UPOWERDEVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
|
||||
class UPowerDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Type { Unknown = 0, GenericInterface = 1, Processor = 2,
|
||||
Block = 3, StorageAccess = 4, StorageDrive = 5,
|
||||
OpticalDrive = 6, StorageVolume = 7, OpticalDisc = 8,
|
||||
Camera = 9, PortableMediaPlayer = 10,
|
||||
Battery = 12, NetworkShare = 14, Last = 0xffff
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
explicit UPowerDevice(const QString &udi, QObject *parent = nullptr);
|
||||
|
||||
bool queryDeviceInterface(Type type) const;
|
||||
QString description() const;
|
||||
QString batteryTechnology() const;
|
||||
QString product() const;
|
||||
QString vendor() const;
|
||||
|
||||
QString udi() const;
|
||||
|
||||
QVariant prop(const QString &key) const;
|
||||
bool propertyExists(const QString &key) const;
|
||||
QMap<QString, QVariant> allProperties() const;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private slots:
|
||||
void onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps);
|
||||
void login1Resuming(bool active);
|
||||
void slotChanged();
|
||||
|
||||
private:
|
||||
void checkCache(const QString &key) const;
|
||||
|
||||
private:
|
||||
mutable QDBusInterface m_device;
|
||||
mutable QVariantMap m_cache;
|
||||
|
||||
QString m_udi;
|
||||
};
|
||||
|
||||
#endif // UPOWERDEVICE_H
|
||||
@ -0,0 +1,115 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2020 Reven Martin <revenmartin@gmail.com>
|
||||
SPDX-FileCopyrightText: 2010 Michael Zanetti <mzanetti@kde.org>
|
||||
SPDX-FileCopyrightText: 2010 Lukas Tinkl <ltinkl@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "upowermanager.h"
|
||||
#include "upowerdevice.h"
|
||||
#include "battery.h"
|
||||
#include "power.h"
|
||||
|
||||
#include <QDBusReply>
|
||||
#include <QDebug>
|
||||
#include <QDBusMetaType>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
UPowerManager::UPowerManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_interface(UP_DBUS_SERVICE,
|
||||
UP_DBUS_PATH,
|
||||
UP_DBUS_INTERFACE,
|
||||
QDBusConnection::systemBus())
|
||||
, m_onBattery(false)
|
||||
{
|
||||
qDBusRegisterMetaType<QList<QDBusObjectPath>>();
|
||||
qDBusRegisterMetaType<QVariantMap>();
|
||||
|
||||
bool serviceFound = m_interface.isValid();
|
||||
if (!serviceFound) {
|
||||
// find out whether it will be activated automatically
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"ListActivatableNames");
|
||||
|
||||
QDBusReply<QStringList> reply = QDBusConnection::systemBus().call(message);
|
||||
if (reply.isValid() && reply.value().contains(UP_DBUS_SERVICE)) {
|
||||
QDBusConnection::systemBus().interface()->startService(UP_DBUS_SERVICE);
|
||||
serviceFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceFound) {
|
||||
if (m_interface.metaObject()->indexOfSignal("DeviceAdded(QDBusObjectPath)") != -1) {
|
||||
// for UPower >= 0.99.0, changed signature :o/
|
||||
connect(&m_interface, SIGNAL(DeviceAdded(QDBusObjectPath)),
|
||||
this, SLOT(onDeviceAdded(QDBusObjectPath)));
|
||||
connect(&m_interface, SIGNAL(DeviceRemoved(QDBusObjectPath)),
|
||||
this, SLOT(onDeviceRemoved(QDBusObjectPath)));
|
||||
} else {
|
||||
connect(&m_interface, SIGNAL(DeviceAdded(QString)),
|
||||
this, SIGNAL(deviceAdded(QString)));
|
||||
connect(&m_interface, SIGNAL(DeviceRemoved(QString)),
|
||||
this, SIGNAL(deviceRemoved(QString)));
|
||||
}
|
||||
|
||||
// On battery
|
||||
QDBusConnection::systemBus().connect(UP_DBUS_SERVICE, UP_DBUS_PATH,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged", this,
|
||||
SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
|
||||
m_onBattery = m_interface.property("OnBattery").toBool();
|
||||
|
||||
// All devices
|
||||
QDBusReply<QList<QDBusObjectPath>> reply = m_interface.call("EnumerateDevices");
|
||||
if (!reply.isValid()) {
|
||||
qWarning() << Q_FUNC_INFO << " error: " << reply.error().name();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto pathList = reply.value();
|
||||
for (const QDBusObjectPath &path : pathList) {
|
||||
UPowerDevice *device = new UPowerDevice(path.path());
|
||||
Battery *battery = new Battery(device);
|
||||
|
||||
if (battery->type() != Battery::PrimaryBattery) {
|
||||
device->deleteLater();
|
||||
battery->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString UPowerManager::udiPrefix() const
|
||||
{
|
||||
return UP_UDI_PREFIX;
|
||||
}
|
||||
|
||||
bool UPowerManager::onBattery() const
|
||||
{
|
||||
return m_onBattery;
|
||||
}
|
||||
|
||||
void UPowerManager::onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps)
|
||||
{
|
||||
Q_UNUSED(ifaceName);
|
||||
Q_UNUSED(changedProps);
|
||||
Q_UNUSED(invalidatedProps);
|
||||
|
||||
const bool onBattery = m_interface.property("OnBattery").toBool();
|
||||
m_onBattery = onBattery;
|
||||
emit onBatteryChanged();
|
||||
}
|
||||
|
||||
void UPowerManager::onDeviceAdded(const QDBusObjectPath &path)
|
||||
{
|
||||
qDebug() << "onDeviceAdded()" << path.path();
|
||||
}
|
||||
|
||||
void UPowerManager::onDeviceRemoved(const QDBusObjectPath &path)
|
||||
{
|
||||
qDebug() << "onDeviceRemoved()" << path.path();
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2020 Reven Martin <revenmartin@gmail.com>
|
||||
SPDX-FileCopyrightText: 2010 Michael Zanetti <mzanetti@kde.org>
|
||||
SPDX-FileCopyrightText: 2010 Lukas Tinkl <ltinkl@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#ifndef UPOWERMANAGER_H
|
||||
#define UPOWERMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
|
||||
class UPowerDevice;
|
||||
class Battery;
|
||||
class UPowerManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UPowerManager(QObject *parent = nullptr);
|
||||
|
||||
QString udiPrefix() const;
|
||||
|
||||
bool onBattery() const;
|
||||
|
||||
signals:
|
||||
void onBatteryChanged();
|
||||
|
||||
private slots:
|
||||
void onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps);
|
||||
void onDeviceAdded(const QDBusObjectPath &path);
|
||||
void onDeviceRemoved(const QDBusObjectPath &path);
|
||||
|
||||
private:
|
||||
QDBusInterface m_interface;
|
||||
bool m_onBattery;
|
||||
};
|
||||
|
||||
#endif // UPOWERMANAGER_H
|
||||
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: rekols <rekols@foxmail.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 3 of the License, or
|
||||
* 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 "brightnessmanager.h"
|
||||
#include "brightnessadaptor.h"
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define PREFIX "/sys/class/backlight/"
|
||||
|
||||
BrightnessManager::BrightnessManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_fileWatcher(new QFileSystemWatcher(this))
|
||||
{
|
||||
// init dbus
|
||||
new BrightnessAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Brightness"), this);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
BrightnessManager::~BrightnessManager()
|
||||
{
|
||||
}
|
||||
|
||||
int BrightnessManager::maxBrightness()
|
||||
{
|
||||
int max_brightness;
|
||||
QFile file(m_dirname + "/max_brightness");
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "reading max brightness failed with error code " << file.error() << file.errorString();
|
||||
return -1; // some non-zero value
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
stream >> max_brightness;
|
||||
file.close();
|
||||
|
||||
return max_brightness ? max_brightness : -1;
|
||||
}
|
||||
|
||||
int BrightnessManager::brightness()
|
||||
{
|
||||
QFile file(m_dirname + "/brightness");
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int brightness;
|
||||
QTextStream stream(&file);
|
||||
stream >> brightness;
|
||||
file.close();
|
||||
|
||||
return brightness * 100 / maxBrightness();
|
||||
}
|
||||
|
||||
void BrightnessManager::setValue(int value)
|
||||
{
|
||||
QProcess process;
|
||||
process.start("pkexec", QStringList() << "cutefish-screen-brightness" << "--set" << QString::number(value));
|
||||
process.waitForFinished(-1);
|
||||
}
|
||||
|
||||
void BrightnessManager::init()
|
||||
{
|
||||
if (useWhitelistInit())
|
||||
initUsingWhitelist();
|
||||
else
|
||||
initUsingBacklightType();
|
||||
|
||||
if (!m_dirname.isEmpty()) {
|
||||
m_fileWatcher->addPath(m_dirname + "/actual_brightness");
|
||||
m_fileWatcher->addPath(m_dirname + "/brightness");
|
||||
m_fileWatcher->addPath(m_dirname + "/bl_power");
|
||||
m_actualBacklight = brightness();
|
||||
connect(m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &BrightnessManager::handleFileChanged);
|
||||
}
|
||||
}
|
||||
|
||||
bool BrightnessManager::useWhitelistInit()
|
||||
{
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
|
||||
int major, minor, patch, result;
|
||||
result = sscanf(uts.release, "%d.%d", &major, &minor);
|
||||
|
||||
if (result != 2) {
|
||||
return true; // Malformed version
|
||||
}
|
||||
|
||||
if (major == 3) {
|
||||
return false; //Kernel 3, we want type based init
|
||||
}
|
||||
|
||||
result = sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch);
|
||||
|
||||
if (result != 3) {
|
||||
return true; // Malformed version
|
||||
}
|
||||
|
||||
if (patch < 37) {
|
||||
return true; //Minor than 2.6.37, use whiteList based
|
||||
}
|
||||
|
||||
return false;//Use Type based interafce
|
||||
}
|
||||
|
||||
void BrightnessManager::initUsingWhitelist()
|
||||
{
|
||||
QStringList interfaces;
|
||||
interfaces << "nv_backlight" << "radeon_bl" << "mbp_backlight" << "asus_laptop"
|
||||
<< "toshiba" << "eeepc" << "thinkpad_screen" << "acpi_video1" << "acpi_video0"
|
||||
<< "intel_backlight" << "apple_backlight" << "fujitsu-laptop" << "samsung"
|
||||
<< "nvidia_backlight" << "dell_backlight" << "sony" << "pwm-backlight";
|
||||
|
||||
QDir dir;
|
||||
foreach (const QString & interface, interfaces) {
|
||||
dir.setPath(PREFIX + interface);
|
||||
//qDebug() << "searching dir:" << dir;
|
||||
if (dir.exists()) {
|
||||
m_dirname = dir.path();
|
||||
//qDebug() << "kernel backlight support found in" << m_dirname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//If none of our whitelisted interface is available, get the first one (if any)
|
||||
if (m_dirname.isEmpty()) {
|
||||
dir.setPath(PREFIX);
|
||||
dir.setFilter(QDir::AllDirs | QDir::NoDot | QDir::NoDotDot | QDir::NoDotAndDotDot | QDir::Readable);
|
||||
QStringList dirList = dir.entryList();
|
||||
if (!dirList.isEmpty()) {
|
||||
m_dirname = dirList.first();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BrightnessManager::initUsingBacklightType()
|
||||
{
|
||||
QString m_dirname;
|
||||
QDir dir(PREFIX);
|
||||
dir.setFilter(QDir::AllDirs | QDir::NoDot | QDir::NoDotDot | QDir::NoDotAndDotDot | QDir::Readable);
|
||||
dir.setSorting(QDir::Name | QDir::Reversed);// Reverse is needed to priorize acpi_video1 over 0
|
||||
|
||||
QStringList interfaces = dir.entryList();
|
||||
|
||||
if (interfaces.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file;
|
||||
QByteArray buffer;
|
||||
QStringList firmware, platform, raw;
|
||||
|
||||
foreach(const QString & interface, interfaces) {
|
||||
file.setFileName(PREFIX + interface + "/type");
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer = file.readLine().trimmed();
|
||||
if (buffer == "firmware") {
|
||||
firmware.append(interface);
|
||||
} else if(buffer == "platform") {
|
||||
platform.append(interface);
|
||||
} else if (buffer == "raw") {
|
||||
raw.append(interface);
|
||||
} else {
|
||||
qWarning() << "Interface type not handled" << buffer;
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
if (!firmware.isEmpty()) {
|
||||
m_dirname = PREFIX + firmware.first();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!platform.isEmpty()) {
|
||||
m_dirname = PREFIX + platform.first();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!raw.isEmpty()) {
|
||||
m_dirname = PREFIX + raw.first();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BrightnessManager::handleFileChanged(const QString &path)
|
||||
{
|
||||
Q_UNUSED(path);
|
||||
|
||||
int newValue = brightness();
|
||||
|
||||
if (m_actualBacklight != newValue) {
|
||||
m_actualBacklight = newValue;
|
||||
Q_EMIT brightnessChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool BrightnessManager::brightnessEnabled()
|
||||
{
|
||||
QDir dir;
|
||||
dir.setPath(PREFIX);
|
||||
dir.setFilter(QDir::AllDirs | QDir::NoDot | QDir::NoDotDot | QDir::NoDotAndDotDot | QDir::Readable);
|
||||
QStringList dirList = dir.entryList();
|
||||
return !dirList.isEmpty();
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: rekols <rekols@foxmail.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 3 of the License, or
|
||||
* 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 BRIGHTNESSMANAGER_H
|
||||
#define BRIGHTNESSMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
class BrightnessManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool brightnessEnabled READ brightnessEnabled)
|
||||
Q_PROPERTY(int maxBrightness READ maxBrightness)
|
||||
Q_PROPERTY(int brightness READ brightness WRITE setValue)
|
||||
|
||||
public:
|
||||
BrightnessManager(QObject *parent = nullptr);
|
||||
~BrightnessManager();
|
||||
|
||||
int maxBrightness();
|
||||
int brightness();
|
||||
bool brightnessEnabled();
|
||||
|
||||
void setValue(int value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void brightnessChanged();
|
||||
|
||||
private:
|
||||
void init();
|
||||
bool useWhitelistInit();
|
||||
void initUsingWhitelist();
|
||||
void initUsingBacklightType();
|
||||
|
||||
private slots:
|
||||
void handleFileChanged(const QString &path);
|
||||
|
||||
private:
|
||||
QFileSystemWatcher *m_fileWatcher;
|
||||
int m_actualBacklight;
|
||||
QString m_dirname;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.cutefish.Brightness">
|
||||
<method name="setValue">
|
||||
<arg name="value" type="i" direction="in"/>
|
||||
</method>
|
||||
|
||||
<property name="maxBrightness" type="i" access="read"/>
|
||||
<property name="brightness" type="i" access="read"/>
|
||||
<property name="brightnessEnabled" type="b" access="read"/>
|
||||
|
||||
<signal name="brightnessChanged"></signal>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 DBUSADAPTOR_H
|
||||
#define DBUSADAPTOR_H
|
||||
|
||||
#include <QtDBus>
|
||||
#include "application.h"
|
||||
|
||||
class DBusAdaptor : public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.panda.settings")
|
||||
|
||||
public:
|
||||
DBusAdaptor(Application *app)
|
||||
: QDBusAbstractAdaptor(app),
|
||||
m_app(app)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
Application *m_app;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 "language.h"
|
||||
#include "languageadaptor.h"
|
||||
|
||||
Language::Language(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_settings(new QSettings(QStringLiteral("cutefishos"), QStringLiteral("language")))
|
||||
{
|
||||
new LanguageAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Language"), this);
|
||||
|
||||
if (!m_settings->contains("language"))
|
||||
m_settings->setValue("language", "en_US");
|
||||
|
||||
emit languageChanged();
|
||||
}
|
||||
|
||||
QString Language::languageCode() const
|
||||
{
|
||||
return m_settings->value("language").toString();
|
||||
}
|
||||
|
||||
void Language::setLanguage(const QString &code)
|
||||
{
|
||||
m_settings->setValue("language", code);
|
||||
|
||||
emit languageChanged();
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 LANGUAGE_H
|
||||
#define LANGUAGE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
|
||||
class Language : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString languageCode READ languageCode WRITE setLanguage NOTIFY languageChanged)
|
||||
|
||||
public:
|
||||
Language(QObject *parent = nullptr);
|
||||
|
||||
QString languageCode() const;
|
||||
void setLanguage(const QString &code);
|
||||
|
||||
signals:
|
||||
void languageChanged();
|
||||
|
||||
private:
|
||||
QSettings *m_settings;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.cutefish.Language">
|
||||
<method name="setLanguage">
|
||||
<arg name="value" type="s" direction="in"/>
|
||||
</method>
|
||||
|
||||
<property name="languageCode" type="s" access="read"/>
|
||||
|
||||
<signal name="languageChanged"></signal>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 "application.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Application a(argc, argv);
|
||||
a.setQuitOnLastWindowClosed(false);
|
||||
return a.exec();
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.cutefish.Theme">
|
||||
<method name="setDarkMode">
|
||||
<arg name="darkMode" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="setDarkModeDimsWallpaer">
|
||||
<arg name="darkModeDimsWallpaer" type="b" direction="in"/>
|
||||
</method>
|
||||
<method name="setSystemFont">
|
||||
<arg name="fontFamily" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="setSystemFixedFont">
|
||||
<arg name="fontFamily" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="setSystemFontPointSize">
|
||||
<arg name="fontSize" type="d" direction="in"/>
|
||||
</method>
|
||||
<method name="setDevicePixelRatio">
|
||||
<arg name="ratio" type="d" direction="in"/>
|
||||
</method>
|
||||
<method name="setWallpaper">
|
||||
<arg name="path" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="setAccentColor">
|
||||
<arg name="accentColor" type="i" direction="in"/>
|
||||
</method>
|
||||
|
||||
<property name="isDarkMode" type="b" access="read"/>
|
||||
<property name="darkModeDimsWallpaer" type="b" access="read"/>
|
||||
<property name="systemFont" type="s" access="read"/>
|
||||
<property name="systemFixedFont" type="s" access="read"/>
|
||||
<property name="systemFontPointSize" type="d" access="read"/>
|
||||
<property name="devicePixelRatio" type="d" access="read"/>
|
||||
<property name="wallpaper" type="s" access="read"/>
|
||||
<property name="accentColor" type="i" access="read"/>
|
||||
|
||||
<signal name="darkModeChanged">
|
||||
<arg type="b"/>
|
||||
</signal>
|
||||
<signal name="wallpaperChanged">
|
||||
<arg type="s"/>
|
||||
</signal>
|
||||
<signal name="darkModeDimsWallpaerChanged">
|
||||
</signal>
|
||||
<signal name="accentColorChanged">
|
||||
<arg type="i"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 "thememanager.h"
|
||||
#include "themeadaptor.h"
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
static const QByteArray s_systemFontName = QByteArrayLiteral("Font");
|
||||
static const QByteArray s_systemFixedFontName = QByteArrayLiteral("FixedFont");
|
||||
static const QByteArray s_systemPointFontSize = QByteArrayLiteral("FontSize");
|
||||
static const QByteArray s_devicePixelRatio = QByteArrayLiteral("PixelRatio");
|
||||
|
||||
static QString gtkRc2Path()
|
||||
{
|
||||
return QDir::homePath() + QLatin1String("/.gtkrc-2.0");
|
||||
}
|
||||
|
||||
static QString gtk3SettingsIniPath()
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/gtk-3.0/settings.ini");
|
||||
}
|
||||
|
||||
ThemeManager::ThemeManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_settings(new QSettings(QStringLiteral("cutefishos"), QStringLiteral("theme")))
|
||||
{
|
||||
if (!QFile::exists(m_settings->fileName())) {
|
||||
QFile file(m_settings->fileName());
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
in << "";
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
// init dbus
|
||||
new ThemeAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Theme"), this);
|
||||
|
||||
// init value
|
||||
m_isDarkMode = m_settings->value("DarkMode", false).toBool();
|
||||
m_darkModeDimsWallpaer = m_settings->value("DarkModeDimsWallpaer", false).toBool();
|
||||
m_wallpaperPath = m_settings->value("Wallpaper", "/usr/share/backgrounds/cutefishos/unsplash-12.jpg").toString();
|
||||
m_accentColor = m_settings->value("AccentColor", 0).toInt();
|
||||
|
||||
// Start the DE and need to update the settings again.
|
||||
initGtkConfig();
|
||||
}
|
||||
|
||||
bool ThemeManager::isDarkMode()
|
||||
{
|
||||
return m_isDarkMode;
|
||||
}
|
||||
|
||||
void ThemeManager::setDarkMode(bool darkMode)
|
||||
{
|
||||
if (darkMode == m_isDarkMode)
|
||||
return;
|
||||
|
||||
m_isDarkMode = darkMode;
|
||||
m_settings->setValue("DarkMode", darkMode);
|
||||
|
||||
updateGtkDarkTheme();
|
||||
|
||||
emit darkModeChanged(m_isDarkMode);
|
||||
}
|
||||
|
||||
bool ThemeManager::darkModeDimsWallpaer() const
|
||||
{
|
||||
return m_darkModeDimsWallpaer;
|
||||
}
|
||||
|
||||
void ThemeManager::setDarkModeDimsWallpaer(bool value)
|
||||
{
|
||||
if (m_darkModeDimsWallpaer == value)
|
||||
return;
|
||||
|
||||
m_darkModeDimsWallpaer = value;
|
||||
m_settings->setValue("DarkModeDimsWallpaer", m_darkModeDimsWallpaer);
|
||||
|
||||
emit darkModeDimsWallpaerChanged();
|
||||
}
|
||||
|
||||
int ThemeManager::accentColor()
|
||||
{
|
||||
return m_settings->value("AccentColor", 0).toInt();
|
||||
}
|
||||
|
||||
void ThemeManager::setAccentColor(int accentColor)
|
||||
{
|
||||
if (m_accentColor == accentColor)
|
||||
return;
|
||||
|
||||
m_accentColor = accentColor;
|
||||
m_settings->setValue("AccentColor", m_accentColor);
|
||||
|
||||
emit accentColorChanged(m_accentColor);
|
||||
}
|
||||
|
||||
QString ThemeManager::systemFont()
|
||||
{
|
||||
return m_settings->value(s_systemFontName, "Noto Sans").toString();
|
||||
}
|
||||
|
||||
void ThemeManager::setSystemFont(const QString &fontFamily)
|
||||
{
|
||||
m_settings->setValue(s_systemFontName, fontFamily);
|
||||
updateGtkFont();
|
||||
}
|
||||
|
||||
QString ThemeManager::systemFixedFont()
|
||||
{
|
||||
return m_settings->value(s_systemFixedFontName, "Monospace").toString();
|
||||
}
|
||||
|
||||
void ThemeManager::setSystemFixedFont(const QString &fontFamily)
|
||||
{
|
||||
m_settings->setValue(s_systemFixedFontName, fontFamily);
|
||||
}
|
||||
|
||||
qreal ThemeManager::systemFontPointSize()
|
||||
{
|
||||
return m_settings->value(s_systemPointFontSize, 10.5).toReal();
|
||||
}
|
||||
|
||||
void ThemeManager::setSystemFontPointSize(qreal fontSize)
|
||||
{
|
||||
m_settings->setValue(s_systemPointFontSize, fontSize);
|
||||
updateGtkFont();
|
||||
}
|
||||
|
||||
qreal ThemeManager::devicePixelRatio()
|
||||
{
|
||||
return m_settings->value(s_devicePixelRatio, 1.0).toReal();
|
||||
}
|
||||
|
||||
void ThemeManager::setDevicePixelRatio(qreal ratio)
|
||||
{
|
||||
m_settings->setValue(s_devicePixelRatio, ratio);
|
||||
}
|
||||
|
||||
QString ThemeManager::wallpaper()
|
||||
{
|
||||
return m_wallpaperPath;
|
||||
}
|
||||
|
||||
void ThemeManager::setWallpaper(const QString &path)
|
||||
{
|
||||
if (m_wallpaperPath != path) {
|
||||
m_wallpaperPath = path;
|
||||
m_settings->setValue("Wallpaper", path);
|
||||
emit wallpaperChanged(path);
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeManager::initGtkConfig()
|
||||
{
|
||||
QSettings settings(gtk3SettingsIniPath(), QSettings::IniFormat);
|
||||
settings.clear();
|
||||
settings.setIniCodec("UTF-8");
|
||||
settings.beginGroup("Settings");
|
||||
// font
|
||||
settings.setValue("gtk-font-name", QString("%1 %2").arg(systemFont()).arg(systemFontPointSize()));
|
||||
// dark mode
|
||||
settings.setValue("gtk-application-prefer-dark-theme", isDarkMode());
|
||||
// other
|
||||
settings.setValue("gtk-enable-animations", true);
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
void ThemeManager::updateGtkFont()
|
||||
{
|
||||
QSettings settings(gtk3SettingsIniPath(), QSettings::IniFormat);
|
||||
settings.setIniCodec("UTF-8");
|
||||
settings.beginGroup("Settings");
|
||||
settings.setValue("gtk-font-name", QString("%1 %2").arg(systemFont()).arg(systemFontPointSize()));
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
void ThemeManager::updateGtkDarkTheme()
|
||||
{
|
||||
QSettings settings(gtk3SettingsIniPath(), QSettings::IniFormat);
|
||||
settings.setIniCodec("UTF-8");
|
||||
settings.beginGroup("Settings");
|
||||
settings.setValue("gtk-application-prefer-dark-theme", isDarkMode());
|
||||
settings.sync();
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: revenmartin <revenmartin@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 3 of the License, or
|
||||
* 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 THEMEMANAGER_H
|
||||
#define THEMEMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
|
||||
class ThemeManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isDarkMode READ isDarkMode WRITE setDarkMode NOTIFY darkModeChanged)
|
||||
Q_PROPERTY(bool darkModeDimsWallpaer READ darkModeDimsWallpaer WRITE setDarkModeDimsWallpaer NOTIFY darkModeDimsWallpaerChanged)
|
||||
Q_PROPERTY(QString systemFont READ systemFont WRITE setSystemFont)
|
||||
Q_PROPERTY(QString systemFixedFont READ systemFixedFont WRITE setSystemFixedFont)
|
||||
Q_PROPERTY(qreal systemFontPointSize READ systemFontPointSize WRITE setSystemFontPointSize)
|
||||
Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio)
|
||||
Q_PROPERTY(QString wallpaper READ wallpaper WRITE setWallpaper NOTIFY wallpaperChanged)
|
||||
Q_PROPERTY(int accentColor READ accentColor WRITE setAccentColor NOTIFY accentColorChanged)
|
||||
|
||||
public:
|
||||
ThemeManager(QObject *parent = nullptr);
|
||||
|
||||
bool isDarkMode();
|
||||
void setDarkMode(bool darkMode);
|
||||
|
||||
bool darkModeDimsWallpaer() const;
|
||||
void setDarkModeDimsWallpaer(bool value);
|
||||
|
||||
QString systemFont();
|
||||
void setSystemFont(const QString &fontFamily);
|
||||
|
||||
QString systemFixedFont();
|
||||
void setSystemFixedFont(const QString &fontFamily);
|
||||
|
||||
qreal systemFontPointSize();
|
||||
void setSystemFontPointSize(qreal fontSize);
|
||||
|
||||
qreal devicePixelRatio();
|
||||
void setDevicePixelRatio(qreal ratio);
|
||||
|
||||
QString wallpaper();
|
||||
void setWallpaper(const QString &path);
|
||||
|
||||
int accentColor();
|
||||
void setAccentColor(int accentColor);
|
||||
|
||||
void initGtkConfig();
|
||||
|
||||
signals:
|
||||
void darkModeChanged(bool darkMode);
|
||||
void wallpaperChanged(QString path);
|
||||
void darkModeDimsWallpaerChanged();
|
||||
void accentColorChanged(int accentColor);
|
||||
|
||||
private:
|
||||
void updateGtkFont();
|
||||
void updateGtkDarkTheme();
|
||||
|
||||
QSettings *m_settings;
|
||||
bool m_isDarkMode;
|
||||
bool m_darkModeDimsWallpaer;
|
||||
QString m_wallpaperPath;
|
||||
int m_accentColor;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation>Tage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation>Stunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation>Minuten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation>bis Akku voll.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation>übrig.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation>Voll Aufgeladen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation>jetzt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation>vergangen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation>%1 Batterie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Lithium-ion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Unbekannt</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation>d</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation>h</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation>m</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation>until fully charged.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation>remaining.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation>Fully charged.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation>now</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation>ago</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation>%1 Battery</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Lithium-ion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Lithium Polymer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Lithium Iron Phosphate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Lead Acid</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Nickel Cadmium</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Nickel Metal Hydride</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Unknown</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="es" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation>d</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation>h</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation>m</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation>hasta completar la carga.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation>restantes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation>Carga completa.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation>ahora</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation>atrás</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation>Batería de %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>iones de litio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>polímero de litio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>ferrofosfato de litio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>plomo-ácido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>níquel-cadmio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>níquel-metalhidruro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Desconocido</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="es_MX" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="it" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished">sconosciuto</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="nb_NO" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation>d</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation>t</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation>m</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation>til full opplading.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation>gjenstående.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation>Fullt oppladet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation>nå</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation>siden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation>%1 batteri</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Litium-ion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Litium-polymer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Litium-jernfosfat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Blysyre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Nikkel-kadmium</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Mikke-metallhydrid</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>Ukjent</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="pl_PL">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation>d.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation>godz.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation>min.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation>do pełnego naładowania.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translatorcomment>I don't know of a better way to translate this.</translatorcomment>
|
||||
<translation>czasu na baterii.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation>W pełni naładowana.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation>teraz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation>temu</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation>Bateria %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>litowo-jonowa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>litowo-polimerowa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>litowo-żelazowo-fosforanowa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>kwasowo-ołowiowa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>niklowo-kadmowa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>niklowo-wodorkowa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>nieznana</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="pt_BR" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="zh_CN">
|
||||
<context>
|
||||
<name>Battery</name>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="268"/>
|
||||
<source>d</source>
|
||||
<translation>天</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="274"/>
|
||||
<source>h</source>
|
||||
<translation>小时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="281"/>
|
||||
<source>m</source>
|
||||
<translation>分钟</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="290"/>
|
||||
<source>until fully charged.</source>
|
||||
<translation>充满电。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="292"/>
|
||||
<source>remaining.</source>
|
||||
<translation>剩余。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="294"/>
|
||||
<source>Fully charged.</source>
|
||||
<translation>已充满电。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="317"/>
|
||||
<source>now</source>
|
||||
<translation>现在</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/battery.cpp" line="319"/>
|
||||
<source>ago</source>
|
||||
<translation>之前</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UPowerDevice</name>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="71"/>
|
||||
<source>%1 Battery</source>
|
||||
<comment>%1 is battery technology</comment>
|
||||
<translation>%1 电池</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="87"/>
|
||||
<source>Lithium-ion</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>锂离子</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="89"/>
|
||||
<source>Lithium Polymer</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>锂聚合物</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="91"/>
|
||||
<source>Lithium Iron Phosphate</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>磷酸铁锂</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="93"/>
|
||||
<source>Lead Acid</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>铅酸</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="95"/>
|
||||
<source>Nickel Cadmium</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>镍镉</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="97"/>
|
||||
<source>Nickel Metal Hydride</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>金属氢化物镍</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../battery/upowerdevice.cpp" line="99"/>
|
||||
<source>Unknown</source>
|
||||
<comment>battery technology</comment>
|
||||
<translation>未知</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,23 @@
|
||||
project(cutefish-shutdown)
|
||||
|
||||
add_executable(cutefish-shutdown
|
||||
main.cpp
|
||||
actions.cpp
|
||||
qml.qrc
|
||||
)
|
||||
|
||||
target_link_libraries(cutefish-shutdown
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
Qt5::DBus
|
||||
)
|
||||
|
||||
file(GLOB TS_FILES translations/*.ts)
|
||||
qt5_create_translation(QM_FILES ${TS_FILES})
|
||||
add_custom_target(shutdown-translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES})
|
||||
add_dependencies(cutefish-shutdown shutdown-translations)
|
||||
install(FILES ${QM_FILES} DESTINATION /usr/share/cutefish-shutdown/translations)
|
||||
|
||||
install(TARGETS cutefish-shutdown RUNTIME DESTINATION /usr/bin)
|
||||
@ -0,0 +1,59 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.5
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
Item {
|
||||
id: control
|
||||
width: 150
|
||||
height: width
|
||||
|
||||
property string text
|
||||
property string icon
|
||||
property color hoveredColor: Qt.rgba(255, 255, 255, 0.1)
|
||||
property color pressedColor: Qt.rgba(255, 255, 255, 0.2)
|
||||
signal clicked
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: mouseArea.pressed ? pressedColor : mouseArea.containsMouse ? hoveredColor : "transparent"
|
||||
radius: 10
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: control.clicked()
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
spacing: 15
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
source: control.icon
|
||||
width: control.width * 0.5
|
||||
height: width
|
||||
sourceSize.width: width
|
||||
sourceSize.height: width
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: control.text
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
#include "actions.h"
|
||||
#include <QCommandLineParser>
|
||||
#include <QDBusInterface>
|
||||
#include <QApplication>
|
||||
|
||||
const static QString s_dbusName = "org.cutefish.Session";
|
||||
const static QString s_pathName = "/Session";
|
||||
const static QString s_interfaceName = "org.cutefish.Session";
|
||||
|
||||
Actions::Actions(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Actions::shutdown()
|
||||
{
|
||||
QDBusInterface iface(s_dbusName, s_pathName, s_interfaceName, QDBusConnection::sessionBus());
|
||||
if (iface.isValid()) {
|
||||
iface.call("powerOff");
|
||||
}
|
||||
}
|
||||
|
||||
void Actions::logout()
|
||||
{
|
||||
QDBusInterface iface(s_dbusName, s_pathName, s_interfaceName, QDBusConnection::sessionBus());
|
||||
if (iface.isValid()) {
|
||||
iface.call("logout");
|
||||
}
|
||||
}
|
||||
|
||||
void Actions::reboot()
|
||||
{
|
||||
QDBusInterface iface(s_dbusName, s_pathName, s_interfaceName, QDBusConnection::sessionBus());
|
||||
if (iface.isValid()) {
|
||||
iface.call("reboot");
|
||||
}
|
||||
}
|
||||
|
||||
void Actions::suspend()
|
||||
{
|
||||
QDBusInterface iface(s_dbusName, s_pathName, s_interfaceName, QDBusConnection::sessionBus());
|
||||
if (iface.isValid()) {
|
||||
iface.call("suspend");
|
||||
}
|
||||
QCoreApplication::exit(0);
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
#ifndef ACTIONS_H
|
||||
#define ACTIONS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Actions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Actions(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void shutdown();
|
||||
Q_INVOKABLE void logout();
|
||||
Q_INVOKABLE void reboot();
|
||||
Q_INVOKABLE void suspend();
|
||||
};
|
||||
|
||||
#endif // ACTIONS_H
|
||||
@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs
|
||||
id="defs3051">
|
||||
<style
|
||||
type="text/css"
|
||||
id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
d="M 16,3.9999997 A 12,12 0 0 0 4,16 12,12 0 0 0 16,28 12,12 0 0 0 28,16 12,12 0 0 0 16,3.9999997 Z m 0,1 A 11,11 0 0 1 27,16 11,11 0 0 1 16,27 11,11 0 0 1 5,16 11,11 0 0 1 16,4.9999997 Z m 3.269531,3 L 11,16 19.269531,24 20,23.292969 12.460938,16 20,8.7070309 19.269531,7.9999997 Z"
|
||||
class="ColorScheme-Text"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 640 B |
@ -0,0 +1,13 @@
|
||||
<svg version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="M 4,16 A 12,12 0 0 1 5.671875,9.916016 L 11.050781,15.292969 10.339844,16 5.935547,11.595703 A 11,11 0 0 0 5,16 11,11 0 0 0 16,27 11,11 0 0 0 21.351562,25.595703 l 0.728516,0.732422 A 12,12 0 0 1 16,28 12,12 0 0 1 4,16 Z M 9.916016,5.671875 A 12,12 0 0 1 16,4 12,12 0 0 1 28,16 12,12 0 0 1 26.328125,22.083984 L 20.949219,16.707031 21.65625,16 26.060547,20.40625 A 11,11 0 0 0 27,16 11,11 0 0 0 16,5 11,11 0 0 0 10.648438,6.404297 Z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 809 B |
@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<defs
|
||||
id="defs3051">
|
||||
<style
|
||||
type="text/css"
|
||||
id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
d="M 15,4 15,4.05078 15,5.054686 15,13 17,13 17,5.050781 17,4.046875 17,4 16,4 15,4 Z m 3,0.169922 0,1.021484 A 11,11 0 0 1 27,16 11,11 0 0 1 16,27 11,11 0 0 1 5,16 11,11 0 0 1 14,5.189453 L 14,4.181641 A 12,12 0 0 0 4,16 12,12 0 0 0 16,28 12,12 0 0 0 28,16 12,12 0 0 0 18,4.169922 Z"
|
||||
class="ColorScheme-Text"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 641 B |
@ -0,0 +1,13 @@
|
||||
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<style
|
||||
type="text/css"
|
||||
id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#dedede;
|
||||
}
|
||||
</style>
|
||||
<g class="ColorScheme-Text" fill="currentColor">
|
||||
<path d="M9.762 5.762a12 12 0 0 0-.004.008A12 12 0 0 0 4 16a12 12 0 0 0 12 12 12 12 0 0 0 10.238-5.762l-.732-.732A11 11 0 0 1 20 23 11 11 0 0 1 9 12a11 11 0 0 1 1.486-5.502 11 11 0 0 1 .008-.004zM8.8 7.702A12 12 0 0 0 8 12a12 12 0 0 0 12 12 12 12 0 0 0 4.326-.82A11 11 0 0 1 16 27 11 11 0 0 1 5 16a11 11 0 0 1 3.8-8.299zM22 6v1h2.293l-2 2-.293.293V10h4V9h-2.293l2-2L26 6.707V6h-.707z"/>
|
||||
<path d="M20 13v1h2.293l-2 2-.293.293V17h4v-1h-2.293l2-2 .293-.293V13h-.707zm-6-5v1h2.293l-2 2-.293.293V12h4v-1h-2.293l2-2L18 8.707V8h-.707z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 825 B |
@ -0,0 +1,40 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <QFile>
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "actions.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// Translations
|
||||
QLocale locale;
|
||||
QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-shutdown/translations/").arg(locale.name());
|
||||
if (QFile::exists(qmFilePath)) {
|
||||
QTranslator *translator = new QTranslator(QGuiApplication::instance());
|
||||
if (translator->load(qmFilePath)) {
|
||||
QGuiApplication::installTranslator(translator);
|
||||
} else {
|
||||
translator->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
engine.rootContext()->setContextProperty("actions", new Actions);
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.3
|
||||
import QtQuick.Controls 2.5
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
ApplicationWindow {
|
||||
width: Screen.width
|
||||
height: Screen.height
|
||||
visible: true
|
||||
visibility: Window.FullScreen
|
||||
flags: Qt.FramelessWindowHint | Qt.Popup
|
||||
id: root
|
||||
|
||||
color: "transparent"
|
||||
|
||||
function exit() {
|
||||
Qt.quit()
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: "black"
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (!active)
|
||||
exit()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: exit()
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
spacing: root.width * 0.1
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: shutdownButton
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: qsTr("Shutdown")
|
||||
icon: "qrc:///icons/system-shutdown.svg"
|
||||
onClicked: actions.shutdown()
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: rebootButton
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: qsTr("Reboot")
|
||||
icon: "qrc:///icons/system-reboot.svg"
|
||||
onClicked: actions.reboot()
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: logoutButton
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: qsTr("Logout")
|
||||
icon: "qrc:///icons/system-log-out.svg"
|
||||
onClicked: actions.logout()
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: suspendButton
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: qsTr("Suspend")
|
||||
icon: "qrc:///icons/system-suspend.svg"
|
||||
onClicked: actions.suspend()
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
<file>icons/system-log-out.svg</file>
|
||||
<file>icons/system-reboot.svg</file>
|
||||
<file>icons/system-shutdown.svg</file>
|
||||
<file>icons/system-suspend.svg</file>
|
||||
<file>IconButton.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="cs" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="47"/>
|
||||
<source>Shutdown</source>
|
||||
<translation>Vypnout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="55"/>
|
||||
<source>Reboot</source>
|
||||
<translation>Restartovat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="63"/>
|
||||
<source>Logout</source>
|
||||
<translation>Odhlásit se</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="71"/>
|
||||
<source>Suspend</source>
|
||||
<translation>Uspat</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de_DE" sourcelanguage="de_DE">
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
<location filename="../main.qml" line="47"/>
|
||||
<source>Shutdown</source>
|
||||
<translation>Ausschalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="55"/>
|
||||
<source>Reboot</source>
|
||||
<translation>Neustart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="63"/>
|
||||
<source>Logout</source>
|
||||
<translation>Abmelden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.qml" line="71"/>
|
||||
<source>Suspend</source>
|
||||
<translation>Bereitschaft</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue