first commit
54
.gitignore
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
# C++ objects and libs
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.a
|
||||
*.la
|
||||
*.lai
|
||||
*.so
|
||||
*.so.*
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
# Qt-es
|
||||
object_script.*.Release
|
||||
object_script.*.Debug
|
||||
*_plugin_import.cpp
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
*.qbs.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
*.qmlc
|
||||
*.jsc
|
||||
Makefile*
|
||||
*build-*
|
||||
*.qm
|
||||
*.prl
|
||||
|
||||
# Qt unit tests
|
||||
target_wrapper.*
|
||||
|
||||
# QtCreator
|
||||
*.autosave
|
||||
|
||||
# QtCreator Qml
|
||||
*.qmlproject.user
|
||||
*.qmlproject.user.*
|
||||
|
||||
# QtCreator CMake
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# QtCreator 4.8< compilation database
|
||||
compile_commands.json
|
||||
|
||||
# QtCreator local machine specific files for imported projects
|
||||
*creator.user*
|
||||
|
||||
build/*
|
74
CMakeLists.txt
Normal file
|
@ -0,0 +1,74 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(PROJECT_NAME cyber-dock)
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
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 Widgets Concurrent Quick QuickControls2 X11Extras DBus LinguistTools)
|
||||
find_package(Qt5 REQUIRED ${QT})
|
||||
find_package(KF5WindowSystem REQUIRED)
|
||||
find_package(dbusmenu-qt5 REQUIRED)
|
||||
find_package(MeuiKit REQUIRED)
|
||||
|
||||
set(SRCS
|
||||
src/applicationitem.h
|
||||
src/applicationmodel.cpp
|
||||
src/battery.cpp
|
||||
src/brightness.cpp
|
||||
src/controlcenterdialog.cpp
|
||||
src/docksettings.cpp
|
||||
src/iconthemeimageprovider.cpp
|
||||
src/main.cpp
|
||||
src/mainwindow.cpp
|
||||
src/systemappmonitor.cpp
|
||||
src/systemappitem.cpp
|
||||
src/processprovider.cpp
|
||||
src/trashmanager.cpp
|
||||
src/volumemanager.cpp
|
||||
src/utils.cpp
|
||||
src/xwindowinterface.cpp
|
||||
|
||||
src/appearance.cpp
|
||||
src/fakewindow.cpp
|
||||
|
||||
src/statusnotifier/dbustypes.cpp
|
||||
src/statusnotifier/sniasync.cpp
|
||||
src/statusnotifier/statusnotifieriteminterface.cpp
|
||||
src/statusnotifier/statusnotifiermodel.cpp
|
||||
src/statusnotifier/statusnotifierwatcher.cpp
|
||||
src/statusnotifier/statusnotifieritemsource.cpp
|
||||
)
|
||||
|
||||
set(RESOURCES
|
||||
resources.qrc
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SRCS} ${DBUS_SRCS} ${RESOURCES})
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
Qt5::Quick
|
||||
Qt5::QuickControls2
|
||||
Qt5::X11Extras
|
||||
Qt5::Concurrent
|
||||
Qt5::DBus
|
||||
|
||||
MeuiKit
|
||||
|
||||
KF5::WindowSystem
|
||||
dbusmenu-qt5
|
||||
)
|
||||
|
||||
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(${PROJECT_NAME} translations)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION /usr/bin)
|
||||
install(FILES ${QM_FILES} DESTINATION /usr/share/${PROJECT_NAME}/translations)
|
674
LICENSE
Normal file
|
@ -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>.
|
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Dock
|
||||
|
||||
CutefishOS application dock.
|
||||
|
||||
## Dependencies
|
||||
|
||||
```shell
|
||||
sudo pacman -S gcc cmake qt5-base qt5-quickcontrols2 kwindowsystem
|
||||
```
|
||||
|
||||
You also need [`meuikit`](https://github.com/cyberos/meuikit) and [`libcyber-system`](https://github.com/cyberos/libcyber-system).
|
||||
|
||||
## Build and Install
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project has been licensed by GPLv3.
|
75
qml/AppItem.qml
Normal file
|
@ -0,0 +1,75 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import Qt.labs.platform 1.0
|
||||
import Cyber.Dock 1.0
|
||||
|
||||
DockItem {
|
||||
id: appItem
|
||||
|
||||
property var windowCount: model.windowCount
|
||||
|
||||
iconName: model.iconName ? model.iconName : "application-x-desktop"
|
||||
isActive: model.isActive
|
||||
popupText: model.visibleName
|
||||
enableActivateDot: windowCount !== 0
|
||||
draggable: model.appId === "cyber-launcher" ? false : true
|
||||
dragItemIndex: index
|
||||
|
||||
onWindowCountChanged: {
|
||||
if (windowCount > 0)
|
||||
updateGeometry()
|
||||
}
|
||||
|
||||
onPositionChanged: updateGeometry()
|
||||
onPressed: updateGeometry()
|
||||
onClicked: appModel.clicked(model.appId)
|
||||
onRightClicked: if (model.appId !== "cyber-launcher") contextMenu.open()
|
||||
|
||||
dropArea.onEntered: {
|
||||
if (drag.source)
|
||||
appModel.move(drag.source.dragItemIndex, appItem.dragItemIndex)
|
||||
else
|
||||
appModel.raiseWindow(model.appId)
|
||||
}
|
||||
|
||||
dropArea.onDropped: {
|
||||
appModel.save()
|
||||
updateGeometry()
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: contextMenu
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Open")
|
||||
visible: windowCount === 0
|
||||
onTriggered: appModel.openNewInstance(model.appId)
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: model.visibleName
|
||||
visible: windowCount > 0
|
||||
onTriggered: appModel.openNewInstance(model.appId)
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: model.isPinned ? qsTr("Unpin") : qsTr("Pin")
|
||||
onTriggered: {
|
||||
model.isPinned ? appModel.unPin(model.appId) : appModel.pin(model.appId)
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Close All")
|
||||
visible: windowCount !== 0
|
||||
onTriggered: appModel.closeAllByAppId(model.appId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateGeometry() {
|
||||
appModel.updateGeometries(model.appId, Qt.rect(appItem.mapToGlobal(0, 0).x,
|
||||
appItem.mapToGlobal(0, 0).y,
|
||||
appItem.width, appItem.height))
|
||||
}
|
||||
}
|
120
qml/CardItem.qml
Normal file
|
@ -0,0 +1,120 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
import MeuiKit 1.0 as Meui
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property bool checked: false
|
||||
property alias icon: _image.source
|
||||
property alias label: _titleLabel.text
|
||||
property alias text: _label.text
|
||||
|
||||
signal clicked
|
||||
|
||||
property var hoverColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.secondBackgroundColor, 2)
|
||||
: Qt.darker(Meui.Theme.secondBackgroundColor, 1.3)
|
||||
property var pressedColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.secondBackgroundColor, 1.8)
|
||||
: Qt.darker(Meui.Theme.secondBackgroundColor, 1.5)
|
||||
|
||||
property var highlightHoverColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.highlightColor, 1.2)
|
||||
: Qt.darker(Meui.Theme.highlightColor, 1.1)
|
||||
property var highlightPressedColor: Meui.Theme.darkMode ? Qt.lighter(Meui.Theme.highlightColor, 1.1)
|
||||
: Qt.darker(Meui.Theme.highlightColor, 1.2)
|
||||
|
||||
MouseArea {
|
||||
id: _mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: control.clicked()
|
||||
|
||||
onPressedChanged: {
|
||||
control.scale = pressed ? 0.95 : 1.0
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
}
|
||||
}
|
||||
|
||||
Meui.RoundedRect {
|
||||
anchors.fill: parent
|
||||
radius: Meui.Theme.bigRadius
|
||||
backgroundOpacity: control.checked ? 0.9 : 0.3
|
||||
animationEnabled: false
|
||||
|
||||
color: {
|
||||
if (control.checked) {
|
||||
if (_mouseArea.pressed)
|
||||
return highlightPressedColor
|
||||
else if (_mouseArea.containsMouse)
|
||||
return highlightHoverColor
|
||||
else
|
||||
return Meui.Theme.highlightColor
|
||||
} else {
|
||||
if (_mouseArea.pressed)
|
||||
return pressedColor
|
||||
else if (_mouseArea.containsMouse)
|
||||
return hoverColor
|
||||
else
|
||||
return Meui.Theme.secondBackgroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Meui.Units.smallSpacing
|
||||
anchors.rightMargin: Meui.Units.smallSpacing
|
||||
|
||||
Image {
|
||||
id: _image
|
||||
Layout.preferredWidth: control.height * 0.3
|
||||
Layout.preferredHeight: control.height * 0.3
|
||||
sourceSize: Qt.size(width, height)
|
||||
asynchronous: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: Meui.Units.largeSpacing
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: _image
|
||||
source: _image
|
||||
color: control.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.disabledTextColor
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Label {
|
||||
id: _titleLabel
|
||||
color: control.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
|
||||
Layout.preferredHeight: control.height * 0.15
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Label {
|
||||
id: _label
|
||||
color: control.checked ? Meui.Theme.highlightedTextColor : Meui.Theme.textColor
|
||||
elide: Label.ElideRight
|
||||
Layout.preferredHeight: control.height * 0.1
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
// Layout.fillWidth: true
|
||||
Layout.bottomMargin: Meui.Units.largeSpacing
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
352
qml/ControlCenter.qml
Normal file
|
@ -0,0 +1,352 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Window 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Cyber.Dock 1.0
|
||||
import MeuiKit 1.0 as Meui
|
||||
import Cyber.Accounts 1.0 as Accounts
|
||||
|
||||
ControlCenterDialog {
|
||||
id: control
|
||||
width: 500
|
||||
height: _mainLayout.implicitHeight + Meui.Units.largeSpacing * 4
|
||||
|
||||
minimumWidth: 500
|
||||
maximumWidth: 500
|
||||
minimumHeight: _mainLayout.implicitHeight + Meui.Units.largeSpacing * 4
|
||||
maximumHeight: _mainLayout.implicitHeight + Meui.Units.largeSpacing * 4
|
||||
|
||||
property point position: Qt.point(0, 0)
|
||||
|
||||
onWidthChanged: adjustCorrectLocation()
|
||||
onHeightChanged: adjustCorrectLocation()
|
||||
onPositionChanged: adjustCorrectLocation()
|
||||
|
||||
color: "transparent"
|
||||
|
||||
Appearance {
|
||||
id: appearance
|
||||
}
|
||||
|
||||
function adjustCorrectLocation() {
|
||||
var posX = control.position.x
|
||||
var posY = control.position.y
|
||||
|
||||
// left
|
||||
if (posX < 0)
|
||||
posX = Meui.Units.largeSpacing
|
||||
|
||||
// top
|
||||
if (posY < 0)
|
||||
posY = Meui.Units.largeSpacing
|
||||
|
||||
// right
|
||||
if (posX + control.width > Screen.width)
|
||||
posX = Screen.width - control.width - Meui.Units.largeSpacing
|
||||
|
||||
// bottom
|
||||
if (posY > control.height > Screen.width)
|
||||
posY = Screen.width - control.width - Meui.Units.largeSpacing
|
||||
|
||||
control.x = posX
|
||||
control.y = posY
|
||||
}
|
||||
|
||||
Brightness {
|
||||
id: brightness
|
||||
}
|
||||
|
||||
Accounts.UserAccount {
|
||||
id: currentUser
|
||||
}
|
||||
|
||||
Meui.WindowBlur {
|
||||
view: control
|
||||
geometry: Qt.rect(control.x, control.y, control.width, control.height)
|
||||
windowRadius: _background.radius
|
||||
enabled: true
|
||||
}
|
||||
|
||||
Meui.RoundedRect {
|
||||
id: _background
|
||||
anchors.fill: parent
|
||||
radius: control.height * 0.05
|
||||
color: Meui.Theme.backgroundColor
|
||||
backgroundOpacity: Meui.Theme.darkMode ? 0.3 : 0.4
|
||||
}
|
||||
|
||||
Meui.WindowShadow {
|
||||
view: control
|
||||
geometry: Qt.rect(control.x, control.y, control.width, control.height)
|
||||
radius: _background.radius
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: _mainLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: Meui.Units.largeSpacing * 2
|
||||
spacing: Meui.Units.largeSpacing
|
||||
|
||||
Item {
|
||||
id: topItem
|
||||
Layout.fillWidth: true
|
||||
height: 50
|
||||
|
||||
RowLayout {
|
||||
id: topItemLayout
|
||||
anchors.fill: parent
|
||||
spacing: Meui.Units.largeSpacing
|
||||
|
||||
Image {
|
||||
id: userIcon
|
||||
Layout.fillHeight: true
|
||||
width: height
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: currentUser.iconFileName ? "file:///" + currentUser.iconFileName : "image://icontheme/default-user"
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Item {
|
||||
width: userIcon.width
|
||||
height: userIcon.height
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.height / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: userLabel
|
||||
text: currentUser.userName
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
elide: Label.ElideRight
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: settingsButton
|
||||
implicitWidth: topItem.height * 0.8
|
||||
implicitHeight: topItem.height * 0.8
|
||||
Layout.alignment: Qt.AlignTop
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + "settings.svg"
|
||||
onLeftButtonClicked: {
|
||||
control.visible = false
|
||||
process.startDetached("cyber-settings")
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: shutdownButton
|
||||
implicitWidth: topItem.height * 0.8
|
||||
implicitHeight: topItem.height * 0.8
|
||||
Layout.alignment: Qt.AlignTop
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + "system-shutdown-symbolic.svg"
|
||||
onLeftButtonClicked: {
|
||||
control.visible = false
|
||||
process.startDetached("cyber-shutdown")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: controlItem
|
||||
Layout.fillWidth: true
|
||||
height: 120
|
||||
visible: wirelessItem.visible || bluetoothItem.visible
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: Meui.Units.largeSpacing
|
||||
|
||||
CardItem {
|
||||
id: wirelessItem
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: contentItem.width / 3 - Meui.Units.largeSpacing * 2
|
||||
icon: "qrc:/svg/dark/network-wireless-connected-100.svg"
|
||||
visible: network.wirelessHardwareEnabled
|
||||
checked: network.wirelessEnabled
|
||||
label: qsTr("Wi-Fi")
|
||||
text: network.wirelessEnabled ? network.wirelessConnectionName ?
|
||||
network.wirelessConnectionName :
|
||||
qsTr("On") : qsTr("Off")
|
||||
onClicked: network.wirelessEnabled = !network.wirelessEnabled
|
||||
}
|
||||
|
||||
CardItem {
|
||||
id: bluetoothItem
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: contentItem.width / 3 - Meui.Units.largeSpacing * 2
|
||||
icon: "qrc:/svg/light/bluetooth-symbolic.svg"
|
||||
checked: false
|
||||
label: qsTr("Bluetooth")
|
||||
text: qsTr("Off")
|
||||
}
|
||||
|
||||
CardItem {
|
||||
id: darkModeItem
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: contentItem.width / 3 - Meui.Units.largeSpacing * 2
|
||||
icon: "qrc:/svg/light/dark-mode.svg"
|
||||
checked: Meui.Theme.darkMode
|
||||
label: qsTr("Dark Mode")
|
||||
text: Meui.Theme.darkMode ? qsTr("On") : qsTr("Off")
|
||||
onClicked: appearance.switchDarkMode(!Meui.Theme.darkMode)
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MprisController {
|
||||
height: 100
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Item {
|
||||
id: brightnessItem
|
||||
Layout.fillWidth: true
|
||||
height: 50
|
||||
visible: brightness.enabled
|
||||
|
||||
Meui.RoundedRect {
|
||||
id: brightnessItemBg
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
radius: Meui.Theme.bigRadius
|
||||
color: Meui.Theme.backgroundColor
|
||||
backgroundOpacity: 0.3
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: brightnessItemBg
|
||||
anchors.margins: Meui.Units.largeSpacing
|
||||
spacing: Meui.Units.largeSpacing
|
||||
|
||||
Image {
|
||||
width: parent.height * 0.6
|
||||
height: parent.height * 0.6
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/brightness.svg"
|
||||
}
|
||||
|
||||
Slider {
|
||||
id: brightnessSlider
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
value: brightness.value
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
onMoved: {
|
||||
brightness.setValue(brightnessSlider.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: volumeItem
|
||||
Layout.fillWidth: true
|
||||
height: 50
|
||||
visible: volume.isValid
|
||||
|
||||
Meui.RoundedRect {
|
||||
id: volumeItemBg
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
radius: Meui.Theme.bigRadius
|
||||
color: Meui.Theme.backgroundColor
|
||||
backgroundOpacity: 0.3
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: volumeItemBg
|
||||
anchors.margins: Meui.Units.largeSpacing
|
||||
spacing: Meui.Units.largeSpacing
|
||||
|
||||
Image {
|
||||
width: parent.height * 0.6
|
||||
height: parent.height * 0.6
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/" + volume.iconName + ".svg"
|
||||
}
|
||||
|
||||
Slider {
|
||||
id: slider
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
value: volume.volume
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
onValueChanged: {
|
||||
volume.setVolume(value)
|
||||
|
||||
if (volume.isMute && value > 0)
|
||||
volume.setMute(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label {
|
||||
id: timeLabel
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
repeat: true
|
||||
running: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
timeLabel.text = new Date().toLocaleString(Qt.locale(), Locale.ShortFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
StandardItem {
|
||||
width: batteryLayout.implicitWidth + Meui.Units.largeSpacing
|
||||
height: batteryLayout.implicitHeight + Meui.Units.largeSpacing
|
||||
|
||||
onClicked: process.startDetached("cyber-settings", ["-m", "battery"])
|
||||
|
||||
RowLayout {
|
||||
id: batteryLayout
|
||||
anchors.fill: parent
|
||||
visible: battery.available
|
||||
spacing: 0
|
||||
|
||||
Image {
|
||||
id: batteryIcon
|
||||
width: 22
|
||||
height: 16
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + battery.iconSource
|
||||
asynchronous: true
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
text: battery.chargePercent + "%"
|
||||
color: Meui.Theme.textColor
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
93
qml/ControlCenterItem.qml
Normal file
|
@ -0,0 +1,93 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Cyber.Dock 1.0
|
||||
import MeuiKit 1.0 as Meui
|
||||
|
||||
StandardItem {
|
||||
id: controlItem
|
||||
|
||||
Layout.preferredWidth: isHorizontal ? controlLayout.implicitWidth + Meui.Units.largeSpacing * 2 : mainLayout.width * 0.7
|
||||
Layout.preferredHeight: isHorizontal ? mainLayout.height * 0.7 : controlLayout.implicitHeight + Meui.Units.largeSpacing * 2
|
||||
Layout.rightMargin: isHorizontal ? root.windowRadius / 2 : 0
|
||||
Layout.bottomMargin: isHorizontal ? 0 : root.windowRadius / 2
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
onClicked: {
|
||||
if (controlCenter.visible)
|
||||
controlCenter.visible = false
|
||||
else {
|
||||
// 先初始化,用户可能会通过Alt鼠标左键移动位置
|
||||
controlCenter.position = Qt.point(0, 0)
|
||||
|
||||
controlCenter.visible = true
|
||||
controlCenter.position = Qt.point(mapToGlobal(0, 0).x, mapToGlobal(0, 0).y)
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: controlLayout
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: isHorizontal ? Meui.Units.smallSpacing : 0
|
||||
anchors.rightMargin: isHorizontal ? Meui.Units.smallSpacing : 0
|
||||
anchors.topMargin: isHorizontal ? Meui.Units.smallSpacing : 0
|
||||
anchors.bottomMargin: isHorizontal ? Meui.Units.smallSpacing : 0
|
||||
columnSpacing: isHorizontal ? Meui.Units.largeSpacing + Meui.Units.smallSpacing : 0
|
||||
rowSpacing: isHorizontal ? 0 : Meui.Units.largeSpacing + Meui.Units.smallSpacing
|
||||
flow: isHorizontal ? Grid.LeftToRight : Grid.TopToBottom
|
||||
|
||||
Image {
|
||||
id: wirelessIcon
|
||||
width: root.trayItemSize
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: network.wirelessIconName ? "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + network.wirelessIconName + ".svg" : ""
|
||||
asynchronous: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
visible: network.enabled &&
|
||||
network.wirelessEnabled &&
|
||||
network.wirelessConnectionName !== "" &&
|
||||
wirelessIcon.status === Image.Ready
|
||||
}
|
||||
|
||||
Image {
|
||||
id: batteryIcon
|
||||
visible: battery.available && status === Image.Ready
|
||||
height: root.trayItemSize
|
||||
width: height + 6
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + battery.iconSource
|
||||
asynchronous: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Image {
|
||||
id: volumeIcon
|
||||
visible: volume.isValid && status === Image.Ready
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark/" : "light/") + volume.iconName + ".svg"
|
||||
width: root.trayItemSize
|
||||
height: width
|
||||
sourceSize: Qt.size(width, height)
|
||||
asynchronous: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
id: timeLabel
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
font.pixelSize: isHorizontal ? controlLayout.height / 3 : controlLayout.width / 5
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
repeat: true
|
||||
running: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
timeLabel.text = new Date().toLocaleTimeString(Qt.locale(), Locale.ShortFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
175
qml/DockItem.qml
Normal file
|
@ -0,0 +1,175 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtGraphicalEffects 1.0
|
||||
import Cyber.Dock 1.0
|
||||
import MeuiKit 1.0 as Meui
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property bool isLeft: Settings.direction === DockSettings.Left
|
||||
|
||||
property var iconSize: (isLeft ? control.height : control.width) * iconSizeRatio
|
||||
|
||||
property bool draggable: false
|
||||
property int dragItemIndex
|
||||
|
||||
property alias icon: icon
|
||||
property alias mouseArea: iconArea
|
||||
property alias dropArea: iconDropArea
|
||||
|
||||
property bool enableActivateDot: true
|
||||
property bool isActive: false
|
||||
|
||||
property var popupText
|
||||
|
||||
property double iconSizeRatio: 0.8
|
||||
property var iconName
|
||||
|
||||
property bool dragStarted: false
|
||||
|
||||
signal positionChanged()
|
||||
signal released()
|
||||
signal pressed(var mouse)
|
||||
signal pressAndHold(var mouse)
|
||||
signal clicked(var mouse)
|
||||
signal rightClicked(var mouse)
|
||||
signal doubleClicked(var mouse)
|
||||
|
||||
Drag.active: mouseArea.drag.active && control.draggable
|
||||
Drag.dragType: Drag.Automatic
|
||||
Drag.supportedActions: Qt.MoveAction
|
||||
Drag.hotSpot.x: icon.width / 2
|
||||
Drag.hotSpot.y: icon.height / 2
|
||||
|
||||
Drag.onDragStarted: {
|
||||
dragStarted = true
|
||||
}
|
||||
|
||||
Drag.onDragFinished: {
|
||||
dragStarted = false
|
||||
}
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
anchors.centerIn: parent
|
||||
source: iconName ? iconName.indexOf("/") === 0 || iconName.indexOf("file://") === 0 || iconName.indexOf("qrc") === 0
|
||||
? iconName : "image://icontheme/" + iconName : iconName
|
||||
sourceSize.width: control.iconSize
|
||||
sourceSize.height: control.iconSize
|
||||
width: sourceSize.width
|
||||
height: sourceSize.height
|
||||
asynchronous: false
|
||||
smooth: true
|
||||
cache: true
|
||||
|
||||
visible: !dragStarted
|
||||
|
||||
ColorOverlay {
|
||||
id: iconColorize
|
||||
anchors.fill: icon
|
||||
source: icon
|
||||
color: "#000000"
|
||||
opacity: iconArea.pressed && !mouseArea.drag.active ? 0.5 : 0
|
||||
}
|
||||
}
|
||||
|
||||
DropArea {
|
||||
id: iconDropArea
|
||||
anchors.fill: icon
|
||||
enabled: draggable
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: icon
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
drag.axis: Drag.XAndYAxis
|
||||
|
||||
onClicked: {
|
||||
if (mouse.button === Qt.RightButton)
|
||||
control.rightClicked(mouse)
|
||||
else
|
||||
control.clicked(mouse)
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
control.pressed(mouse)
|
||||
popupTips.hide()
|
||||
}
|
||||
|
||||
onPositionChanged: {
|
||||
if (pressed) {
|
||||
if (mouse.source !== Qt.MouseEventSynthesizedByQt) {
|
||||
drag.target = icon
|
||||
icon.grabToImage(function(result) {
|
||||
control.Drag.imageSource = result.url
|
||||
})
|
||||
} else {
|
||||
drag.target = null
|
||||
}
|
||||
}
|
||||
|
||||
control.positionChanged()
|
||||
}
|
||||
|
||||
onPressAndHold : control.pressAndHold(mouse)
|
||||
onReleased: {
|
||||
drag.target = null
|
||||
control.released()
|
||||
}
|
||||
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse && control.popupText !== "") {
|
||||
popupTips.popupText = control.popupText
|
||||
|
||||
if (Settings.direction === DockSettings.Left)
|
||||
popupTips.position = Qt.point(root.width + Meui.Units.largeSpacing,
|
||||
control.mapToGlobal(0, 0).y + (control.height / 2 - popupTips.height / 2))
|
||||
else
|
||||
popupTips.position = Qt.point(control.mapToGlobal(0, 0).x + (control.width / 2 - popupTips.width / 2),
|
||||
control.mapToGlobal(0, 0).y - popupTips.height - Meui.Units.smallSpacing / 2)
|
||||
|
||||
popupTips.show()
|
||||
} else {
|
||||
popupTips.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: activeLine
|
||||
width: isLeft ? parent.width * 0.06 : (isActive ? parent.height * 0.4 : parent.height * 0.06)
|
||||
height: isLeft ? (isActive ? parent.height * 0.4 : parent.height * 0.06) : parent.height * 0.06
|
||||
color: Meui.Theme.textColor
|
||||
radius: isLeft ? width / 2 : height / 2
|
||||
visible: enableActivateDot && !dragStarted
|
||||
opacity: isActive ? 1 : 0.6
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 125
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: !isLeft ? 125 : 0
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: isLeft ? 125 : 0
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
x: isLeft ? 3 : (parent.width - width) / 2
|
||||
y: isLeft ? (parent.height - height) / 2 : icon.y + icon.height + activeLine.height / 2 - 2
|
||||
// 1 is the window border
|
||||
}
|
||||
}
|
57
qml/IconButton.qml
Normal file
|
@ -0,0 +1,57 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import MeuiKit 1.0 as Meui
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property url source
|
||||
property real size: 24
|
||||
property string popupText
|
||||
|
||||
signal leftButtonClicked
|
||||
signal rightButtonClicked
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: control.visible ? true : false
|
||||
|
||||
onClicked: {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
control.leftButtonClicked()
|
||||
else if (mouse.button === Qt.RightButton)
|
||||
control.rightButtonClicked()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
radius: parent.height * 0.2
|
||||
|
||||
color: {
|
||||
if (mouseArea.containsMouse) {
|
||||
if (mouseArea.containsPress)
|
||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(0, 0, 0, 0.3)
|
||||
else
|
||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.2) : Qt.rgba(0, 0, 0, 0.2)
|
||||
}
|
||||
|
||||
return "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: iconImage
|
||||
anchors.centerIn: parent
|
||||
width: parent.height * 0.8
|
||||
height: width
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
source: control.source
|
||||
asynchronous: true
|
||||
}
|
||||
}
|
137
qml/MprisController.qml
Normal file
|
@ -0,0 +1,137 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtGraphicalEffects 1.0
|
||||
import MeuiKit 1.0 as Meui
|
||||
import Cyber.Mpris 1.0
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
visible: available && (_songLabel.text != "" || _artistLabel.text != "")
|
||||
|
||||
property bool available: mprisManager.availableServices.length > 1
|
||||
property bool isPlaying: currentService && mprisManager.playbackStatus === Mpris.Playing
|
||||
property alias currentService: mprisManager.currentService
|
||||
property var artUrlTag: Mpris.metadataToString(Mpris.ArtUrl)
|
||||
property var titleTag: Mpris.metadataToString(Mpris.Title)
|
||||
property var artistTag: Mpris.metadataToString(Mpris.Artist)
|
||||
|
||||
MprisManager {
|
||||
id: mprisManager
|
||||
}
|
||||
|
||||
Meui.RoundedRect {
|
||||
id: _background
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
radius: Meui.Theme.bigRadius
|
||||
color: Meui.Theme.backgroundColor
|
||||
backgroundOpacity: 0.3
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: _mainLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: Meui.Units.largeSpacing
|
||||
anchors.rightMargin: Meui.Units.largeSpacing * 2
|
||||
spacing: Meui.Units.largeSpacing
|
||||
|
||||
Image {
|
||||
id: artImage
|
||||
Layout.fillHeight: true
|
||||
width: height
|
||||
visible: status === Image.Ready
|
||||
sourceSize: Qt.size(width, height)
|
||||
source: control.available ? (artUrlTag in mprisManager.metadata) ? mprisManager.metadata[artUrlTag].toString() : "" : ""
|
||||
asynchronous: true
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Item {
|
||||
width: artImage.width
|
||||
height: artImage.height
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Meui.Theme.bigRadius
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Label {
|
||||
id: _songLabel
|
||||
Layout.fillWidth: true
|
||||
visible: _songLabel.text !== ""
|
||||
text: control.available ? (titleTag in mprisManager.metadata) ? mprisManager.metadata[titleTag].toString() : "" : ""
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Label {
|
||||
id: _artistLabel
|
||||
Layout.fillWidth: true
|
||||
visible: _artistLabel.text !== ""
|
||||
text: control.available ? (artistTag in mprisManager.metadata) ? mprisManager.metadata[artistTag].toString() : "" : ""
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: _buttons
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: _mainLayout.width / 3
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
IconButton {
|
||||
width: 33
|
||||
height: 33
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-skip-backward-symbolic.svg"
|
||||
onLeftButtonClicked: if (mprisManager.canGoPrevious) mprisManager.previous()
|
||||
visible: control.available ? mprisManager.canGoPrevious : false
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
IconButton {
|
||||
width: 33
|
||||
height: 33
|
||||
source: control.isPlaying ? "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-playback-pause-symbolic.svg"
|
||||
: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-playback-start-symbolic.svg"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
visible: mprisManager.canPause || mprisManager.canPlay
|
||||
onLeftButtonClicked:
|
||||
if ((control.isPlaying && mprisManager.canPause) || (!control.isPlaying && mprisManager.canPlay)) {
|
||||
mprisManager.playPause()
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
width: 33
|
||||
height: 33
|
||||
source: "qrc:/svg/" + (Meui.Theme.darkMode ? "dark" : "light") + "/media-skip-forward-symbolic.svg"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
onLeftButtonClicked: if (mprisManager.canGoNext) mprisManager.next()
|
||||
visible: control.available ? mprisManager.canGoNext : false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
74
qml/StandardItem.qml
Normal file
|
@ -0,0 +1,74 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import MeuiKit 1.0 as Meui
|
||||
import Cyber.Dock 1.0
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property var popupText: ""
|
||||
|
||||
signal clicked
|
||||
signal rightClicked
|
||||
|
||||
MouseArea {
|
||||
id: _mouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
if (mouse.button == Qt.LeftButton)
|
||||
control.clicked()
|
||||
else if (mouse.button == Qt.RightButton)
|
||||
control.rightClicked()
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
popupTips.hide()
|
||||
}
|
||||
|
||||
onContainsMouseChanged: {
|
||||
if (containsMouse && control.popupText !== "") {
|
||||
popupTips.popupText = control.popupText
|
||||
|
||||
if (Settings.direction === DockSettings.Left)
|
||||
popupTips.position = Qt.point(root.width + Meui.Units.largeSpacing,
|
||||
control.mapToGlobal(0, 0).y + (control.height / 2 - popupTips.height / 2))
|
||||
else
|
||||
popupTips.position = Qt.point(control.mapToGlobal(0, 0).x + (control.width / 2 - popupTips.width / 2),
|
||||
mainWindow.y - popupTips.height - Meui.Units.smallSpacing / 2)
|
||||
|
||||
popupTips.show()
|
||||
} else {
|
||||
popupTips.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Meui.Theme.smallRadius
|
||||
|
||||
color: {
|
||||
if (_mouseArea.containsMouse) {
|
||||
if (_mouseArea.containsPress)
|
||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(0, 0, 0, 0.2)
|
||||
else
|
||||
return (Meui.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.2) : Qt.rgba(0, 0, 0, 0.1)
|
||||
}
|
||||
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 125
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
260
qml/main.qml
Normal file
|
@ -0,0 +1,260 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Cyber.NetworkManagement 1.0 as NM
|
||||
import Cyber.Dock 1.0
|
||||
import MeuiKit 1.0 as Meui
|
||||
|
||||
Item {
|
||||
id: root
|
||||
visible: true
|
||||
|
||||
property color borderColor: Meui.Theme.darkMode ? Qt.rgba(255, 255, 255, 0.1) : Qt.rgba(0, 0, 0, 0.05)
|
||||
property real windowRadius: (Settings.direction === DockSettings.Left) ? root.width * 0.25 : root.height * 0.25
|
||||
property bool isHorizontal: Settings.direction !== DockSettings.Left
|
||||
property var appViewLength: isHorizontal ? appItemView.width : appItemView.height
|
||||
property var appViewHeight: isHorizontal ? appItemView.height : appItemView.width
|
||||
property var trayItemSize: 16
|
||||
property var iconSize: 0
|
||||
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
enabled: true
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: calcIconSizeTimer
|
||||
repeat: false
|
||||
running: false
|
||||
interval: 10
|
||||
onTriggered: calcIconSize()
|
||||
}
|
||||
|
||||
function calcIconSize() {
|
||||
const appCount = appItemView.count
|
||||
const size = (appViewLength - (appViewLength % appCount)) / appCount
|
||||
const rootHeight = isHorizontal ? root.height : root.width
|
||||
const calcSize = size >= rootHeight ? rootHeight : Math.min(size, rootHeight)
|
||||
root.iconSize = calcSize
|
||||
}
|
||||
|
||||
function delayCalcIconSize() {
|
||||
if (calcIconSizeTimer.running)
|
||||
calcIconSizeTimer.stop()
|
||||
|
||||
calcIconSizeTimer.interval = 100
|
||||
calcIconSizeTimer.restart()
|
||||
}
|
||||
|
||||
Meui.WindowShadow {
|
||||
view: mainWindow
|
||||
geometry: Qt.rect(root.x, root.y, root.width, root.height)
|
||||
radius: _background.radius
|
||||
}
|
||||
|
||||
Meui.WindowBlur {
|
||||
view: mainWindow
|
||||
geometry: Qt.rect(root.x, root.y, root.width, root.height)
|
||||
windowRadius: _background.radius
|
||||
enabled: true
|
||||
}
|
||||
|
||||
// Background
|
||||
Rectangle {
|
||||
id: _background
|
||||
anchors.fill: parent
|
||||
radius: windowRadius
|
||||
color: Meui.Theme.backgroundColor
|
||||
opacity: Meui.Theme.darkMode ? 0.3 : 0.5
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 0
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
radius: windowRadius
|
||||
border.width: 1
|
||||
border.color: Qt.rgba(0, 0, 0, 0.5)
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
radius: windowRadius - 1
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: Qt.rgba(255, 255, 255, 0.2)
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
}
|
||||
|
||||
Meui.PopupTips {
|
||||
id: popupTips
|
||||
backgroundColor: Meui.Theme.backgroundColor
|
||||
backgroundOpacity: Meui.Theme.darkMode ? 0.3 : 0.4
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: mainLayout
|
||||
anchors.fill: parent
|
||||
flow: isHorizontal ? Grid.LeftToRight : Grid.TopToBottom
|
||||
columnSpacing: 0
|
||||
rowSpacing: 0
|
||||
|
||||
ListView {
|
||||
id: appItemView
|
||||
orientation: isHorizontal ? Qt.Horizontal : Qt.Vertical
|
||||
snapMode: ListView.SnapToItem
|
||||
interactive: false
|
||||
model: appModel
|
||||
clip: true
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
onCountChanged: root.delayCalcIconSize()
|
||||
|
||||
delegate: AppItem {
|
||||
id: appItemDelegate
|
||||
implicitWidth: isHorizontal ? root.iconSize : ListView.view.width
|
||||
implicitHeight: isHorizontal ? ListView.view.height : root.iconSize
|
||||
|
||||
// Behavior on implicitWidth {
|
||||
// NumberAnimation {
|
||||
// from: root.iconSize
|
||||
// easing.type: Easing.InOutQuad
|
||||
// duration: isHorizontal ? 250 : 0
|
||||
// }
|
||||
// }
|
||||
|
||||
// Behavior on implicitHeight {
|
||||
// NumberAnimation {
|
||||
// from: root.iconSize
|
||||
// easing.type: Easing.InOutQuad
|
||||
// duration: !isHorizontal ? 250 : 0
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
moveDisplaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x, y"
|
||||
duration: 300
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: trayView
|
||||
|
||||
property var itemWidth: isHorizontal ? root.trayItemSize + Meui.Units.largeSpacing * 2 : mainLayout.width * 0.7
|
||||
property var itemHeight: isHorizontal ? mainLayout.height * 0.7 : root.trayItemSize + Meui.Units.largeSpacing * 2
|
||||
|
||||
Layout.preferredWidth: isHorizontal ? itemWidth * count + count * trayView.spacing : mainLayout.width * 0.7
|
||||
Layout.preferredHeight: isHorizontal ? mainLayout.height * 0.7 : itemHeight * count + count * trayView.spacing
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
orientation: isHorizontal ? Qt.Horizontal : Qt.Vertical
|
||||
layoutDirection: Qt.RightToLeft
|
||||
interactive: false
|
||||
model: trayModel
|
||||
spacing: Meui.Units.smallSpacing
|
||||
clip: true
|
||||
|
||||
StatusNotifierModel {
|
||||
id: trayModel
|
||||
}
|
||||
|
||||
onCountChanged: delayCalcIconSize()
|
||||
|
||||
delegate: StandardItem {
|
||||
height: trayView.itemHeight
|
||||
width: trayView.itemWidth
|
||||
|
||||
Image {
|
||||
id: trayIcon
|
||||
anchors.centerIn: parent
|
||||
// source: iconName ? "image://icontheme/" + iconName
|
||||
// : iconBytes ? "data:image/png;base64," + iconBytes
|
||||
// : "image://icontheme/application-x-desktop"
|
||||
|
||||
source: iconName ? "image://icontheme/" + iconName : "image://icontheme/application-x-desktop"
|
||||
|
||||
width: root.trayItemSize
|
||||
height: root.trayItemSize
|
||||
sourceSize.width: root.trayItemSize
|
||||
sourceSize.height: root.trayItemSize
|
||||
asynchronous: true
|
||||
}
|
||||
|
||||
onClicked: trayModel.leftButtonClick(id)
|
||||
onRightClicked: trayModel.rightButtonClick(id)
|
||||
popupText: toolTip ? toolTip : title
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Meui.Units.smallSpacing
|
||||
}
|
||||
|
||||
ControlCenterItem {
|
||||
onWidthChanged: delayCalcIconSize()
|
||||
onHeightChanged: delayCalcIconSize()
|
||||
}
|
||||
}
|
||||
|
||||
ControlCenter {
|
||||
id: controlCenter
|
||||
}
|
||||
|
||||
Volume {
|
||||
id: volume
|
||||
}
|
||||
|
||||
Battery {
|
||||
id: battery
|
||||
}
|
||||
|
||||
NM.ConnectionIcon {
|
||||
id: connectionIconProvider
|
||||
}
|
||||
|
||||
NM.Network {
|
||||
id: network
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Settings
|
||||
|
||||
function onDirectionChanged() {
|
||||
popupTips.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: mainWindow
|
||||
|
||||
function onResizingFished() {
|
||||
root.calcIconSize()
|
||||
}
|
||||
|
||||
function onIconSizeChanged() {
|
||||
root.calcIconSize()
|
||||
}
|
||||
|
||||
function onPositionChanged() {
|
||||
root.delayCalcIconSize()
|
||||
}
|
||||
}
|
||||
}
|
104
resources.qrc
Normal file
|
@ -0,0 +1,104 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>qml/main.qml</file>
|
||||
<file>qml/DockItem.qml</file>
|
||||
<file>qml/AppItem.qml</file>
|
||||
<file>svg/launcher.svg</file>
|
||||
<file>svg/light/audio-volume-high-symbolic.svg</file>
|
||||
<file>svg/light/audio-volume-low-symbolic.svg</file>
|
||||
<file>svg/light/audio-volume-medium-symbolic.svg</file>
|
||||
<file>svg/light/audio-volume-muted-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-0-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-0-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-10-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-10-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-20-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-20-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-30-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-30-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-40-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-40-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-50-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-50-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-60-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-60-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-70-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-70-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-80-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-80-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-90-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-90-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-100-charging-symbolic.svg</file>
|
||||
<file>svg/light/battery-level-100-symbolic.svg</file>
|
||||
<file>svg/light/close_normal.svg</file>
|
||||
<file>svg/light/control.svg</file>
|
||||
<file>svg/light/minimize_normal.svg</file>
|
||||
<file>svg/light/restore_normal.svg</file>
|
||||
<file>svg/light/system-shutdown-symbolic.svg</file>
|
||||
<file>svg/dark/audio-volume-high-symbolic.svg</file>
|
||||
<file>svg/dark/audio-volume-low-symbolic.svg</file>
|
||||
<file>svg/dark/audio-volume-medium-symbolic.svg</file>
|
||||
<file>svg/dark/audio-volume-muted-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-0-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-0-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-10-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-10-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-20-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-20-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-30-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-30-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-40-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-40-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-50-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-50-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-60-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-60-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-70-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-70-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-80-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-80-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-90-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-90-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-100-charging-symbolic.svg</file>
|
||||
<file>svg/dark/battery-level-100-symbolic.svg</file>
|
||||
<file>svg/dark/close_normal.svg</file>
|
||||
<file>svg/dark/control.svg</file>
|
||||
<file>svg/dark/minimize_normal.svg</file>
|
||||
<file>svg/dark/restore_normal.svg</file>
|
||||
<file>svg/dark/system-shutdown-symbolic.svg</file>
|
||||
<file>qml/StandardItem.qml</file>
|
||||
<file>qml/ControlCenter.qml</file>
|
||||
<file>svg/dark/brightness.svg</file>
|
||||
<file>svg/light/brightness.svg</file>
|
||||
<file>qml/IconButton.qml</file>
|
||||
<file>svg/light/settings.svg</file>
|
||||
<file>svg/dark/settings.svg</file>
|
||||
<file>svg/dark/network-wired.svg</file>
|
||||
<file>svg/dark/network-wired-activated.svg</file>
|
||||
<file>svg/dark/network-wireless-connected-00.svg</file>
|
||||
<file>svg/dark/network-wireless-connected-25.svg</file>
|
||||
<file>svg/dark/network-wireless-connected-50.svg</file>
|
||||
<file>svg/dark/network-wireless-connected-75.svg</file>
|
||||
<file>svg/dark/network-wireless-connected-100.svg</file>
|
||||
<file>svg/light/network-wired.svg</file>
|
||||
<file>svg/light/network-wired-activated.svg</file>
|
||||
<file>svg/light/network-wireless-connected-00.svg</file>
|
||||
<file>svg/light/network-wireless-connected-25.svg</file>
|
||||
<file>svg/light/network-wireless-connected-50.svg</file>
|
||||
<file>svg/light/network-wireless-connected-75.svg</file>
|
||||
<file>svg/light/network-wireless-connected-100.svg</file>
|
||||
<file>qml/CardItem.qml</file>
|
||||
<file>svg/light/bluetooth-symbolic.svg</file>
|
||||
<file>qml/MprisController.qml</file>
|
||||
<file>svg/dark/media-playback-pause-symbolic.svg</file>
|
||||
<file>svg/dark/media-playback-start-symbolic.svg</file>
|
||||
<file>svg/dark/media-skip-backward-symbolic.svg</file>
|
||||
<file>svg/dark/media-skip-forward-symbolic.svg</file>
|
||||
<file>svg/light/media-playback-pause-symbolic.svg</file>
|
||||
<file>svg/light/media-playback-start-symbolic.svg</file>
|
||||
<file>svg/light/media-skip-backward-symbolic.svg</file>
|
||||
<file>svg/light/media-skip-forward-symbolic.svg</file>
|
||||
<file>qml/ControlCenterItem.qml</file>
|
||||
<file>svg/light/dark-mode.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
177
src/appearance.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (C) 2020 CyberOS 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 "appearance.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QDBusPendingCall>
|
||||
|
||||
Appearance::Appearance(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_interface("org.cyber.Settings",
|
||||
"/Theme",
|
||||
"org.cyber.Theme",
|
||||
QDBusConnection::sessionBus())
|
||||
, m_dockSettings(new QSettings(QSettings::UserScope, "cyberos", "dock"))
|
||||
, m_dockConfigWacher(new QFileSystemWatcher(this))
|
||||
, m_dockIconSize(0)
|
||||
, m_dockDirection(0)
|
||||
, m_fontPointSize(11)
|
||||
{
|
||||
m_dockIconSize = m_dockSettings->value("IconSize").toInt();
|
||||
m_dockDirection = m_dockSettings->value("Direction").toInt();
|
||||
|
||||
m_dockConfigWacher->addPath(m_dockSettings->fileName());
|
||||
connect(m_dockConfigWacher, &QFileSystemWatcher::fileChanged, this, [=] {
|
||||
m_dockSettings->sync();
|
||||
m_dockIconSize = m_dockSettings->value("IconSize").toInt();
|
||||
m_dockDirection = m_dockSettings->value("Direction").toInt();
|
||||
m_dockConfigWacher->addPath(m_dockSettings->fileName());
|
||||
emit dockIconSizeChanged();
|
||||
emit dockDirectionChanged();
|
||||
});
|
||||
|
||||
// Init
|
||||
if (m_interface.isValid()) {
|
||||
m_fontPointSize = m_interface.property("systemFontPointSize").toInt();
|
||||
|
||||
connect(&m_interface, SIGNAL(darkModeDimsWallpaerChanged()), this, SIGNAL(dimsWallpaperChanged()));
|
||||
}
|
||||
}
|
||||
|
||||
void Appearance::switchDarkMode(bool darkMode)
|
||||
{
|
||||
if (m_interface.isValid()) {
|
||||
m_interface.call("setDarkMode", darkMode);
|
||||
}
|
||||
}
|
||||
|
||||
bool Appearance::dimsWallpaper() const
|
||||
{
|
||||
return m_interface.property("darkModeDimsWallpaer").toBool();
|
||||
}
|
||||
|
||||
void Appearance::setDimsWallpaper(bool value)
|
||||
{
|
||||
m_interface.call("setDarkModeDimsWallpaer", value);
|
||||
}
|
||||
|
||||
int Appearance::dockIconSize() const
|
||||
{
|
||||
return m_dockIconSize;
|
||||
}
|
||||
|
||||
void Appearance::setDockIconSize(int dockIconSize)
|
||||
{
|
||||
if (m_dockIconSize == dockIconSize)
|
||||
return;
|
||||
|
||||
m_dockIconSize = dockIconSize;
|
||||
m_dockSettings->setValue("IconSize", m_dockIconSize);
|
||||
}
|
||||
|
||||
int Appearance::dockDirection() const
|
||||
{
|
||||
return m_dockDirection;
|
||||
}
|
||||
|
||||
void Appearance::setDockDirection(int dockDirection)
|
||||
{
|
||||
if (m_dockDirection == dockDirection)
|
||||
return;
|
||||
|
||||
m_dockDirection = dockDirection;
|
||||
m_dockSettings->setValue("Direction", m_dockDirection);
|
||||
}
|
||||
|
||||
void Appearance::setGenericFontFamily(const QString &name)
|
||||
{
|
||||
if (name.isEmpty())
|
||||
return;
|
||||
|
||||
QDBusInterface iface("org.cyber.Settings",
|
||||
"/Theme",
|
||||
"org.cyber.Theme",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (iface.isValid()) {
|
||||
iface.call("setSystemFont", name);
|
||||
}
|
||||
}
|
||||
|
||||
void Appearance::setFixedFontFamily(const QString &name)
|
||||
{
|
||||
if (name.isEmpty())
|
||||
return;
|
||||
|
||||
QDBusInterface iface("org.cyber.Settings",
|
||||
"/Theme",
|
||||
"org.cyber.Theme",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (iface.isValid()) {
|
||||
iface.call("setSystemFixedFont", name);
|
||||
}
|
||||
}
|
||||
|
||||
int Appearance::fontPointSize() const
|
||||
{
|
||||
return m_fontPointSize;
|
||||
}
|
||||
|
||||
void Appearance::setFontPointSize(int fontPointSize)
|
||||
{
|
||||
m_fontPointSize = fontPointSize;
|
||||
|
||||
QDBusInterface iface("org.cyber.Settings",
|
||||
"/Theme",
|
||||
"org.cyber.Theme",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (iface.isValid()) {
|
||||
iface.call("setSystemFontPointSize", m_fontPointSize * 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void Appearance::setAccentColor(int accentColor)
|
||||
{
|
||||
QDBusInterface iface("org.cyber.Settings",
|
||||
"/Theme",
|
||||
"org.cyber.Theme",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (iface.isValid()) {
|
||||
iface.call("setAccentColor", accentColor);
|
||||
}
|
||||
}
|
||||
|
||||
double Appearance::devicePixelRatio() const
|
||||
{
|
||||
return m_interface.property("devicePixelRatio").toDouble();
|
||||
}
|
||||
|
||||
void Appearance::setDevicePixelRatio(double value)
|
||||
{
|
||||
QDBusInterface iface("org.cyber.Settings",
|
||||
"/Theme",
|
||||
"org.cyber.Theme",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (iface.isValid()) {
|
||||
iface.call("setDevicePixelRatio", value);
|
||||
}
|
||||
}
|
79
src/appearance.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2020 CyberOS 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 APPEARANCE_H
|
||||
#define APPEARANCE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QDBusInterface>
|
||||
|
||||
class Appearance : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int dockIconSize READ dockIconSize WRITE setDockIconSize NOTIFY dockIconSizeChanged)
|
||||
Q_PROPERTY(int dockDirection READ dockDirection WRITE setDockDirection NOTIFY dockDirectionChanged)
|
||||
Q_PROPERTY(int fontPointSize READ fontPointSize WRITE setFontPointSize NOTIFY fontPointSizeChanged)
|
||||
Q_PROPERTY(bool dimsWallpaper READ dimsWallpaper WRITE setDimsWallpaper NOTIFY dimsWallpaperChanged)
|
||||
Q_PROPERTY(double devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio NOTIFY devicePixelRatioChanged)
|
||||
|
||||
public:
|
||||
explicit Appearance(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void switchDarkMode(bool darkMode);
|
||||
|
||||
bool dimsWallpaper() const;
|
||||
Q_INVOKABLE void setDimsWallpaper(bool value);
|
||||
|
||||
int dockIconSize() const;
|
||||
Q_INVOKABLE void setDockIconSize(int dockIconSize);
|
||||
|
||||
int dockDirection() const;
|
||||
Q_INVOKABLE void setDockDirection(int dockDirection);
|
||||
|
||||
Q_INVOKABLE void setGenericFontFamily(const QString &name);
|
||||
Q_INVOKABLE void setFixedFontFamily(const QString &name);
|
||||
|
||||
int fontPointSize() const;
|
||||
Q_INVOKABLE void setFontPointSize(int fontPointSize);
|
||||
|
||||
Q_INVOKABLE void setAccentColor(int accentColor);
|
||||
|
||||
double devicePixelRatio() const;
|
||||
Q_INVOKABLE void setDevicePixelRatio(double value);
|
||||
|
||||
signals:
|
||||
void dockIconSizeChanged();
|
||||
void dockDirectionChanged();
|
||||
void fontPointSizeChanged();
|
||||
void dimsWallpaperChanged();
|
||||
void devicePixelRatioChanged();
|
||||
|
||||
private:
|
||||
QDBusInterface m_interface;
|
||||
QSettings *m_dockSettings;
|
||||
QFileSystemWatcher *m_dockConfigWacher;
|
||||
|
||||
int m_dockIconSize;
|
||||
int m_dockDirection;
|
||||
int m_fontPointSize;
|
||||
};
|
||||
|
||||
#endif // APPEARANCE_H
|
29
src/applicationitem.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef APPLICATIONITEM_H
|
||||
#define APPLICATIONITEM_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class ApplicationItem
|
||||
{
|
||||
public:
|
||||
// window class
|
||||
QString id;
|
||||
// icon name
|
||||
QString iconName;
|
||||
// visible name
|
||||
QString visibleName;
|
||||
QString desktopPath;
|
||||
QString exec;
|
||||
|
||||
QList<quint64> wids;
|
||||
|
||||
int currentActive = 0;
|
||||
bool isActive = false;
|
||||
bool isPinned = false;
|
||||
|
||||
bool operator==(ApplicationItem item) {
|
||||
return item.id == this->id;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // APPLICATIONITEM_H
|
456
src/applicationmodel.cpp
Normal file
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "applicationmodel.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
ApplicationModel::ApplicationModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_iface(XWindowInterface::instance())
|
||||
, m_sysAppMonitor(SystemAppMonitor::self())
|
||||
{
|
||||
m_sysAppMonitor->moveToThread(qApp->thread());
|
||||
this->moveToThread(qApp->thread());
|
||||
|
||||
connect(m_iface, &XWindowInterface::windowAdded, this, &ApplicationModel::onWindowAdded);
|
||||
connect(m_iface, &XWindowInterface::windowRemoved, this, &ApplicationModel::onWindowRemoved);
|
||||
connect(m_iface, &XWindowInterface::activeChanged, this, &ApplicationModel::onActiveChanged);
|
||||
|
||||
initPinnedApplications();
|
||||
|
||||
QTimer::singleShot(100, m_iface, &XWindowInterface::startInitWindows);
|
||||
}
|
||||
|
||||
int ApplicationModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_appItems.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ApplicationModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[AppIdRole] = "appId";
|
||||
roles[IconNameRole] = "iconName";
|
||||
roles[VisibleNameRole] = "visibleName";
|
||||
roles[ActiveRole] = "isActive";
|
||||
roles[WindowCountRole] = "windowCount";
|
||||
roles[IsPinnedRole] = "isPinned";
|
||||
return roles;
|
||||
}
|
||||
|
||||
QVariant ApplicationModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
ApplicationItem *item = m_appItems.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case AppIdRole:
|
||||
return item->id;
|
||||
case IconNameRole:
|
||||
return item->iconName;
|
||||
case VisibleNameRole:
|
||||
return item->visibleName;
|
||||
case ActiveRole:
|
||||
return item->isActive;
|
||||
case WindowCountRole:
|
||||
return item->wids.count();
|
||||
case IsPinnedRole:
|
||||
return item->isPinned;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ApplicationModel::clicked(const QString &id)
|
||||
{
|
||||
ApplicationItem *item = findItemById(id);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
// Application Item that has been pinned,
|
||||
// We need to open it.
|
||||
if (item->wids.isEmpty()) {
|
||||
// open application
|
||||
openNewInstance(item->id);
|
||||
}
|
||||
// Multiple windows have been opened and need to switch between them,
|
||||
// The logic here needs to be improved.
|
||||
else if (item->wids.count() > 1) {
|
||||
item->currentActive++;
|
||||
|
||||
if (item->currentActive == item->wids.count())
|
||||
item->currentActive = 0;
|
||||
|
||||
m_iface->forceActiveWindow(item->wids.at(item->currentActive));
|
||||
} else if (m_iface->activeWindow() == item->wids.first()) {
|
||||
m_iface->minimizeWindow(item->wids.first());
|
||||
} else {
|
||||
m_iface->forceActiveWindow(item->wids.first());
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::raiseWindow(const QString &id)
|
||||
{
|
||||
ApplicationItem *item = findItemById(id);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
m_iface->forceActiveWindow(item->wids.at(item->currentActive));
|
||||
}
|
||||
|
||||
bool ApplicationModel::openNewInstance(const QString &appId)
|
||||
{
|
||||
ApplicationItem *item = findItemById(appId);
|
||||
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
QProcess process;
|
||||
if (!item->exec.isEmpty()) {
|
||||
QStringList args = item->exec.split(" ");
|
||||
process.setProgram(args.first());
|
||||
args.removeFirst();
|
||||
|
||||
if (!args.isEmpty()) {
|
||||
process.setArguments(args);
|
||||
}
|
||||
|
||||
} else {
|
||||
process.setProgram(appId);
|
||||
}
|
||||
|
||||
return process.startDetached();
|
||||
}
|
||||
|
||||
void ApplicationModel::closeAllByAppId(const QString &appId)
|
||||
{
|
||||
ApplicationItem *item = findItemById(appId);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
for (quint64 wid : item->wids) {
|
||||
m_iface->closeWindow(wid);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::pin(const QString &appId)
|
||||
{
|
||||
ApplicationItem *item = findItemById(appId);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item->isPinned = true;
|
||||
|
||||
handleDataChangedFromItem(item);
|
||||
savePinAndUnPinList();
|
||||
}
|
||||
|
||||
void ApplicationModel::unPin(const QString &appId)
|
||||
{
|
||||
ApplicationItem *item = findItemById(appId);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item->isPinned = false;
|
||||
handleDataChangedFromItem(item);
|
||||
|
||||
// Need to be removed after unpin
|
||||
if (item->wids.isEmpty()) {
|
||||
int index = indexOf(item->id);
|
||||
if (index != -1) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_appItems.removeAll(item);
|
||||
endRemoveRows();
|
||||
|
||||
emit itemRemoved();
|
||||
emit countChanged();
|
||||
}
|
||||
}
|
||||
|
||||
savePinAndUnPinList();
|
||||
}
|
||||
|
||||
void ApplicationModel::updateGeometries(const QString &id, QRect rect)
|
||||
{
|
||||
ApplicationItem *item = findItemById(id);
|
||||
|
||||
// If not found
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
for (quint64 id : item->wids) {
|
||||
m_iface->setIconGeometry(id, rect);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::move(int from, int to)
|
||||
{
|
||||
if (from == to)
|
||||
return;
|
||||
|
||||
m_appItems.move(from, to);
|
||||
|
||||
if (from < to)
|
||||
beginMoveRows(QModelIndex(), from, from, QModelIndex(), to + 1);
|
||||
else
|
||||
beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
|
||||
|
||||
endMoveRows();
|
||||
}
|
||||
|
||||
ApplicationItem *ApplicationModel::findItemByWId(quint64 wid)
|
||||
{
|
||||
for (ApplicationItem *item : m_appItems) {
|
||||
for (quint64 winId : item->wids) {
|
||||
if (winId == wid)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ApplicationItem *ApplicationModel::findItemById(const QString &id)
|
||||
{
|
||||
for (ApplicationItem *item : m_appItems) {
|
||||
if (item->id == id)
|
||||
return item;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ApplicationModel::contains(const QString &id)
|
||||
{
|
||||
for (ApplicationItem *item : qAsConst(m_appItems)) {
|
||||
if (item->id == id)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ApplicationModel::indexOf(const QString &id)
|
||||
{
|
||||
for (ApplicationItem *item : m_appItems) {
|
||||
if (item->id == id)
|
||||
return m_appItems.indexOf(item);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ApplicationModel::initPinnedApplications()
|
||||
{
|
||||
QSettings settings(QSettings::UserScope, "cyberos", "dock_pinned");
|
||||
QStringList groups = settings.childGroups();
|
||||
|
||||
// Launcher
|
||||
ApplicationItem *item = new ApplicationItem;
|
||||
item->id = "cyber-launcher";
|
||||
item->exec = "cyber-launcher";
|
||||
item->iconName = "qrc:/svg/launcher.svg";
|
||||
item->visibleName = tr("Launcher");
|
||||
m_appItems.append(item);
|
||||
|
||||
// Pinned Apps
|
||||
for (int i = 0; i < groups.size(); ++i) {
|
||||
for (const QString &id : groups) {
|
||||
settings.beginGroup(id);
|
||||
int index = settings.value("Index").toInt();
|
||||
|
||||
if (index == i) {
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
ApplicationItem *item = new ApplicationItem;
|
||||
|
||||
item->desktopPath = settings.value("DesktopPath").toString();
|
||||
item->id = id;
|
||||
item->isPinned = true;
|
||||
|
||||
// Read from desktop file.
|
||||
if (!item->desktopPath.isEmpty()) {
|
||||
QMap<QString, QString> desktopInfo = Utils::instance()->readInfoFromDesktop(item->desktopPath);
|
||||
item->iconName = desktopInfo.value("Icon");
|
||||
item->visibleName = desktopInfo.value("Name");
|
||||
item->exec = desktopInfo.value("Exec");
|
||||
}
|
||||
|
||||
// Read from config file.
|
||||
if (item->iconName.isEmpty())
|
||||
item->iconName = settings.value("Icon").toString();
|
||||
|
||||
if (item->visibleName.isEmpty())
|
||||
item->visibleName = settings.value("VisibleName").toString();
|
||||
|
||||
if (item->exec.isEmpty())
|
||||
item->exec = settings.value("Exec").toString();
|
||||
|
||||
m_appItems.append(item);
|
||||
endInsertRows();
|
||||
|
||||
emit itemAdded();
|
||||
emit countChanged();
|
||||
|
||||
settings.endGroup();
|
||||
break;
|
||||
} else {
|
||||
settings.endGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::savePinAndUnPinList()
|
||||
{
|
||||
QSettings settings(QSettings::UserScope, "cyberos", "dock_pinned");
|
||||
settings.clear();
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (ApplicationItem *item : m_appItems) {
|
||||
if (item->isPinned) {
|
||||
settings.beginGroup(item->id);
|
||||
settings.setValue("Index", index);
|
||||
settings.setValue("Icon", item->iconName);
|
||||
settings.setValue("VisibleName", item->visibleName);
|
||||
settings.setValue("Exec", item->exec);
|
||||
settings.setValue("DesktopPath", item->desktopPath);
|
||||
settings.endGroup();
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
void ApplicationModel::handleDataChangedFromItem(ApplicationItem *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QModelIndex idx = index(indexOf(item->id), 0, QModelIndex());
|
||||
|
||||
if (idx.isValid()) {
|
||||
emit dataChanged(idx, idx);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::onWindowAdded(quint64 wid)
|
||||
{
|
||||
QMap<QString, QVariant> info = m_iface->requestInfo(wid);
|
||||
const QString id = info.value("id").toString();
|
||||
|
||||
if (contains(id)) {
|
||||
for (ApplicationItem *item : m_appItems) {
|
||||
if (item->id == id) {
|
||||
item->wids.append(wid);
|
||||
// Need to update application active status.
|
||||
item->isActive = info.value("active").toBool();
|
||||
handleDataChangedFromItem(item);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
ApplicationItem *item = new ApplicationItem;
|
||||
item->id = id;
|
||||
item->iconName = info.value("iconName").toString();
|
||||
item->visibleName = info.value("visibleName").toString();
|
||||
item->isActive = info.value("active").toBool();
|
||||
item->wids.append(wid);
|
||||
|
||||
QString desktopPath = m_iface->desktopFilePath(wid);
|
||||
|
||||
if (!desktopPath.isEmpty()) {
|
||||
QMap<QString, QString> desktopInfo = Utils::instance()->readInfoFromDesktop(desktopPath);
|
||||
item->iconName = desktopInfo.value("Icon");
|
||||
item->visibleName = desktopInfo.value("Name");
|
||||
item->exec = desktopInfo.value("Exec");
|
||||
item->desktopPath = desktopPath;
|
||||
}
|
||||
|
||||
m_appItems << item;
|
||||
endInsertRows();
|
||||
|
||||
emit itemAdded();
|
||||
emit countChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::onWindowRemoved(quint64 wid)
|
||||
{
|
||||
ApplicationItem *item = findItemByWId(wid);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
// Remove from wid list.
|
||||
item->wids.removeOne(wid);
|
||||
|
||||
if (item->currentActive >= item->wids.size())
|
||||
item->currentActive = 0;
|
||||
|
||||
handleDataChangedFromItem(item);
|
||||
|
||||
if (item->wids.isEmpty()) {
|
||||
// If it is not fixed to the dock, need to remove it.
|
||||
if (!item->isPinned) {
|
||||
int index = indexOf(item->id);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_appItems.removeAll(item);
|
||||
endRemoveRows();
|
||||
|
||||
emit itemRemoved();
|
||||
emit countChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationModel::onActiveChanged(quint64 wid)
|
||||
{
|
||||
// Using this method will cause the listview scrollbar to reset.
|
||||
// beginResetModel();
|
||||
|
||||
for (ApplicationItem *item : m_appItems) {
|
||||
if (item->isActive != item->wids.contains(wid)) {
|
||||
item->isActive = item->wids.contains(wid);
|
||||
|
||||
QModelIndex idx = index(indexOf(item->id), 0, QModelIndex());
|
||||
if (idx.isValid()) {
|
||||
emit dataChanged(idx, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
88
src/applicationmodel.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 APPLICATIONMODEL_H
|
||||
#define APPLICATIONMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "applicationitem.h"
|
||||
#include "systemappmonitor.h"
|
||||
#include "xwindowinterface.h"
|
||||
|
||||
class ApplicationModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
AppIdRole = Qt::UserRole + 1,
|
||||
IconNameRole,
|
||||
VisibleNameRole,
|
||||
ActiveRole,
|
||||
WindowCountRole,
|
||||
IsPinnedRole
|
||||
};
|
||||
|
||||
explicit ApplicationModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
Q_INVOKABLE void save() { savePinAndUnPinList(); }
|
||||
|
||||
Q_INVOKABLE void clicked(const QString &id);
|
||||
Q_INVOKABLE void raiseWindow(const QString &id);
|
||||
|
||||
Q_INVOKABLE bool openNewInstance(const QString &appId);
|
||||
Q_INVOKABLE void closeAllByAppId(const QString &appId);
|
||||
Q_INVOKABLE void pin(const QString &appId);
|
||||
Q_INVOKABLE void unPin(const QString &appId);
|
||||
|
||||
Q_INVOKABLE void updateGeometries(const QString &id, QRect rect);
|
||||
|
||||
Q_INVOKABLE void move(int from, int to);
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
void itemAdded();
|
||||
void itemRemoved();
|
||||
|
||||
private:
|
||||
ApplicationItem *findItemByWId(quint64 wid);
|
||||
ApplicationItem *findItemById(const QString &id);
|
||||
bool contains(const QString &id);
|
||||
int indexOf(const QString &id);
|
||||
void initPinnedApplications();
|
||||
void savePinAndUnPinList();
|
||||
|
||||
void handleDataChangedFromItem(ApplicationItem *item);
|
||||
|
||||
void onWindowAdded(quint64 wid);
|
||||
void onWindowRemoved(quint64 wid);
|
||||
void onActiveChanged(quint64 wid);
|
||||
|
||||
private:
|
||||
XWindowInterface *m_iface;
|
||||
SystemAppMonitor *m_sysAppMonitor;
|
||||
QList<ApplicationItem *> m_appItems;
|
||||
};
|
||||
|
||||
#endif // APPLICATIONMODEL_H
|
130
src/battery.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include "battery.h"
|
||||
|
||||
static const QString s_sServer = "org.cyber.Settings";
|
||||
static const QString s_sPath = "/PrimaryBattery";
|
||||
static const QString s_sInterface = "org.cyber.PrimaryBattery";
|
||||
|
||||
Battery::Battery(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_upowerInterface("org.freedesktop.UPower",
|
||||
"/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower",
|
||||
QDBusConnection::systemBus())
|
||||
, m_interface("org.cyber.Settings",
|
||||
"/PrimaryBattery",
|
||||
"org.cyber.PrimaryBattery",
|
||||
QDBusConnection::sessionBus())
|
||||
, m_available(false)
|
||||
, m_onBattery(false)
|
||||
{
|
||||
m_available = m_interface.isValid() && !m_interface.lastError().isValid();
|
||||
|
||||
if (m_available) {
|
||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "chargeStateChanged", this, SLOT(chargeStateChanged(int)));
|
||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "chargePercentChanged", this, SLOT(chargePercentChanged(int)));
|
||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "lastChargedPercentChanged", this, SLOT(lastChargedPercentChanged()));
|
||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "capacityChanged", this, SLOT(capacityChanged(int)));
|
||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "remainingTimeChanged", this, SLOT(remainingTimeChanged(qlonglong)));
|
||||
|
||||
// Update Icon
|
||||
QDBusConnection::sessionBus().connect(s_sServer, s_sPath, s_sInterface, "chargePercentChanged", this, SLOT(iconSourceChanged()));
|
||||
|
||||
QDBusInterface interface("org.freedesktop.UPower", "/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower", QDBusConnection::systemBus());
|
||||
|
||||
QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged", this,
|
||||
SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)));
|
||||
|
||||
if (interface.isValid()) {
|
||||
m_onBattery = interface.property("OnBattery").toBool();
|
||||
}
|
||||
|
||||
emit validChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool Battery::available() const
|
||||
{
|
||||
return m_available;
|
||||
}
|
||||
|
||||
bool Battery::onBattery() const
|
||||
{
|
||||
return m_onBattery;
|
||||
}
|
||||
|
||||
int Battery::chargeState() const
|
||||
{
|
||||
return m_interface.property("chargeState").toInt();
|
||||
}
|
||||
|
||||
int Battery::chargePercent() const
|
||||
{
|
||||
return m_interface.property("chargePercent").toInt();
|
||||
}
|
||||
|
||||
int Battery::lastChargedPercent() const
|
||||
{
|
||||
return m_interface.property("lastChargedPercent").toInt();
|
||||
}
|
||||
|
||||
int Battery::capacity() const
|
||||
{
|
||||
return m_interface.property("capacity").toInt();
|
||||
}
|
||||
|
||||
QString Battery::statusString() const
|
||||
{
|
||||
return m_interface.property("statusString").toString();
|
||||
}
|
||||
|
||||
QString Battery::iconSource() const
|
||||
{
|
||||
int percent = this->chargePercent();
|
||||
int range = 0;
|
||||
|
||||
if (percent >= 95)
|
||||
range = 100;
|
||||
else if (percent >= 85)
|
||||
range = 90;
|
||||
else if (percent>= 75)
|
||||
range = 80;
|
||||
else if (percent >= 65)
|
||||
range = 70;
|
||||
else if (percent >= 55)
|
||||
range = 60;
|
||||
else if (percent >= 45)
|
||||
range = 50;
|
||||
else if (percent >= 35)
|
||||
range = 40;
|
||||
else if (percent >= 25)
|
||||
range = 30;
|
||||
else if (percent >= 15)
|
||||
range = 20;
|
||||
else if (percent >= 5)
|
||||
range = 10;
|
||||
else
|
||||
range = 0;
|
||||
|
||||
if (m_onBattery)
|
||||
return QString("battery-level-%1-symbolic.svg").arg(range);
|
||||
|
||||
return QString("battery-level-%1-charging-symbolic.svg").arg(range);
|
||||
}
|
||||
|
||||
void Battery::onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps)
|
||||
{
|
||||
Q_UNUSED(ifaceName);
|
||||
Q_UNUSED(changedProps);
|
||||
Q_UNUSED(invalidatedProps);
|
||||
|
||||
bool onBattery = m_upowerInterface.property("OnBattery").toBool();
|
||||
if (onBattery != m_onBattery) {
|
||||
m_onBattery = onBattery;
|
||||
m_interface.call("refresh");
|
||||
emit onBatteryChanged();
|
||||
emit iconSourceChanged();
|
||||
}
|
||||
}
|
53
src/battery.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef BATTERY_H
|
||||
#define BATTERY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
|
||||
class Battery : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool available READ available NOTIFY validChanged)
|
||||
Q_PROPERTY(int chargeState READ chargeState NOTIFY chargeStateChanged)
|
||||
Q_PROPERTY(int chargePercent READ chargePercent NOTIFY chargePercentChanged)
|
||||
Q_PROPERTY(int lastChargedPercent READ lastChargedPercent NOTIFY lastChargedPercentChanged)
|
||||
Q_PROPERTY(int capacity READ capacity NOTIFY capacityChanged)
|
||||
Q_PROPERTY(QString statusString READ statusString NOTIFY remainingTimeChanged)
|
||||
Q_PROPERTY(bool onBattery READ onBattery NOTIFY onBatteryChanged)
|
||||
Q_PROPERTY(QString iconSource READ iconSource NOTIFY iconSourceChanged)
|
||||
|
||||
public:
|
||||
explicit Battery(QObject *parent = nullptr);
|
||||
|
||||
bool available() const;
|
||||
bool onBattery() const;
|
||||
|
||||
int chargeState() const;
|
||||
int chargePercent() const;
|
||||
int lastChargedPercent() const;
|
||||
int capacity() const;
|
||||
QString statusString() const;
|
||||
|
||||
QString iconSource() const;
|
||||
|
||||
signals:
|
||||
void validChanged();
|
||||
void chargeStateChanged(int);
|
||||
void chargePercentChanged(int);
|
||||
void capacityChanged(int);
|
||||
void remainingTimeChanged(qlonglong time);
|
||||
void onBatteryChanged();
|
||||
void lastChargedPercentChanged();
|
||||
void iconSourceChanged();
|
||||
|
||||
private slots:
|
||||
void onPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps);
|
||||
|
||||
private:
|
||||
QDBusInterface m_upowerInterface;
|
||||
QDBusInterface m_interface;
|
||||
bool m_available;
|
||||
bool m_onBattery;
|
||||
};
|
||||
|
||||
#endif // BATTERY_H
|
51
src/brightness.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2020 CyberOS 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 "brightness.h"
|
||||
|
||||
Brightness::Brightness(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_dbusConnection(QDBusConnection::sessionBus())
|
||||
, m_iface("org.cyber.Settings",
|
||||
"/Brightness",
|
||||
"org.cyber.Brightness", m_dbusConnection)
|
||||
, m_value(0)
|
||||
, m_enabled(false)
|
||||
{
|
||||
if (!m_iface.isValid())
|
||||
return;
|
||||
|
||||
m_value = m_iface.property("brightness").toInt();
|
||||
m_enabled = m_iface.property("brightnessEnabled").toBool();
|
||||
}
|
||||
|
||||
void Brightness::setValue(int value)
|
||||
{
|
||||
m_iface.call("setValue", value);
|
||||
}
|
||||
|
||||
int Brightness::value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool Brightness::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
50
src/brightness.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2020 CyberOS 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 BRIGHTNESS_H
|
||||
#define BRIGHTNESS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
|
||||
class Brightness : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int value READ value NOTIFY valueChanged)
|
||||
Q_PROPERTY(bool enabled READ enabled CONSTANT)
|
||||
|
||||
public:
|
||||
explicit Brightness(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void setValue(int value);
|
||||
|
||||
int value() const;
|
||||
bool enabled() const;
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
private:
|
||||
QDBusConnection m_dbusConnection;
|
||||
QDBusInterface m_iface;
|
||||
int m_value;
|
||||
bool m_enabled;
|
||||
};
|
||||
|
||||
#endif // BRIGHTNESS_H
|
25
src/controlcenterdialog.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "controlcenterdialog.h"
|
||||
#include "xwindowinterface.h"
|
||||
#include <KWindowSystem>
|
||||
|
||||
ControlCenterDialog::ControlCenterDialog(QQuickView *parent)
|
||||
: QQuickView(parent)
|
||||
{
|
||||
setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
||||
|
||||
connect(this, &QQuickView::activeChanged, this, [=] {
|
||||
if (!isActive())
|
||||
hide();
|
||||
});
|
||||
}
|
||||
|
||||
void ControlCenterDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher);
|
||||
QQuickView::showEvent(event);
|
||||
}
|
||||
|
||||
void ControlCenterDialog::hideEvent(QHideEvent *event)
|
||||
{
|
||||
QQuickView::hideEvent(event);
|
||||
}
|
19
src/controlcenterdialog.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef CONTROLCENTERDIALOG_H
|
||||
#define CONTROLCENTERDIALOG_H
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QTimer>
|
||||
|
||||
class ControlCenterDialog : public QQuickView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ControlCenterDialog(QQuickView *view = nullptr);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // CONTROLCENTERDIALOG_H
|
141
src/docksettings.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "docksettings.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QDBusInterface>
|
||||
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
static DockSettings *SELF = nullptr;
|
||||
|
||||
DockSettings *DockSettings::self()
|
||||
{
|
||||
if (SELF == nullptr)
|
||||
SELF = new DockSettings;
|
||||
|
||||
return SELF;
|
||||
}
|
||||
|
||||
DockSettings::DockSettings(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_iconSize(0)
|
||||
, m_edgeMargins(10)
|
||||
, m_statusBarHeight(30)
|
||||
, m_direction(Left)
|
||||
, m_visibility(AlwaysVisible)
|
||||
, m_settings(new QSettings(QSettings::UserScope, "cyberos", "dock"))
|
||||
, m_fileWatcher(new QFileSystemWatcher(this))
|
||||
{
|
||||
if (!m_settings->contains("IconSize"))
|
||||
m_settings->setValue("IconSize", 64);
|
||||
if (!m_settings->contains("Direction"))
|
||||
m_settings->setValue("Direction", Bottom);
|
||||
if (!m_settings->contains("Visibility"))
|
||||
m_settings->setValue("Visibility", AlwaysVisible);
|
||||
|
||||
m_settings->sync();
|
||||
|
||||
m_iconSize = m_settings->value("IconSize").toInt();
|
||||
m_direction = static_cast<Direction>(m_settings->value("Direction").toInt());
|
||||
|
||||
m_fileWatcher->addPath(m_settings->fileName());
|
||||
connect(m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &DockSettings::onConfigFileChanged);
|
||||
}
|
||||
|
||||
int DockSettings::iconSize() const
|
||||
{
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
void DockSettings::setIconSize(int iconSize)
|
||||
{
|
||||
m_iconSize = iconSize;
|
||||
emit iconSizeChanged();
|
||||
}
|
||||
|
||||
DockSettings::Direction DockSettings::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
void DockSettings::setDirection(const Direction &direction)
|
||||
{
|
||||
m_direction = direction;
|
||||
emit directionChanged();
|
||||
}
|
||||
|
||||
DockSettings::Visibility DockSettings::visibility() const
|
||||
{
|
||||
return m_visibility;
|
||||
}
|
||||
|
||||
void DockSettings::setVisibility(const DockSettings::Visibility &visibility)
|
||||
{
|
||||
if (m_visibility != visibility) {
|
||||
m_visibility = visibility;
|
||||
emit visibilityChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int DockSettings::edgeMargins() const
|
||||
{
|
||||
return m_edgeMargins;
|
||||
}
|
||||
|
||||
void DockSettings::setEdgeMargins(int edgeMargins)
|
||||
{
|
||||
m_edgeMargins = edgeMargins;
|
||||
}
|
||||
|
||||
int DockSettings::statusBarHeight() const
|
||||
{
|
||||
return m_statusBarHeight;
|
||||
}
|
||||
|
||||
void DockSettings::setStatusBarHeight(int statusBarHeight)
|
||||
{
|
||||
m_statusBarHeight = statusBarHeight;
|
||||
}
|
||||
|
||||
void DockSettings::onConfigFileChanged()
|
||||
{
|
||||
if (!QFile(m_settings->fileName()).exists())
|
||||
return;
|
||||
|
||||
m_settings->sync();
|
||||
|
||||
int iconSize = m_settings->value("IconSize").toInt();
|
||||
Direction direction = static_cast<Direction>(m_settings->value("Direction").toInt());
|
||||
Visibility visibility = static_cast<Visibility>(m_settings->value("Visibility").toInt());
|
||||
|
||||
if (m_iconSize != iconSize)
|
||||
setIconSize(iconSize);
|
||||
|
||||
if (m_direction != direction)
|
||||
setDirection(direction);
|
||||
|
||||
if (m_visibility != visibility)
|
||||
setVisibility(visibility);
|
||||
|
||||
m_fileWatcher->addPath(m_settings->fileName());
|
||||
}
|
84
src/docksettings.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 DOCKSETTINGS_H
|
||||
#define DOCKSETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
class DockSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged)
|
||||
Q_PROPERTY(int iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
|
||||
Q_PROPERTY(int edgeMargins READ edgeMargins WRITE setEdgeMargins)
|
||||
|
||||
public:
|
||||
enum Direction {
|
||||
Left = 0,
|
||||
Bottom
|
||||
};
|
||||
Q_ENUMS(Direction)
|
||||
|
||||
enum Visibility {
|
||||
AlwaysVisible = 0,
|
||||
AutoHide,
|
||||
AlwaysHide
|
||||
};
|
||||
Q_ENUMS(Visibility)
|
||||
|
||||
static DockSettings *self();
|
||||
explicit DockSettings(QObject *parent = nullptr);
|
||||
|
||||
int iconSize() const;
|
||||
void setIconSize(int iconSize);
|
||||
|
||||
Direction direction() const;
|
||||
void setDirection(const Direction &direction);
|
||||
|
||||
Visibility visibility() const;
|
||||
void setVisibility(const Visibility &visibility);
|
||||
|
||||
int edgeMargins() const;
|
||||
void setEdgeMargins(int edgeMargins);
|
||||
|
||||
int statusBarHeight() const;
|
||||
void setStatusBarHeight(int statusBarHeight);
|
||||
|
||||
private slots:
|
||||
void onConfigFileChanged();
|
||||
|
||||
signals:
|
||||
void iconSizeChanged();
|
||||
void directionChanged();
|
||||
void visibilityChanged();
|
||||
|
||||
private:
|
||||
int m_iconSize;
|
||||
int m_edgeMargins;
|
||||
int m_statusBarHeight;
|
||||
Direction m_direction;
|
||||
Visibility m_visibility;
|
||||
QSettings *m_settings;
|
||||
QFileSystemWatcher *m_fileWatcher;
|
||||
};
|
||||
|
||||
#endif // DOCKSETTINGS_H
|
98
src/fakewindow.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
#include "fakewindow.h"
|
||||
#include "docksettings.h"
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QQuickView>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
|
||||
#include <KWindowSystem>
|
||||
|
||||
// X11
|
||||
#include <NETWM>
|
||||
|
||||
FakeWindow::FakeWindow(QQuickView *parent)
|
||||
: QQuickView(parent)
|
||||
, m_delayedContainsMouse(false)
|
||||
, m_containsMouse(false)
|
||||
{
|
||||
setColor(Qt::red);
|
||||
setDefaultAlphaBuffer(true);
|
||||
setFlags(Qt::FramelessWindowHint |
|
||||
Qt::WindowStaysOnTopHint |
|
||||
Qt::NoDropShadowWindowHint |
|
||||
Qt::WindowDoesNotAcceptFocus);
|
||||
setScreen(qApp->primaryScreen());
|
||||
updateGeometry();
|
||||
show();
|
||||
|
||||
m_delayedMouseTimer.setSingleShot(true);
|
||||
m_delayedMouseTimer.setInterval(50);
|
||||
connect(&m_delayedMouseTimer, &QTimer::timeout, this, [this]() {
|
||||
if (m_delayedContainsMouse) {
|
||||
setContainsMouse(true);
|
||||
} else {
|
||||
setContainsMouse(false);
|
||||
}
|
||||
});
|
||||
|
||||
connect(DockSettings::self(), &DockSettings::directionChanged, this, &FakeWindow::updateGeometry);
|
||||
}
|
||||
|
||||
bool FakeWindow::containsMouse() const
|
||||
{
|
||||
return m_containsMouse;
|
||||
}
|
||||
|
||||
bool FakeWindow::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::DragEnter || e->type() == QEvent::DragMove) {
|
||||
if (!m_containsMouse) {
|
||||
m_delayedContainsMouse = false;
|
||||
m_delayedMouseTimer.stop();
|
||||
setContainsMouse(true);
|
||||
emit dragEntered();
|
||||
}
|
||||
} else if (e->type() == QEvent::Enter) {
|
||||
m_delayedContainsMouse = true;
|
||||
if (!m_delayedMouseTimer.isActive()) {
|
||||
m_delayedMouseTimer.start();
|
||||
}
|
||||
} else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) {
|
||||
m_delayedContainsMouse = false;
|
||||
if (!m_delayedMouseTimer.isActive()) {
|
||||
m_delayedMouseTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
return QQuickView::event(e);
|
||||
}
|
||||
|
||||
void FakeWindow::setContainsMouse(bool contains)
|
||||
{
|
||||
if (m_containsMouse != contains) {
|
||||
m_containsMouse = contains;
|
||||
emit containsMouseChanged(contains);
|
||||
}
|
||||
}
|
||||
|
||||
void FakeWindow::updateGeometry()
|
||||
{
|
||||
int length = 10;
|
||||
const QRect screenRect = qApp->primaryScreen()->geometry();
|
||||
QRect newRect;
|
||||
|
||||
if (DockSettings::self()->direction() == DockSettings::Left) {
|
||||
newRect = QRect(screenRect.x() - (length * 2), (screenRect.height() + length) / 2,
|
||||
length, screenRect.height());
|
||||
} else if (DockSettings::self()->direction() == DockSettings::Bottom) {
|
||||
newRect = QRect(screenRect.x(),
|
||||
screenRect.y() + screenRect.height() - length,
|
||||
screenRect.width(), length);
|
||||
}
|
||||
|
||||
setGeometry(newRect);
|
||||
}
|
34
src/fakewindow.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef FAKEWINDOW_H
|
||||
#define FAKEWINDOW_H
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QTimer>
|
||||
|
||||
class FakeWindow : public QQuickView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FakeWindow(QQuickView *parent = nullptr);
|
||||
|
||||
bool containsMouse() const;
|
||||
|
||||
signals:
|
||||
void containsMouseChanged(bool contains);
|
||||
void dragEntered();
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void setContainsMouse(bool contains);
|
||||
void updateGeometry();
|
||||
|
||||
private:
|
||||
QTimer m_delayedMouseTimer;
|
||||
|
||||
bool m_delayedContainsMouse;
|
||||
bool m_containsMouse;
|
||||
};
|
||||
|
||||
#endif // FAKEWINDOW_H
|
33
src/iconthemeimageprovider.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "iconthemeimageprovider.h"
|
||||
#include <QIcon>
|
||||
|
||||
IconThemeImageProvider::IconThemeImageProvider()
|
||||
: QQuickImageProvider(QQuickImageProvider::Pixmap)
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap IconThemeImageProvider::requestPixmap(const QString &id, QSize *realSize,
|
||||
const QSize &requestedSize)
|
||||
{
|
||||
// Sanitize requested size
|
||||
QSize size(requestedSize);
|
||||
if (size.width() < 1)
|
||||
size.setWidth(1);
|
||||
if (size.height() < 1)
|
||||
size.setHeight(1);
|
||||
|
||||
// Return real size
|
||||
if (realSize)
|
||||
*realSize = size;
|
||||
|
||||
// Is it a path?
|
||||
if (id.startsWith(QLatin1Char('/')))
|
||||
return QPixmap(id).scaled(size);
|
||||
|
||||
// Return icon from theme or fallback to a generic icon
|
||||
QIcon icon = QIcon::fromTheme(id);
|
||||
if (icon.isNull())
|
||||
icon = QIcon::fromTheme(QLatin1String("application-x-desktop"));
|
||||
|
||||
return icon.pixmap(size);
|
||||
}
|
14
src/iconthemeimageprovider.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef ICONTHEMEIMAGEPROVIDER_H
|
||||
#define ICONTHEMEIMAGEPROVIDER_H
|
||||
|
||||
#include <QtQuick/QQuickImageProvider>
|
||||
|
||||
class IconThemeImageProvider : public QQuickImageProvider
|
||||
{
|
||||
public:
|
||||
IconThemeImageProvider();
|
||||
|
||||
QPixmap requestPixmap(const QString &id, QSize *realSize, const QSize &requestedSize);
|
||||
};
|
||||
|
||||
#endif // ICONTHEMEIMAGEPROVIDER_H
|
47
src/main.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickView>
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
|
||||
#include "applicationmodel.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cyber-dock/translations/").arg(QLocale::system().name());
|
||||
if (QFile::exists(qmFilePath)) {
|
||||
QTranslator *translator = new QTranslator(QApplication::instance());
|
||||
if (translator->load(qmFilePath)) {
|
||||
QGuiApplication::installTranslator(translator);
|
||||
} else {
|
||||
translator->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow w;
|
||||
|
||||
return app.exec();
|
||||
}
|
190
src/mainwindow.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "mainwindow.h"
|
||||
#include "iconthemeimageprovider.h"
|
||||
#include "processprovider.h"
|
||||
#include "volumemanager.h"
|
||||
#include "battery.h"
|
||||
#include "brightness.h"
|
||||
#include "controlcenterdialog.h"
|
||||
#include "statusnotifier/statusnotifiermodel.h"
|
||||
#include "appearance.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
|
||||
#include <QQmlContext>
|
||||
#include <QQmlProperty>
|
||||
#include <QQuickItem>
|
||||
#include <QMetaEnum>
|
||||
|
||||
#include <NETWM>
|
||||
#include <KWindowSystem>
|
||||
#include <KWindowEffects>
|
||||
|
||||
MainWindow::MainWindow(QQuickView *parent)
|
||||
: QQuickView(parent)
|
||||
, m_settings(DockSettings::self())
|
||||
, m_appModel(new ApplicationModel)
|
||||
, m_fakeWindow(nullptr)
|
||||
{
|
||||
qmlRegisterType<DockSettings>("Cyber.Dock", 1, 0, "DockSettings");
|
||||
qmlRegisterType<VolumeManager>("Cyber.Dock", 1, 0, "Volume");
|
||||
qmlRegisterType<Battery>("Cyber.Dock", 1, 0, "Battery");
|
||||
qmlRegisterType<Brightness>("Cyber.Dock", 1, 0, "Brightness");
|
||||
qmlRegisterType<ControlCenterDialog>("Cyber.Dock", 1, 0, "ControlCenterDialog");
|
||||
qmlRegisterType<StatusNotifierModel>("Cyber.Dock", 1, 0, "StatusNotifierModel");
|
||||
qmlRegisterType<Appearance>("Cyber.Dock", 1, 0, "Appearance");
|
||||
|
||||
setDefaultAlphaBuffer(false);
|
||||
setColor(Qt::transparent);
|
||||
|
||||
setFlags(Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
|
||||
KWindowSystem::setOnDesktop(winId(), NET::OnAllDesktops);
|
||||
KWindowSystem::setType(winId(), NET::Dock);
|
||||
|
||||
engine()->rootContext()->setContextProperty("appModel", m_appModel);
|
||||
engine()->rootContext()->setContextProperty("process", new ProcessProvider);
|
||||
engine()->rootContext()->setContextProperty("Settings", m_settings);
|
||||
engine()->rootContext()->setContextProperty("mainWindow", this);
|
||||
|
||||
setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
// setClearBeforeRendering(true);
|
||||
setScreen(qApp->primaryScreen());
|
||||
setSource(QUrl(QStringLiteral("qrc:/qml/main.qml")));
|
||||
setVisible(true);
|
||||
initSlideWindow();
|
||||
resizeWindow();
|
||||
onVisibilityChanged();
|
||||
|
||||
connect(qApp->primaryScreen(), &QScreen::virtualGeometryChanged, this, &MainWindow::resizeWindow);
|
||||
connect(qApp->primaryScreen(), &QScreen::geometryChanged, this, &MainWindow::resizeWindow);
|
||||
|
||||
connect(m_settings, &DockSettings::directionChanged, this, &MainWindow::onPositionChanged);
|
||||
connect(m_settings, &DockSettings::iconSizeChanged, this, &MainWindow::onIconSizeChanged);
|
||||
connect(m_settings, &DockSettings::visibilityChanged, this, &MainWindow::onVisibilityChanged);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
QRect MainWindow::windowRect() const
|
||||
{
|
||||
const QRect screenGeometry = qApp->primaryScreen()->geometry();
|
||||
|
||||
QSize newSize(0, 0);
|
||||
QPoint position(0, 0);
|
||||
|
||||
switch (m_settings->direction()) {
|
||||
case DockSettings::Left:
|
||||
newSize = QSize(m_settings->iconSize(), screenGeometry.height() - m_settings->edgeMargins());
|
||||
position = { screenGeometry.x() + DockSettings::self()->edgeMargins() / 2,
|
||||
(screenGeometry.height() - newSize.height()) / 2
|
||||
};
|
||||
break;
|
||||
case DockSettings::Bottom:
|
||||
newSize = QSize(screenGeometry.width() - DockSettings::self()->edgeMargins(), m_settings->iconSize());
|
||||
position = { (screenGeometry.width() - newSize.width()) / 2,
|
||||
screenGeometry.y() + screenGeometry.height() - newSize.height()
|
||||
- DockSettings::self()->edgeMargins() / 2
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QRect(position, newSize);
|
||||
}
|
||||
|
||||
void MainWindow::resizeWindow()
|
||||
{
|
||||
setGeometry(windowRect());
|
||||
updateViewStruts();
|
||||
|
||||
emit resizingFished();
|
||||
}
|
||||
|
||||
void MainWindow::initSlideWindow()
|
||||
{
|
||||
KWindowEffects::SlideFromLocation location = KWindowEffects::NoEdge;
|
||||
|
||||
if (m_settings->direction() == DockSettings::Left)
|
||||
location = KWindowEffects::LeftEdge;
|
||||
else if (m_settings->direction() == DockSettings::Bottom)
|
||||
location = KWindowEffects::BottomEdge;
|
||||
|
||||
KWindowEffects::slideWindow(winId(), location);
|
||||
}
|
||||
|
||||
void MainWindow::updateViewStruts()
|
||||
{
|
||||
XWindowInterface::instance()->setViewStruts(this, m_settings->direction(), geometry());
|
||||
}
|
||||
|
||||
void MainWindow::createFakeWindow()
|
||||
{
|
||||
if (!m_fakeWindow) {
|
||||
m_fakeWindow = new FakeWindow;
|
||||
|
||||
connect(m_fakeWindow, &FakeWindow::containsMouseChanged, this, [=](bool contains) {
|
||||
|
||||
});
|
||||
|
||||
connect(m_fakeWindow, &FakeWindow::dragEntered, this, [&] {});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::deleteFakeWindow()
|
||||
{
|
||||
if (m_fakeWindow) {
|
||||
m_fakeWindow->deleteLater();
|
||||
m_fakeWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onPositionChanged()
|
||||
{
|
||||
setVisible(false);
|
||||
initSlideWindow();
|
||||
setVisible(true);
|
||||
|
||||
setGeometry(windowRect());
|
||||
updateViewStruts();
|
||||
|
||||
emit positionChanged();
|
||||
}
|
||||
|
||||
void MainWindow::onIconSizeChanged()
|
||||
{
|
||||
setGeometry(windowRect());
|
||||
updateViewStruts();
|
||||
|
||||
emit iconSizeChanged();
|
||||
}
|
||||
|
||||
void MainWindow::onVisibilityChanged()
|
||||
{
|
||||
if (m_settings->visibility() == DockSettings::AlwaysVisible)
|
||||
return;
|
||||
|
||||
createFakeWindow();
|
||||
}
|
66
src/mainwindow.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QTimer>
|
||||
|
||||
#include "docksettings.h"
|
||||
#include "applicationmodel.h"
|
||||
#include "fakewindow.h"
|
||||
|
||||
class MainWindow : public QQuickView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QQuickView *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
signals:
|
||||
void resizingFished();
|
||||
void iconSizeChanged();
|
||||
void positionChanged();
|
||||
|
||||
protected:
|
||||
void event(QEvent *e, QObject *obj);
|
||||
|
||||
private:
|
||||
QRect windowRect() const;
|
||||
void resizeWindow();
|
||||
void initSlideWindow();
|
||||
void updateViewStruts();
|
||||
|
||||
void createFakeWindow();
|
||||
void deleteFakeWindow();
|
||||
|
||||
private slots:
|
||||
void onPositionChanged();
|
||||
void onIconSizeChanged();
|
||||
void onVisibilityChanged();
|
||||
|
||||
private:
|
||||
DockSettings *m_settings;
|
||||
ApplicationModel *m_appModel;
|
||||
FakeWindow *m_fakeWindow;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
16
src/processprovider.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "processprovider.h"
|
||||
#include <QProcess>
|
||||
|
||||
ProcessProvider::ProcessProvider(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ProcessProvider::startDetached(const QString &exec, QStringList args)
|
||||
{
|
||||
QProcess process;
|
||||
process.setProgram(exec);
|
||||
process.setArguments(args);
|
||||
return process.startDetached();
|
||||
}
|
16
src/processprovider.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef PROCESSPROVIDER_H
|
||||
#define PROCESSPROVIDER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class ProcessProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProcessProvider(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE bool startDetached(const QString &exec, QStringList args = QStringList());
|
||||
};
|
||||
|
||||
#endif // PROCESSPROVIDER_H
|
47
src/statusnotifier/dbustypes.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "dbustypes.h"
|
||||
|
||||
// Marshall the IconPixmap data into a D-Bus argument
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << icon.width;
|
||||
argument << icon.height;
|
||||
argument << icon.bytes;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Retrieve the ImageStruct data from the D-Bus argument
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> icon.width;
|
||||
argument >> icon.height;
|
||||
argument >> icon.bytes;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Marshall the ToolTip data into a D-Bus argument
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << toolTip.iconName;
|
||||
argument << toolTip.iconPixmap;
|
||||
argument << toolTip.title;
|
||||
argument << toolTip.description;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Retrieve the ToolTip data from the D-Bus argument
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> toolTip.iconName;
|
||||
argument >> toolTip.iconPixmap;
|
||||
argument >> toolTip.title;
|
||||
argument >> toolTip.description;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
30
src/statusnotifier/dbustypes.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include <QDBusArgument>
|
||||
|
||||
#ifndef DBUSTYPES_H
|
||||
#define DBUSTYPES_H
|
||||
|
||||
struct IconPixmap {
|
||||
int width;
|
||||
int height;
|
||||
QByteArray bytes;
|
||||
};
|
||||
|
||||
typedef QList<IconPixmap> IconPixmapList;
|
||||
|
||||
struct ToolTip {
|
||||
QString iconName;
|
||||
QList<IconPixmap> iconPixmap;
|
||||
QString title;
|
||||
QString description;
|
||||
};
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const IconPixmap &icon);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, IconPixmap &icon);
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const ToolTip &toolTip);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, ToolTip &toolTip);
|
||||
|
||||
Q_DECLARE_METATYPE(IconPixmap)
|
||||
Q_DECLARE_METATYPE(ToolTip)
|
||||
|
||||
#endif // DBUSTYPES_H
|
21
src/statusnotifier/sniasync.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "sniasync.h"
|
||||
|
||||
SniAsync::SniAsync(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent/* = 0*/)
|
||||
: QObject(parent)
|
||||
, m_sni{service, path, connection}
|
||||
{
|
||||
//forward StatusNotifierItem signals
|
||||
connect(&m_sni, &org::kde::StatusNotifierItem::NewAttentionIcon, this, &SniAsync::NewAttentionIcon);
|
||||
connect(&m_sni, &org::kde::StatusNotifierItem::NewIcon, this, &SniAsync::NewIcon);
|
||||
connect(&m_sni, &org::kde::StatusNotifierItem::NewOverlayIcon, this, &SniAsync::NewOverlayIcon);
|
||||
connect(&m_sni, &org::kde::StatusNotifierItem::NewStatus, this, &SniAsync::NewStatus);
|
||||
connect(&m_sni, &org::kde::StatusNotifierItem::NewTitle, this, &SniAsync::NewTitle);
|
||||
connect(&m_sni, &org::kde::StatusNotifierItem::NewToolTip, this, &SniAsync::NewToolTip);
|
||||
}
|
||||
|
||||
QDBusPendingReply<QDBusVariant> SniAsync::asyncPropGet(QString const & property)
|
||||
{
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(m_sni.service(), m_sni.path(), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
|
||||
msg << m_sni.interface() << property;
|
||||
return m_sni.connection().asyncCall(msg);
|
||||
}
|
89
src/statusnotifier/sniasync.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
#if !defined(SNIASYNC_H)
|
||||
#define SNIASYNC_H
|
||||
|
||||
#include <functional>
|
||||
#include "statusnotifieriteminterface.h"
|
||||
|
||||
template<typename>
|
||||
struct remove_class_type { using type = void; }; // bluff
|
||||
template<typename C, typename R, typename... ArgTypes>
|
||||
struct remove_class_type<R (C::*)(ArgTypes...)> { using type = R(ArgTypes...); };
|
||||
template<typename C, typename R, typename... ArgTypes>
|
||||
struct remove_class_type<R (C::*)(ArgTypes...) const> { using type = R(ArgTypes...); };
|
||||
|
||||
template <typename L>
|
||||
class call_sig_helper
|
||||
{
|
||||
template <typename L1>
|
||||
static decltype(&L1::operator()) test(int);
|
||||
template <typename L1>
|
||||
static void test(...); //bluff
|
||||
public:
|
||||
using type = decltype(test<L>(0));
|
||||
};
|
||||
template <typename L>
|
||||
struct call_signature : public remove_class_type<typename call_sig_helper<L>::type> {};
|
||||
template <typename R, typename... ArgTypes>
|
||||
struct call_signature<R (ArgTypes...)> { using type = R (ArgTypes...); };
|
||||
template <typename R, typename... ArgTypes>
|
||||
struct call_signature<R (*)(ArgTypes...)> { using type = R (ArgTypes...); };
|
||||
template <typename C, typename R, typename... ArgTypes>
|
||||
struct call_signature<R (C::*)(ArgTypes...)> { using type = R (ArgTypes...); };
|
||||
template<typename C, typename R, typename... ArgTypes>
|
||||
struct call_signature<R (C::*)(ArgTypes...) const> { using type = R(ArgTypes...); };
|
||||
|
||||
template <typename> struct is_valid_signature : public std::false_type {};
|
||||
template <typename Arg>
|
||||
struct is_valid_signature<void (Arg)> : public std::true_type {};
|
||||
|
||||
class SniAsync : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SniAsync(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
|
||||
|
||||
template <typename F>
|
||||
inline void propertyGetAsync(QString const &name, F finished)
|
||||
{
|
||||
static_assert(is_valid_signature<typename call_signature<F>::type>::value, "need callable (lambda, *function, callable obj) (Arg) -> void");
|
||||
connect(new QDBusPendingCallWatcher{asyncPropGet(name), this},
|
||||
&QDBusPendingCallWatcher::finished,
|
||||
[this, finished, name] (QDBusPendingCallWatcher * call)
|
||||
{
|
||||
QDBusPendingReply<QVariant> reply = *call;
|
||||
if (reply.isError())
|
||||
qDebug().noquote().nospace() << "Error on DBus request(" << m_sni.service() << ',' << m_sni.path() << "): " << reply.error();
|
||||
finished(qdbus_cast<typename std::function<typename call_signature<F>::type>::argument_type>(reply.value()));
|
||||
call->deleteLater();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//exposed methods from org::kde::StatusNotifierItem
|
||||
inline QString service() const { return m_sni.service(); }
|
||||
|
||||
public slots:
|
||||
//Forwarded slots from org::kde::StatusNotifierItem
|
||||
inline QDBusPendingReply<> Activate(int x, int y) { return m_sni.Activate(x, y); }
|
||||
inline QDBusPendingReply<> ContextMenu(int x, int y) { return m_sni.ContextMenu(x, y); }
|
||||
inline QDBusPendingReply<> Scroll(int delta, const QString &orientation) { return m_sni.Scroll(delta, orientation); }
|
||||
inline QDBusPendingReply<> SecondaryActivate(int x, int y) { return m_sni.SecondaryActivate(x, y); }
|
||||
|
||||
signals:
|
||||
//Forwarded signals from org::kde::StatusNotifierItem
|
||||
void NewAttentionIcon();
|
||||
void NewIcon();
|
||||
void NewOverlayIcon();
|
||||
void NewStatus(const QString &status);
|
||||
void NewTitle();
|
||||
void NewToolTip();
|
||||
|
||||
private:
|
||||
QDBusPendingReply<QDBusVariant> asyncPropGet(QString const & property);
|
||||
|
||||
private:
|
||||
org::kde::StatusNotifierItem m_sni;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
14
src/statusnotifier/statusnotifieriteminterface.cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "statusnotifieriteminterface.h"
|
||||
|
||||
/*
|
||||
* Implementation of interface class StatusNotifierItemInterface
|
||||
*/
|
||||
|
||||
StatusNotifierItemInterface::StatusNotifierItemInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
|
||||
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
|
||||
{
|
||||
}
|
||||
|
||||
StatusNotifierItemInterface::~StatusNotifierItemInterface()
|
||||
{
|
||||
}
|
136
src/statusnotifier/statusnotifieriteminterface.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
#ifndef STATUSNOTIFIERITEMINTERFACE_H
|
||||
#define STATUSNOTIFIERITEMINTERFACE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QtDBus>
|
||||
#include "dbustypes.h"
|
||||
|
||||
/*
|
||||
* Proxy class for interface org.kde.StatusNotifierItem
|
||||
*/
|
||||
class StatusNotifierItemInterface: public QDBusAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static inline const char *staticInterfaceName()
|
||||
{ return "org.kde.StatusNotifierItem"; }
|
||||
|
||||
public:
|
||||
StatusNotifierItemInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
|
||||
|
||||
~StatusNotifierItemInterface();
|
||||
|
||||
Q_PROPERTY(QString AttentionIconName READ attentionIconName)
|
||||
inline QString attentionIconName() const
|
||||
{ return qvariant_cast< QString >(property("AttentionIconName")); }
|
||||
|
||||
Q_PROPERTY(IconPixmapList AttentionIconPixmap READ attentionIconPixmap)
|
||||
inline IconPixmapList attentionIconPixmap() const
|
||||
{ return qvariant_cast< IconPixmapList >(property("AttentionIconPixmap")); }
|
||||
|
||||
Q_PROPERTY(QString AttentionMovieName READ attentionMovieName)
|
||||
inline QString attentionMovieName() const
|
||||
{ return qvariant_cast< QString >(property("AttentionMovieName")); }
|
||||
|
||||
Q_PROPERTY(QString Category READ category)
|
||||
inline QString category() const
|
||||
{ return qvariant_cast< QString >(property("Category")); }
|
||||
|
||||
Q_PROPERTY(QString IconName READ iconName)
|
||||
inline QString iconName() const
|
||||
{ return qvariant_cast< QString >(property("IconName")); }
|
||||
|
||||
Q_PROPERTY(IconPixmapList IconPixmap READ iconPixmap)
|
||||
inline IconPixmapList iconPixmap() const
|
||||
{ return qvariant_cast< IconPixmapList >(property("IconPixmap")); }
|
||||
|
||||
Q_PROPERTY(QString IconThemePath READ iconThemePath)
|
||||
inline QString iconThemePath() const
|
||||
{ return qvariant_cast< QString >(property("IconThemePath")); }
|
||||
|
||||
Q_PROPERTY(QString Id READ id)
|
||||
inline QString id() const
|
||||
{ return qvariant_cast< QString >(property("Id")); }
|
||||
|
||||
Q_PROPERTY(bool ItemIsMenu READ itemIsMenu)
|
||||
inline bool itemIsMenu() const
|
||||
{ return qvariant_cast< bool >(property("ItemIsMenu")); }
|
||||
|
||||
Q_PROPERTY(QDBusObjectPath Menu READ menu)
|
||||
inline QDBusObjectPath menu() const
|
||||
{ return qvariant_cast< QDBusObjectPath >(property("Menu")); }
|
||||
|
||||
Q_PROPERTY(QString OverlayIconName READ overlayIconName)
|
||||
inline QString overlayIconName() const
|
||||
{ return qvariant_cast< QString >(property("OverlayIconName")); }
|
||||
|
||||
Q_PROPERTY(IconPixmapList OverlayIconPixmap READ overlayIconPixmap)
|
||||
inline IconPixmapList overlayIconPixmap() const
|
||||
{ return qvariant_cast< IconPixmapList >(property("OverlayIconPixmap")); }
|
||||
|
||||
Q_PROPERTY(QString Status READ status)
|
||||
inline QString status() const
|
||||
{ return qvariant_cast< QString >(property("Status")); }
|
||||
|
||||
Q_PROPERTY(QString Title READ title)
|
||||
inline QString title() const
|
||||
{ return qvariant_cast< QString >(property("Title")); }
|
||||
|
||||
Q_PROPERTY(ToolTip ToolTip READ toolTip)
|
||||
inline ToolTip toolTip() const
|
||||
{ return qvariant_cast< ToolTip >(property("ToolTip")); }
|
||||
|
||||
Q_PROPERTY(int WindowId READ windowId)
|
||||
inline int windowId() const
|
||||
{ return qvariant_cast< int >(property("WindowId")); }
|
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
inline QDBusPendingReply<> Activate(int x, int y)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y);
|
||||
return asyncCallWithArgumentList(QLatin1String("Activate"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> ContextMenu(int x, int y)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y);
|
||||
return asyncCallWithArgumentList(QLatin1String("ContextMenu"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Scroll(int delta, const QString &orientation)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(delta) << QVariant::fromValue(orientation);
|
||||
return asyncCallWithArgumentList(QLatin1String("Scroll"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> SecondaryActivate(int x, int y)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y);
|
||||
return asyncCallWithArgumentList(QLatin1String("SecondaryActivate"), argumentList);
|
||||
}
|
||||
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void NewAttentionIcon();
|
||||
void NewIcon();
|
||||
void NewOverlayIcon();
|
||||
void NewStatus(const QString &status);
|
||||
void NewTitle();
|
||||
void NewToolTip();
|
||||
};
|
||||
|
||||
namespace org {
|
||||
namespace kde {
|
||||
typedef ::StatusNotifierItemInterface StatusNotifierItem;
|
||||
}
|
||||
}
|
||||
#endif
|
211
src/statusnotifier/statusnotifieritemsource.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
#include "statusnotifieritemsource.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QIcon>
|
||||
#include <QDebug>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QVariantMap>
|
||||
#include <QImage>
|
||||
#include <QMenu>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <dbusmenu-qt5/dbusmenuimporter.h>
|
||||
|
||||
class MenuImporter : public DBusMenuImporter
|
||||
{
|
||||
public:
|
||||
using DBusMenuImporter::DBusMenuImporter;
|
||||
|
||||
protected:
|
||||
virtual QIcon iconForName(const QString & name) override {
|
||||
return QIcon::fromTheme(name);
|
||||
}
|
||||
};
|
||||
|
||||
StatusNotifierItemSource::StatusNotifierItemSource(const QString &id, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_id(id)
|
||||
, m_refreshing(false)
|
||||
, m_needsReRefreshing(false)
|
||||
, m_menuImporter(nullptr)
|
||||
{
|
||||
int slash = id.indexOf('/');
|
||||
if (slash == -1) {
|
||||
qWarning() << "Invalid notifierItemId:" << id;
|
||||
m_valid = false;
|
||||
m_statusNotifierItemInterface = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
QString service = id.left(slash);
|
||||
QString path = id.mid(slash);
|
||||
|
||||
m_statusNotifierItemInterface = new org::kde::StatusNotifierItem(service, path,
|
||||
QDBusConnection::sessionBus(), this);
|
||||
m_refreshTimer.setSingleShot(true);
|
||||
m_refreshTimer.setInterval(10);
|
||||
connect(&m_refreshTimer, &QTimer::timeout, this, &StatusNotifierItemSource::performRefresh);
|
||||
|
||||
m_valid = !service.isEmpty() && m_statusNotifierItemInterface->isValid();
|
||||
if (m_valid) {
|
||||
connect(m_statusNotifierItemInterface, &StatusNotifierItemInterface::NewTitle, this, &StatusNotifierItemSource::refreshTitle);
|
||||
connect(m_statusNotifierItemInterface, &StatusNotifierItemInterface::NewIcon, this, &StatusNotifierItemSource::refreshIcons);
|
||||
connect(m_statusNotifierItemInterface, &StatusNotifierItemInterface::NewAttentionIcon, this, &StatusNotifierItemSource::refreshIcons);
|
||||
connect(m_statusNotifierItemInterface, &StatusNotifierItemInterface::NewOverlayIcon, this, &StatusNotifierItemSource::refreshIcons);
|
||||
connect(m_statusNotifierItemInterface, &StatusNotifierItemInterface::NewToolTip, this, &StatusNotifierItemSource::refreshToolTip);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
StatusNotifierItemSource::~StatusNotifierItemSource()
|
||||
{
|
||||
delete m_statusNotifierItemInterface;
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::activate(int x, int y)
|
||||
{
|
||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
||||
m_statusNotifierItemInterface->Activate(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::secondaryActivate(int x, int y)
|
||||
{
|
||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
||||
m_statusNotifierItemInterface->call(QDBus::NoBlock, QStringLiteral("SecondaryActivate"), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::contextMenu(int x, int y)
|
||||
{
|
||||
if (m_menuImporter) {
|
||||
m_menuImporter->updateMenu();
|
||||
|
||||
// Popup menu
|
||||
if (m_menuImporter->menu()) {
|
||||
m_menuImporter->menu()->popup(QPoint(x, y));
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Could not find DBusMenu interface, falling back to calling ContextMenu()";
|
||||
if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) {
|
||||
m_statusNotifierItemInterface->call(QDBus::NoBlock, QStringLiteral("ContextMenu"), x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::refresh()
|
||||
{
|
||||
if (!m_refreshTimer.isActive()) {
|
||||
m_refreshTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::refreshTitle()
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::refreshToolTip()
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::refreshIcons()
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::performRefresh()
|
||||
{
|
||||
if (m_refreshing) {
|
||||
m_needsReRefreshing = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_refreshing = true;
|
||||
QDBusMessage message = QDBusMessage::createMethodCall(m_statusNotifierItemInterface->service(),
|
||||
m_statusNotifierItemInterface->path(),
|
||||
QStringLiteral("org.freedesktop.DBus.Properties"),
|
||||
QStringLiteral("GetAll"));
|
||||
|
||||
message << m_statusNotifierItemInterface->interface();
|
||||
QDBusPendingCall call = m_statusNotifierItemInterface->connection().asyncCall(message);
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, &StatusNotifierItemSource::refreshCallback);
|
||||
}
|
||||
|
||||
void StatusNotifierItemSource::refreshCallback(QDBusPendingCallWatcher *call)
|
||||
{
|
||||
m_refreshing = false;
|
||||
if (m_needsReRefreshing) {
|
||||
m_needsReRefreshing = false;
|
||||
performRefresh();
|
||||
call->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusPendingReply<QVariantMap> reply = *call;
|
||||
if (reply.isError()) {
|
||||
m_valid = false;
|
||||
} else {
|
||||
QVariantMap properties = reply.argumentAt<0>();
|
||||
QString path = properties[QStringLiteral("IconThemePath")].toString();
|
||||
|
||||
m_title = properties[QStringLiteral("Title")].toString();
|
||||
m_iconName = properties[QStringLiteral("IconName")].toString();
|
||||
|
||||
// ToolTip
|
||||
ToolTip toolTip;
|
||||
properties[QStringLiteral("ToolTip")].value<QDBusArgument>() >> toolTip;
|
||||
m_tooltip = toolTip.title;
|
||||
|
||||
// Menu
|
||||
QString menuObjectPath = properties[QStringLiteral("Menu")].value<QDBusObjectPath>().path();
|
||||
if (!menuObjectPath.isEmpty()) {
|
||||
if (menuObjectPath.startsWith(QLatin1String("/NO_DBUSMENU"))) {
|
||||
qWarning() << "DBusMenu disabled for this application";
|
||||
} else {
|
||||
m_menuImporter = new MenuImporter(m_statusNotifierItemInterface->service(), menuObjectPath, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Icon
|
||||
IconPixmapList iconPixmaps;
|
||||
properties[QStringLiteral("IconPixmap")].value<QDBusArgument>() >> iconPixmaps;
|
||||
|
||||
QImage image = IconPixmapListToImage(iconPixmaps);
|
||||
if (!image.isNull()) {
|
||||
QByteArray byteArray;
|
||||
QBuffer buffer(&byteArray);
|
||||
image.save(&buffer, "PNG");
|
||||
m_iconBytes = byteArray.toBase64();
|
||||
}
|
||||
|
||||
emit updated(this);
|
||||
}
|
||||
|
||||
call->deleteLater();
|
||||
}
|
||||
|
||||
QImage StatusNotifierItemSource::IconPixmapListToImage(const IconPixmapList &list) const
|
||||
{
|
||||
QIcon icon;
|
||||
|
||||
for (IconPixmap iconPixmap: list) {
|
||||
if (!iconPixmap.bytes.isNull()) {
|
||||
QImage image((uchar*) iconPixmap.bytes.data(), iconPixmap.width,
|
||||
iconPixmap.height, QImage::Format_ARGB32);
|
||||
|
||||
const uchar *end = image.constBits() + image.sizeInBytes();
|
||||
uchar *dest = reinterpret_cast<uchar*>(iconPixmap.bytes.data());
|
||||
for (const uchar *src = image.constBits(); src < end; src += 4, dest += 4)
|
||||
qToUnaligned(qToBigEndian<quint32>(qFromUnaligned<quint32>(src)), dest);
|
||||
|
||||
icon.addPixmap(QPixmap::fromImage(image));
|
||||
}
|
||||
}
|
||||
|
||||
return icon.pixmap(QSize(24, 24)).toImage();
|
||||
}
|
57
src/statusnotifier/statusnotifieritemsource.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef STATUSNOTIFIERITEMSOURCE_H
|
||||
#define STATUSNOTIFIERITEMSOURCE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
|
||||
#include "statusnotifieriteminterface.h"
|
||||
|
||||
class MenuImporter;
|
||||
class StatusNotifierItemSource : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit StatusNotifierItemSource(const QString &id, QObject *parent = nullptr);
|
||||
~StatusNotifierItemSource();
|
||||
|
||||
QString id() const { return m_id; }
|
||||
QString title() const { return m_title; }
|
||||
QString tooltip() const { return m_tooltip; }
|
||||
QString iconName() const { return m_iconName; }
|
||||
QString iconBytes() const { return m_iconBytes; }
|
||||
|
||||
void activate(int x, int y);
|
||||
void secondaryActivate(int x, int y);
|
||||
void contextMenu(int x, int y);
|
||||
|
||||
MenuImporter *menuImporter() { return m_menuImporter; }
|
||||
|
||||
signals:
|
||||
void updated(StatusNotifierItemSource *);
|
||||
|
||||
private slots:
|
||||
void refresh();
|
||||
void refreshTitle();
|
||||
void refreshToolTip();
|
||||
void refreshIcons();
|
||||
void performRefresh();
|
||||
void refreshCallback(QDBusPendingCallWatcher *);
|
||||
QImage IconPixmapListToImage(const IconPixmapList &list) const;
|
||||
|
||||
private:
|
||||
QString m_id;
|
||||
QString m_title;
|
||||
QString m_tooltip;
|
||||
QString m_iconName;
|
||||
QString m_iconBytes;
|
||||
|
||||
bool m_valid;
|
||||
bool m_refreshing;
|
||||
bool m_needsReRefreshing;
|
||||
StatusNotifierItemInterface *m_statusNotifierItemInterface;
|
||||
MenuImporter *m_menuImporter;
|
||||
QTimer m_refreshTimer;
|
||||
};
|
||||
|
||||
#endif // STATUSNOTIFIERITEMSOURCE_H
|
162
src/statusnotifier/statusnotifiermodel.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
#include "statusnotifiermodel.h"
|
||||
#include <QFutureWatcher>
|
||||
#include <QtConcurrent>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QApplication>
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
#include <QCursor>
|
||||
|
||||
StatusNotifierModel::StatusNotifierModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_watcher(nullptr)
|
||||
{
|
||||
QFutureWatcher<StatusNotifierWatcher *> * futureWatcher = new QFutureWatcher<StatusNotifierWatcher *>;
|
||||
connect(futureWatcher, &QFutureWatcher<StatusNotifierWatcher *>::finished, this, [this, futureWatcher] {
|
||||
m_watcher = futureWatcher->future().result();
|
||||
|
||||
connect(m_watcher, &StatusNotifierWatcher::StatusNotifierItemRegistered,
|
||||
this, &StatusNotifierModel::itemAdded);
|
||||
connect(m_watcher, &StatusNotifierWatcher::StatusNotifierItemUnregistered,
|
||||
this, &StatusNotifierModel::itemRemoved);
|
||||
|
||||
qDebug() << m_watcher->RegisteredStatusNotifierItems();
|
||||
|
||||
futureWatcher->deleteLater();
|
||||
});
|
||||
|
||||
QFuture<StatusNotifierWatcher *> future = QtConcurrent::run([=] {
|
||||
QString dbusName = QStringLiteral("org.kde.StatusNotifierHost-%1-%2").arg(QApplication::applicationPid()).arg(1);
|
||||
if (QDBusConnectionInterface::ServiceNotRegistered == QDBusConnection::sessionBus().interface()->registerService(dbusName, QDBusConnectionInterface::DontQueueService))
|
||||
qDebug() << "unable to register service for " << dbusName;
|
||||
|
||||
StatusNotifierWatcher * watcher = new StatusNotifierWatcher;
|
||||
watcher->RegisterStatusNotifierHost(dbusName);
|
||||
watcher->moveToThread(QApplication::instance()->thread());
|
||||
return watcher;
|
||||
});
|
||||
|
||||
futureWatcher->setFuture(future);
|
||||
}
|
||||
|
||||
StatusNotifierModel::~StatusNotifierModel()
|
||||
{
|
||||
delete m_watcher;
|
||||
}
|
||||
|
||||
int StatusNotifierModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> StatusNotifierModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[IdRole] = "id";
|
||||
roles[IconNameRole] = "iconName";
|
||||
roles[IconBytesRole] = "iconBytes";
|
||||
roles[TitleRole] = "title";
|
||||
roles[ToolTipRole] = "toolTip";
|
||||
return roles;
|
||||
}
|
||||
|
||||
QVariant StatusNotifierModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
StatusNotifierItemSource *item = m_items.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case IdRole:
|
||||
return item->id();
|
||||
case IconNameRole:
|
||||
return item->iconName();
|
||||
case IconBytesRole:
|
||||
return item->iconBytes();
|
||||
case TitleRole:
|
||||
return item->title();
|
||||
case ToolTipRole:
|
||||
return item->tooltip();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int StatusNotifierModel::indexOf(const QString &id)
|
||||
{
|
||||
for (StatusNotifierItemSource *item : m_items) {
|
||||
if (item->id() == id)
|
||||
return m_items.indexOf(item);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
StatusNotifierItemSource *StatusNotifierModel::findItemById(const QString &id)
|
||||
{
|
||||
int index = indexOf(id);
|
||||
|
||||
if (index == -1)
|
||||
return nullptr;
|
||||
|
||||
return m_items.at(index);
|
||||
}
|
||||
|
||||
void StatusNotifierModel::leftButtonClick(const QString &id)
|
||||
{
|
||||
StatusNotifierItemSource *item = findItemById(id);
|
||||
if (item) {
|
||||
QPoint p(QCursor::pos());
|
||||
item->activate(p.x(), p.y());
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierModel::rightButtonClick(const QString &id)
|
||||
{
|
||||
StatusNotifierItemSource *item = findItemById(id);
|
||||
if (item) {
|
||||
QPoint p(QCursor::pos());
|
||||
item->contextMenu(p.x(), p.y());
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierModel::itemAdded(QString serviceAndPath)
|
||||
{
|
||||
StatusNotifierItemSource *source = new StatusNotifierItemSource(serviceAndPath, this);
|
||||
|
||||
connect(source, &StatusNotifierItemSource::updated, this, &StatusNotifierModel::updated);
|
||||
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
m_items.append(source);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void StatusNotifierModel::itemRemoved(const QString &serviceAndPath)
|
||||
{
|
||||
int index = indexOf(serviceAndPath);
|
||||
|
||||
if (index != -1) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
StatusNotifierItemSource *item = m_items.at(index);
|
||||
m_items.removeAll(item);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierModel::updated(StatusNotifierItemSource *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
int idx = indexOf(item->id());
|
||||
|
||||
// update
|
||||
if (idx != -1) {
|
||||
dataChanged(index(idx, 0), index(idx, 0));
|
||||
}
|
||||
}
|
53
src/statusnotifier/statusnotifiermodel.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef STATUSNOTIFIERMODEL_H
|
||||
#define STATUSNOTIFIERMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QIcon>
|
||||
#include <QMenu>
|
||||
|
||||
#include <dbusmenu-qt5/dbusmenuimporter.h>
|
||||
|
||||
#include "statusnotifieritemsource.h"
|
||||
#include "statusnotifierwatcher.h"
|
||||
#include "sniasync.h"
|
||||
|
||||
class StatusNotifierModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
IdRole = Qt::UserRole + 1,
|
||||
IconNameRole,
|
||||
IconBytesRole,
|
||||
IconRole,
|
||||
TitleRole,
|
||||
ToolTipRole
|
||||
};
|
||||
|
||||
explicit StatusNotifierModel(QObject *parent = nullptr);
|
||||
~StatusNotifierModel();
|
||||
|
||||
// Basic functionality:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
int indexOf(const QString &id);
|
||||
StatusNotifierItemSource *findItemById(const QString &id);
|
||||
|
||||
Q_INVOKABLE void leftButtonClick(const QString &id);
|
||||
Q_INVOKABLE void rightButtonClick(const QString &id);
|
||||
|
||||
public slots:
|
||||
void itemAdded(QString serviceAndPath);
|
||||
void itemRemoved(const QString &serviceAndPath);
|
||||
void updated(StatusNotifierItemSource *item);
|
||||
|
||||
private:
|
||||
StatusNotifierWatcher *m_watcher;
|
||||
QList<StatusNotifierItemSource *> m_items;
|
||||
};
|
||||
|
||||
#endif // STATUSNOTIFIERMODEL_H
|
99
src/statusnotifier/statusnotifierwatcher.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "statusnotifierwatcher.h"
|
||||
#include <QDebug>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
StatusNotifierWatcher::StatusNotifierWatcher(QObject *parent) : QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<IconPixmap>("IconPixmap");
|
||||
qDBusRegisterMetaType<IconPixmap>();
|
||||
qRegisterMetaType<IconPixmapList>("IconPixmapList");
|
||||
qDBusRegisterMetaType<IconPixmapList>();
|
||||
qRegisterMetaType<ToolTip>("ToolTip");
|
||||
qDBusRegisterMetaType<ToolTip>();
|
||||
|
||||
QDBusConnection dbus = QDBusConnection::sessionBus();
|
||||
switch (dbus.interface()->registerService(QStringLiteral("org.kde.StatusNotifierWatcher"), QDBusConnectionInterface::QueueService).value())
|
||||
{
|
||||
case QDBusConnectionInterface::ServiceNotRegistered:
|
||||
qWarning() << "StatusNotifier: unable to register service for org.kde.StatusNotifierWatcher";
|
||||
break;
|
||||
case QDBusConnectionInterface::ServiceQueued:
|
||||
qWarning() << "StatusNotifier: registration of service org.kde.StatusNotifierWatcher queued, we can become primary after existing one deregisters";
|
||||
break;
|
||||
case QDBusConnectionInterface::ServiceRegistered:
|
||||
break;
|
||||
}
|
||||
|
||||
dbus.registerObject(QStringLiteral("/StatusNotifierWatcher"), this, QDBusConnection::ExportScriptableContents);
|
||||
|
||||
// if (!dbus.registerObject(QStringLiteral("/StatusNotifierWatcher"), this, QDBusConnection::ExportScriptableContents))
|
||||
// qDebug() << QDBusConnection::sessionBus().lastError().message();
|
||||
|
||||
mWatcher = new QDBusServiceWatcher(this);
|
||||
mWatcher->setConnection(dbus);
|
||||
mWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
|
||||
|
||||
connect(mWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &StatusNotifierWatcher::serviceUnregistered);
|
||||
}
|
||||
|
||||
StatusNotifierWatcher::~StatusNotifierWatcher()
|
||||
{
|
||||
QDBusConnection::sessionBus().unregisterService(QStringLiteral("org.kde.StatusNotifierWatcher"));
|
||||
}
|
||||
|
||||
void StatusNotifierWatcher::RegisterStatusNotifierItem(const QString &serviceOrPath)
|
||||
{
|
||||
QString service = serviceOrPath;
|
||||
QString path = QStringLiteral("/StatusNotifierItem");
|
||||
|
||||
// workaround for sni-qt
|
||||
if (service.startsWith(QLatin1Char('/'))) {
|
||||
path = service;
|
||||
service = message().service();
|
||||
}
|
||||
|
||||
QString notifierItemId = service + path;
|
||||
|
||||
if (QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value()
|
||||
&& !mServices.contains(notifierItemId)) {
|
||||
mServices << notifierItemId;
|
||||
mWatcher->addWatchedService(service);
|
||||
emit StatusNotifierItemRegistered(notifierItemId);
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierWatcher::RegisterStatusNotifierHost(const QString &service)
|
||||
{
|
||||
if (!mHosts.contains(service))
|
||||
{
|
||||
mHosts.append(service);
|
||||
mWatcher->addWatchedService(service);
|
||||
}
|
||||
}
|
||||
|
||||
void StatusNotifierWatcher::serviceUnregistered(const QString &service)
|
||||
{
|
||||
// qDebug() << "Service" << service << "unregistered";
|
||||
|
||||
mWatcher->removeWatchedService(service);
|
||||
|
||||
if (mHosts.contains(service))
|
||||
{
|
||||
mHosts.removeAll(service);
|
||||
return;
|
||||
}
|
||||
|
||||
QString match = service + QLatin1Char('/');
|
||||
QStringList::Iterator it = mServices.begin();
|
||||
while (it != mServices.end())
|
||||
{
|
||||
if (it->startsWith(match))
|
||||
{
|
||||
QString name = *it;
|
||||
it = mServices.erase(it);
|
||||
emit StatusNotifierItemUnregistered(name);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
45
src/statusnotifier/statusnotifierwatcher.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef STATUSNOTIFIERWATCHER_H
|
||||
#define STATUSNOTIFIERWATCHER_H
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusContext>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusMetaType>
|
||||
#include <QDBusServiceWatcher>
|
||||
|
||||
#include "dbustypes.h"
|
||||
|
||||
class StatusNotifierWatcher : public QObject, protected QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.StatusNotifierWatcher")
|
||||
Q_SCRIPTABLE Q_PROPERTY(bool IsStatusNotifierHostRegistered READ isStatusNotifierHostRegistered)
|
||||
Q_SCRIPTABLE Q_PROPERTY(int ProtocolVersion READ protocolVersion)
|
||||
Q_SCRIPTABLE Q_PROPERTY(QStringList RegisteredStatusNotifierItems READ RegisteredStatusNotifierItems)
|
||||
|
||||
public:
|
||||
explicit StatusNotifierWatcher(QObject *parent = nullptr);
|
||||
~StatusNotifierWatcher();
|
||||
|
||||
bool isStatusNotifierHostRegistered() { return mHosts.count() > 0; }
|
||||
int protocolVersion() const { return 0; }
|
||||
QStringList RegisteredStatusNotifierItems() const { return mServices; }
|
||||
|
||||
signals:
|
||||
Q_SCRIPTABLE void StatusNotifierItemRegistered(const QString &service);
|
||||
Q_SCRIPTABLE void StatusNotifierItemUnregistered(const QString &service);
|
||||
Q_SCRIPTABLE void StatusNotifierHostRegistered();
|
||||
|
||||
public slots:
|
||||
Q_SCRIPTABLE void RegisterStatusNotifierItem(const QString &serviceOrPath);
|
||||
Q_SCRIPTABLE void RegisterStatusNotifierHost(const QString &service);
|
||||
|
||||
void serviceUnregistered(const QString &service);
|
||||
|
||||
private:
|
||||
QStringList mServices;
|
||||
QStringList mHosts;
|
||||
QDBusServiceWatcher *mWatcher;
|
||||
};
|
||||
|
||||
#endif // STATUSNOTIFIERWATCHER_H
|
26
src/systemappitem.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "systemappitem.h"
|
||||
|
||||
SystemAppItem::SystemAppItem(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
|
||||
}
|
42
src/systemappitem.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 SYSTEMAPPITEM_H
|
||||
#define SYSTEMAPPITEM_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class SystemAppItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SystemAppItem(QObject *parent = nullptr);
|
||||
|
||||
QString path;
|
||||
QString name;
|
||||
QString genericName;
|
||||
QString comment;
|
||||
QString iconName;
|
||||
QString startupWMClass;
|
||||
QString exec;
|
||||
QStringList args;
|
||||
};
|
||||
|
||||
#endif // SYSTEMAPPITEM_H
|
156
src/systemappmonitor.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "systemappmonitor.h"
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QRegularExpression>
|
||||
#include <QDirIterator>
|
||||
#include <QSettings>
|
||||
#include <QLocale>
|
||||
|
||||
#define SystemApplicationsFolder "/usr/share/applications"
|
||||
|
||||
static SystemAppMonitor *SELF = nullptr;
|
||||
|
||||
static QByteArray detectDesktopEnvironment()
|
||||
{
|
||||
const QByteArray desktop = qgetenv("XDG_CURRENT_DESKTOP");
|
||||
|
||||
if (!desktop.isEmpty())
|
||||
return desktop.toUpper();
|
||||
|
||||
return QByteArray("UNKNOWN");
|
||||
}
|
||||
|
||||
SystemAppMonitor *SystemAppMonitor::self()
|
||||
{
|
||||
if (SELF == nullptr)
|
||||
SELF = new SystemAppMonitor;
|
||||
|
||||
return SELF;
|
||||
}
|
||||
|
||||
SystemAppMonitor::SystemAppMonitor(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
|
||||
watcher->addPath(SystemApplicationsFolder);
|
||||
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &SystemAppMonitor::refresh);
|
||||
refresh();
|
||||
}
|
||||
|
||||
SystemAppMonitor::~SystemAppMonitor()
|
||||
{
|
||||
while (!m_items.isEmpty())
|
||||
delete m_items.takeFirst();
|
||||
}
|
||||
|
||||
SystemAppItem *SystemAppMonitor::find(const QString &filePath)
|
||||
{
|
||||
for (SystemAppItem *item : m_items)
|
||||
if (item->path == filePath)
|
||||
return item;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SystemAppMonitor::refresh()
|
||||
{
|
||||
QStringList addedEntries;
|
||||
for (SystemAppItem *item : m_items)
|
||||
addedEntries.append(item->path);
|
||||
|
||||
QStringList allEntries;
|
||||
QDirIterator it(SystemApplicationsFolder, { "*.desktop" }, QDir::NoFilter, QDirIterator::Subdirectories);
|
||||
|
||||
while (it.hasNext()) {
|
||||
const QString &filePath = it.next();
|
||||
|
||||
if (!QFile::exists(filePath))
|
||||
continue;
|
||||
|
||||
allEntries.append(filePath);
|
||||
}
|
||||
|
||||
for (const QString &filePath : allEntries) {
|
||||
if (!addedEntries.contains(filePath)) {
|
||||
addApplication(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
for (SystemAppItem *item : m_items) {
|
||||
if (!allEntries.contains(item->path)) {
|
||||
removeApplication(item);
|
||||
}
|
||||
}
|
||||
|
||||
emit refreshed();
|
||||
}
|
||||
|
||||
void SystemAppMonitor::addApplication(const QString &filePath)
|
||||
{
|
||||
if (find(filePath))
|
||||
return;
|
||||
|
||||
QSettings desktop(filePath, QSettings::IniFormat);
|
||||
desktop.setIniCodec("UTF-8");
|
||||
desktop.beginGroup("Desktop Entry");
|
||||
|
||||
if (desktop.contains("OnlyShowIn")) {
|
||||
const QString &value = desktop.value("OnlyShowIn").toString();
|
||||
if (!value.contains(detectDesktopEnvironment(), Qt::CaseInsensitive)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (desktop.value("NoDisplay").toBool() ||
|
||||
desktop.value("Hidden").toBool()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString appName = desktop.value(QString("Name[%1]").arg(QLocale::system().name())).toString();
|
||||
QString appExec = desktop.value("Exec").toString();
|
||||
|
||||
if (appName.isEmpty())
|
||||
appName = desktop.value("Name").toString();
|
||||
|
||||
appExec.remove(QRegularExpression("%."));
|
||||
appExec.remove(QRegularExpression("^\""));
|
||||
// appExec.remove(QRegularExpression(" *$"));
|
||||
appExec = appExec.simplified();
|
||||
|
||||
SystemAppItem *item = new SystemAppItem;
|
||||
item->path = filePath;
|
||||
item->name = appName;
|
||||
item->genericName = desktop.value("GenericName").toString();
|
||||
item->comment = desktop.value("Comment").toString();
|
||||
item->iconName = desktop.value("Icon").toString();
|
||||
item->startupWMClass = desktop.value("StartupWMClass").toString();
|
||||
item->exec = appExec;
|
||||
item->args = appExec.split(" ");
|
||||
|
||||
m_items.append(item);
|
||||
}
|
||||
|
||||
void SystemAppMonitor::removeApplication(SystemAppItem *item)
|
||||
{
|
||||
m_items.removeOne(item);
|
||||
item->deleteLater();
|
||||
}
|
51
src/systemappmonitor.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 SYSTEMAPPMONITOR_H
|
||||
#define SYSTEMAPPMONITOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include "systemappitem.h"
|
||||
|
||||
class SystemAppMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static SystemAppMonitor *self();
|
||||
|
||||
explicit SystemAppMonitor(QObject *parent = nullptr);
|
||||
~SystemAppMonitor();
|
||||
|
||||
SystemAppItem *find(const QString &filePath);
|
||||
QList<SystemAppItem *> applications() { return m_items; }
|
||||
|
||||
signals:
|
||||
void refreshed();
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
void addApplication(const QString &filePath);
|
||||
void removeApplication(SystemAppItem *item);
|
||||
|
||||
private:
|
||||
QList<SystemAppItem *> m_items;
|
||||
};
|
||||
|
||||
#endif // SYSTEMAPPMONITOR_H
|
58
src/trashmanager.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "trashmanager.h"
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
|
||||
const QString TrashDir = QDir::homePath() + "/.local/share/Trash";
|
||||
const QDir::Filters ItemsShouldCount = QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
|
||||
|
||||
TrashManager::TrashManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_filesWatcher(new QFileSystemWatcher(this)),
|
||||
m_count(0)
|
||||
{
|
||||
onDirectoryChanged();
|
||||
connect(m_filesWatcher, &QFileSystemWatcher::directoryChanged, this, &TrashManager::onDirectoryChanged, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void TrashManager::emptyTrash()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TrashManager::openTrash()
|
||||
{
|
||||
QProcess::startDetached("gio", QStringList() << "open" << "trash:///");
|
||||
}
|
||||
|
||||
void TrashManager::onDirectoryChanged()
|
||||
{
|
||||
m_filesWatcher->addPath(TrashDir);
|
||||
|
||||
if (QDir(TrashDir + "/files").exists()) {
|
||||
m_filesWatcher->addPath(TrashDir + "/files");
|
||||
m_count = QDir(TrashDir + "/files").entryList(ItemsShouldCount).count();
|
||||
} else {
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
emit countChanged();
|
||||
}
|
50
src/trashmanager.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 TRASHMANAGER_H
|
||||
#define TRASHMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
class TrashManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
explicit TrashManager(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void openTrash();
|
||||
Q_INVOKABLE void emptyTrash();
|
||||
|
||||
int count() { return m_count; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void countChanged();
|
||||
|
||||
private slots:
|
||||
void onDirectoryChanged();
|
||||
|
||||
private:
|
||||
QFileSystemWatcher *m_filesWatcher;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
#endif // TRASHMANAGER_H
|
145
src/utils.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "utils.h"
|
||||
#include "systemappmonitor.h"
|
||||
#include "systemappitem.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QUrlQuery>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
|
||||
#include <KWindowSystem>
|
||||
|
||||
static Utils *INSTANCE = nullptr;
|
||||
|
||||
Utils *Utils::instance()
|
||||
{
|
||||
if (!INSTANCE)
|
||||
INSTANCE = new Utils;
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
Utils::Utils(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_sysAppMonitor(SystemAppMonitor::self())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString Utils::cmdFromPid(quint32 pid)
|
||||
{
|
||||
QFile file(QString("/proc/%1/cmdline").arg(pid));
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return QString();
|
||||
|
||||
QString cmd = QString::fromUtf8(file.readAll());
|
||||
QString bin;
|
||||
|
||||
for (int i = 0; i < cmd.size(); ++i) {
|
||||
const QChar ch = cmd[i];
|
||||
if (ch == '\\')
|
||||
i++;
|
||||
else if (ch == ' ')
|
||||
break;
|
||||
else
|
||||
bin += ch;
|
||||
}
|
||||
|
||||
if (bin.split("/").last() == "electron")
|
||||
return QString();
|
||||
|
||||
if (bin.startsWith("/"))
|
||||
return bin.split("/").last();
|
||||
|
||||
return bin;
|
||||
}
|
||||
|
||||
QString Utils::desktopPathFromMetadata(const QString &appId, quint32 pid, const QString &xWindowWMClassName)
|
||||
{
|
||||
QString result;
|
||||
|
||||
if (!appId.isEmpty() && !xWindowWMClassName.isEmpty()) {
|
||||
for (SystemAppItem *item : m_sysAppMonitor->applications()) {
|
||||
// Start search.
|
||||
const QFileInfo desktopFileInfo(item->path);
|
||||
const QString cmdline = cmdFromPid(pid);
|
||||
|
||||
bool founded = false;
|
||||
|
||||
if (desktopFileInfo.baseName() == xWindowWMClassName ||
|
||||
desktopFileInfo.completeBaseName() == xWindowWMClassName)
|
||||
founded = true;
|
||||
|
||||
// StartupWMClass=STRING
|
||||
// If true, it is KNOWN that the application will map at least one
|
||||
// window with the given string as its WM class or WM name hint.
|
||||
// ref: https://specifications.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt
|
||||
if (item->startupWMClass.startsWith(appId, Qt::CaseInsensitive) ||
|
||||
item->startupWMClass.startsWith(xWindowWMClassName, Qt::CaseInsensitive))
|
||||
founded = true;
|
||||
|
||||
if (!founded && item->iconName.startsWith(xWindowWMClassName, Qt::CaseInsensitive))
|
||||
founded = true;
|
||||
|
||||
// Icon name and cmdline.
|
||||
if (!founded && item->iconName == cmdline)
|
||||
founded = true;
|
||||
|
||||
// Exec name and cmdline.
|
||||
if (!founded && item->exec == cmdline)
|
||||
founded = true;
|
||||
|
||||
// Try matching mapped name against 'Name'.
|
||||
if (!founded && item->name.startsWith(xWindowWMClassName, Qt::CaseInsensitive))
|
||||
founded = true;
|
||||
|
||||
// exec
|
||||
if (!founded && item->exec.startsWith(xWindowWMClassName, Qt::CaseInsensitive))
|
||||
founded = true;
|
||||
|
||||
if (!founded && desktopFileInfo.baseName().startsWith(xWindowWMClassName, Qt::CaseInsensitive))
|
||||
founded = true;
|
||||
|
||||
if (founded) {
|
||||
result = item->path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QMap<QString, QString> Utils::readInfoFromDesktop(const QString &desktopFile)
|
||||
{
|
||||
QMap<QString, QString> info;
|
||||
for (SystemAppItem *item : m_sysAppMonitor->applications()) {
|
||||
if (item->path == desktopFile) {
|
||||
info.insert("Icon", item->iconName);
|
||||
info.insert("Name", item->name);
|
||||
info.insert("Exec", item->exec);
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
61
src/utils.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
#include <QUrl>
|
||||
|
||||
class SystemAppMonitor;
|
||||
class Utils : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct AppData
|
||||
{
|
||||
QString id; // Application id (*.desktop sans extension).
|
||||
QString name; // Application name.
|
||||
QString genericName; // Generic application name.
|
||||
QIcon icon;
|
||||
QUrl url;
|
||||
bool skipTaskbar = false;
|
||||
};
|
||||
|
||||
enum UrlComparisonMode {
|
||||
Strict = 0,
|
||||
IgnoreQueryItems
|
||||
};
|
||||
|
||||
static Utils *instance();
|
||||
|
||||
explicit Utils(QObject *parent = nullptr);
|
||||
|
||||
QString cmdFromPid(quint32 pid);
|
||||
QString desktopPathFromMetadata(const QString &appId, quint32 pid = 0,
|
||||
const QString &xWindowWMClassName = QString());
|
||||
QMap<QString, QString> readInfoFromDesktop(const QString &desktopFile);
|
||||
|
||||
private:
|
||||
SystemAppMonitor *m_sysAppMonitor;
|
||||
};
|
||||
|
||||
#endif // UTILS_H
|
151
src/volumemanager.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#include "volumemanager.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QDBusPendingCall>
|
||||
|
||||
static const QString Service = "org.cyber.Settings";
|
||||
static const QString ObjectPath = "/Audio";
|
||||
static const QString Interface = "org.cyber.Audio";
|
||||
|
||||
static VolumeManager *SELF = nullptr;
|
||||
|
||||
VolumeManager *VolumeManager::self()
|
||||
{
|
||||
if (!SELF)
|
||||
SELF = new VolumeManager;
|
||||
|
||||
return SELF;
|
||||
}
|
||||
|
||||
VolumeManager::VolumeManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_isValid(false)
|
||||
, m_isMute(false)
|
||||
, m_volume(0)
|
||||
{
|
||||
QDBusServiceWatcher *watcher = new QDBusServiceWatcher(this);
|
||||
watcher->setConnection(QDBusConnection::sessionBus());
|
||||
watcher->addWatchedService(Service);
|
||||
|
||||
init();
|
||||
|
||||
connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &VolumeManager::init);
|
||||
}
|
||||
|
||||
bool VolumeManager::isValid() const
|
||||
{
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
void VolumeManager::initStatus()
|
||||
{
|
||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
||||
|
||||
m_isValid = iface.isValid() && !iface.lastError().isValid();
|
||||
|
||||
if (m_isValid) {
|
||||
int volume = iface.property("volume").toInt();
|
||||
bool mute = iface.property("mute").toBool();
|
||||
|
||||
if (m_volume != volume) {
|
||||
m_volume = volume;
|
||||
emit volumeChanged();
|
||||
}
|
||||
|
||||
if (m_isMute != mute) {
|
||||
m_isMute = mute;
|
||||
emit muteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
emit validChanged();
|
||||
}
|
||||
|
||||
void VolumeManager::connectDBusSignals()
|
||||
{
|
||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
||||
|
||||
if (iface.isValid()) {
|
||||
QDBusConnection::sessionBus().connect(Service, ObjectPath, Interface, "volumeChanged",
|
||||
this, SLOT(onDBusVolumeChanged(int)));
|
||||
QDBusConnection::sessionBus().connect(Service, ObjectPath, Interface, "muteChanged",
|
||||
this, SLOT(onDBusMuteChanged(bool)));
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeManager::onDBusVolumeChanged(int volume)
|
||||
{
|
||||
if (m_volume != volume) {
|
||||
m_volume = volume;
|
||||
emit volumeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeManager::onDBusMuteChanged(bool mute)
|
||||
{
|
||||
if (m_isMute != mute) {
|
||||
m_isMute = mute;
|
||||
emit muteChanged();
|
||||
|
||||
// Need to update the icon.
|
||||
emit volumeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int VolumeManager::volume() const
|
||||
{
|
||||
return m_volume;
|
||||
}
|
||||
|
||||
QString VolumeManager::iconName() const
|
||||
{
|
||||
if (m_volume <= 0 || m_isMute)
|
||||
return QStringLiteral("audio-volume-muted-symbolic");
|
||||
else if (m_volume <= 25)
|
||||
return QStringLiteral("audio-volume-low-symbolic");
|
||||
else if (m_volume <= 75)
|
||||
return QStringLiteral("audio-volume-medium-symbolic");
|
||||
else
|
||||
return QStringLiteral("audio-volume-high-symbolic");
|
||||
}
|
||||
|
||||
void VolumeManager::toggleMute()
|
||||
{
|
||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
||||
|
||||
if (iface.isValid()) {
|
||||
iface.call("toggleMute");
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeManager::setMute(bool mute)
|
||||
{
|
||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
||||
|
||||
if (iface.isValid()) {
|
||||
iface.call("setMute", QVariant::fromValue(mute));
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeManager::setVolume(int value)
|
||||
{
|
||||
QDBusInterface iface(Service, ObjectPath, Interface, QDBusConnection::sessionBus(), this);
|
||||
|
||||
if (iface.isValid()) {
|
||||
iface.call("setVolume", QVariant::fromValue(value));
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeManager::init()
|
||||
{
|
||||
initStatus();
|
||||
connectDBusSignals();
|
||||
}
|
||||
|
||||
bool VolumeManager::isMute() const
|
||||
{
|
||||
return m_isMute;
|
||||
}
|
49
src/volumemanager.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef VOLUMEMANAGER_H
|
||||
#define VOLUMEMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class VolumeManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isValid READ isValid NOTIFY validChanged)
|
||||
Q_PROPERTY(bool isMute READ isMute NOTIFY muteChanged)
|
||||
Q_PROPERTY(int volume READ volume NOTIFY volumeChanged)
|
||||
Q_PROPERTY(QString iconName READ iconName NOTIFY volumeChanged)
|
||||
|
||||
public:
|
||||
static VolumeManager *self();
|
||||
|
||||
explicit VolumeManager(QObject *parent = nullptr);
|
||||
|
||||
bool isValid() const;
|
||||
bool isMute() const;
|
||||
int volume() const;
|
||||
|
||||
QString iconName() const;
|
||||
|
||||
Q_INVOKABLE void toggleMute();
|
||||
Q_INVOKABLE void setMute(bool mute);
|
||||
Q_INVOKABLE void setVolume(int value);
|
||||
|
||||
signals:
|
||||
void validChanged();
|
||||
void muteChanged();
|
||||
void volumeChanged();
|
||||
|
||||
private:
|
||||
void init();
|
||||
void initStatus();
|
||||
void connectDBusSignals();
|
||||
|
||||
private slots:
|
||||
void onDBusVolumeChanged(int volume);
|
||||
void onDBusMuteChanged(bool mute);
|
||||
|
||||
private:
|
||||
bool m_isValid;
|
||||
bool m_isMute;
|
||||
int m_volume;
|
||||
};
|
||||
|
||||
#endif // VOLUMEMANAGER_H
|
220
src/xwindowinterface.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 "xwindowinterface.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <QX11Info>
|
||||
#include <QWindow>
|
||||
#include <QScreen>
|
||||
|
||||
#include <KWindowEffects>
|
||||
#include <KWindowSystem>
|
||||
#include <KWindowInfo>
|
||||
|
||||
// X11
|
||||
#include <NETWM>
|
||||
|
||||
static XWindowInterface *INSTANCE = nullptr;
|
||||
|
||||
XWindowInterface *XWindowInterface::instance()
|
||||
{
|
||||
if (!INSTANCE)
|
||||
INSTANCE = new XWindowInterface;
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
XWindowInterface::XWindowInterface(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &XWindowInterface::onWindowadded);
|
||||
connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &XWindowInterface::windowRemoved);
|
||||
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &XWindowInterface::activeChanged);
|
||||
}
|
||||
|
||||
void XWindowInterface::enableBlurBehind(QWindow *view, bool enable, const QRegion ®ion)
|
||||
{
|
||||
KWindowEffects::enableBlurBehind(view->winId(), enable, region);
|
||||
}
|
||||
|
||||
WId XWindowInterface::activeWindow()
|
||||
{
|
||||
return KWindowSystem::activeWindow();
|
||||
}
|
||||
|
||||
void XWindowInterface::minimizeWindow(WId win)
|
||||
{
|
||||
KWindowSystem::minimizeWindow(win);
|
||||
}
|
||||
|
||||
void XWindowInterface::closeWindow(WId id)
|
||||
{
|
||||
// FIXME: Why there is no such thing in KWindowSystem??
|
||||
NETRootInfo(QX11Info::connection(), NET::CloseWindow).closeWindowRequest(id);
|
||||
}
|
||||
|
||||
void XWindowInterface::forceActiveWindow(WId win)
|
||||
{
|
||||
KWindowSystem::forceActiveWindow(win);
|
||||
}
|
||||
|
||||
QMap<QString, QVariant> XWindowInterface::requestInfo(quint64 wid)
|
||||
{
|
||||
const KWindowInfo winfo { wid, NET::WMFrameExtents
|
||||
| NET::WMWindowType
|
||||
| NET::WMGeometry
|
||||
| NET::WMDesktop
|
||||
| NET::WMState
|
||||
| NET::WMName
|
||||
| NET::WMVisibleName,
|
||||
NET::WM2WindowClass
|
||||
| NET::WM2Activities
|
||||
| NET::WM2AllowedActions
|
||||
| NET::WM2TransientFor };
|
||||
QMap<QString, QVariant> result;
|
||||
const QString winClass = QString(winfo.windowClassClass());
|
||||
|
||||
result.insert("iconName", winClass.toLower());
|
||||
result.insert("active", wid == KWindowSystem::activeWindow());
|
||||
result.insert("visibleName", winfo.visibleName());
|
||||
result.insert("id", winClass);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString XWindowInterface::requestWindowClass(quint64 wid)
|
||||
{
|
||||
return KWindowInfo(wid, NET::Supported, NET::WM2WindowClass).windowClassClass();
|
||||
}
|
||||
|
||||
bool XWindowInterface::isAcceptableWindow(quint64 wid)
|
||||
{
|
||||
QFlags<NET::WindowTypeMask> ignoreList;
|
||||
ignoreList |= NET::DesktopMask;
|
||||
ignoreList |= NET::DockMask;
|
||||
ignoreList |= NET::SplashMask;
|
||||
ignoreList |= NET::ToolbarMask;
|
||||
ignoreList |= NET::MenuMask;
|
||||
ignoreList |= NET::PopupMenuMask;
|
||||
ignoreList |= NET::NotificationMask;
|
||||
|
||||
KWindowInfo info(wid, NET::WMWindowType | NET::WMState, NET::WM2TransientFor | NET::WM2WindowClass);
|
||||
|
||||
if (!info.valid())
|
||||
return false;
|
||||
|
||||
if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList))
|
||||
return false;
|
||||
|
||||
if (info.hasState(NET::SkipTaskbar) || info.hasState(NET::SkipPager))
|
||||
return false;
|
||||
|
||||
// WM_TRANSIENT_FOR hint not set - normal window
|
||||
WId transFor = info.transientFor();
|
||||
if (transFor == 0 || transFor == wid || transFor == (WId) QX11Info::appRootWindow())
|
||||
return true;
|
||||
|
||||
info = KWindowInfo(transFor, NET::WMWindowType);
|
||||
|
||||
QFlags<NET::WindowTypeMask> normalFlag;
|
||||
normalFlag |= NET::NormalMask;
|
||||
normalFlag |= NET::DialogMask;
|
||||
normalFlag |= NET::UtilityMask;
|
||||
|
||||
return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
|
||||
}
|
||||
|
||||
void XWindowInterface::setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect, bool isMax)
|
||||
{
|
||||
NETExtendedStrut strut;
|
||||
|
||||
const auto screen = view->screen();
|
||||
|
||||
const QRect currentScreen { screen->geometry() };
|
||||
const QRect wholeScreen { {0, 0}, screen->virtualSize() };
|
||||
|
||||
switch (direction) {
|
||||
case DockSettings::Left: {
|
||||
const int leftOffset = { screen->geometry().left() };
|
||||
strut.left_width = rect.width() + leftOffset + DockSettings::self()->edgeMargins();
|
||||
strut.left_start = rect.y();
|
||||
strut.left_end = rect.y() + rect.height() - 1;
|
||||
break;
|
||||
}
|
||||
case DockSettings::Bottom: {
|
||||
const int bottomOffset { wholeScreen.bottom() - currentScreen.bottom() };
|
||||
strut.bottom_width = rect.height() + bottomOffset + (isMax ? 0 : DockSettings::self()->edgeMargins());
|
||||
strut.bottom_start = rect.x();
|
||||
strut.bottom_end = rect.x() + rect.width();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
KWindowSystem::setExtendedStrut(view->winId(),
|
||||
strut.left_width, strut.left_start, strut.left_end,
|
||||
strut.right_width, strut.right_start, strut.right_end,
|
||||
strut.top_width, strut.top_start, strut.top_end,
|
||||
strut.bottom_width, strut.bottom_start, strut.bottom_end
|
||||
);
|
||||
}
|
||||
|
||||
void XWindowInterface::startInitWindows()
|
||||
{
|
||||
for (auto wid : KWindowSystem::self()->windows()) {
|
||||
onWindowadded(wid);
|
||||
}
|
||||
}
|
||||
|
||||
QString XWindowInterface::desktopFilePath(quint64 wid)
|
||||
{
|
||||
const KWindowInfo info(wid, NET::Properties(), NET::WM2WindowClass | NET::WM2DesktopFileName);
|
||||
return Utils::instance()->desktopPathFromMetadata(info.windowClassClass(),
|
||||
NETWinInfo(QX11Info::connection(), wid,
|
||||
QX11Info::appRootWindow(),
|
||||
NET::WMPid,
|
||||
NET::Properties2()).pid(),
|
||||
info.windowClassName());
|
||||
}
|
||||
|
||||
void XWindowInterface::setIconGeometry(quint64 wid, const QRect &rect)
|
||||
{
|
||||
NETWinInfo info(QX11Info::connection(),
|
||||
wid,
|
||||
(WId) QX11Info::appRootWindow(),
|
||||
NET::WMIconGeometry,
|
||||
QFlags<NET::Property2>(1));
|
||||
NETRect nrect;
|
||||
nrect.pos.x = rect.x();
|
||||
nrect.pos.y = rect.y();
|
||||
nrect.size.height = rect.height();
|
||||
nrect.size.width = rect.width();
|
||||
info.setIconGeometry(nrect);
|
||||
}
|
||||
|
||||
void XWindowInterface::onWindowadded(quint64 wid)
|
||||
{
|
||||
if (isAcceptableWindow(wid)) {
|
||||
emit windowAdded(wid);
|
||||
}
|
||||
}
|
67
src/xwindowinterface.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2020 ~ 2021 CyberOS Team.
|
||||
*
|
||||
* Author: rekols <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 XWINDOWINTERFACE_H
|
||||
#define XWINDOWINTERFACE_H
|
||||
|
||||
#include "applicationitem.h"
|
||||
#include "docksettings.h"
|
||||
#include <QObject>
|
||||
|
||||
// KLIB
|
||||
#include <KWindowInfo>
|
||||
#include <KWindowEffects>
|
||||
|
||||
class XWindowInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static XWindowInterface *instance();
|
||||
explicit XWindowInterface(QObject *parent = nullptr);
|
||||
|
||||
void enableBlurBehind(QWindow *view, bool enable = true, const QRegion ®ion = QRegion());
|
||||
|
||||
WId activeWindow();
|
||||
void minimizeWindow(WId win);
|
||||
void closeWindow(WId id);
|
||||
void forceActiveWindow(WId win);
|
||||
|
||||
QMap<QString, QVariant> requestInfo(quint64 wid);
|
||||
QString requestWindowClass(quint64 wid);
|
||||
bool isAcceptableWindow(quint64 wid);
|
||||
|
||||
void setViewStruts(QWindow *view, DockSettings::Direction direction, const QRect &rect, bool isMax = false);
|
||||
|
||||
void startInitWindows();
|
||||
|
||||
QString desktopFilePath(quint64 wid);
|
||||
|
||||
void setIconGeometry(quint64 wid, const QRect &rect);
|
||||
|
||||
signals:
|
||||
void windowAdded(quint64 wid);
|
||||
void windowRemoved(quint64 wid);
|
||||
void activeChanged(quint64 wid);
|
||||
|
||||
private:
|
||||
void onWindowadded(quint64 wid);
|
||||
};
|
||||
|
||||
#endif // XWINDOWINTERFACE_H
|
11
svg/dark/audio-volume-high-symbolic.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(0 -.00047914)" fill="#FFFFFF">
|
||||
<rect y="6" width="5" height="4" ry="1" fill-rule="evenodd"/>
|
||||
<path d="m6 3-3 3v4l3 3z"/>
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M 13.139,1.428 C 12.594,1 12,1.652 12.455,2.16 A 8,8 0 0 1 15,8 8,8 0 0 1 12.446,13.852 C 12,14.323 12.626,15 13.123,14.58 A 9,9 0 0 0 16,8 9,9 0 0 0 13.139,1.428 Z"/>
|
||||
<path d="m10.775 2.889c-0.587-0.535-1.199 0.225-0.684 0.732a6 6 0 0 1 1.909 4.379 6 6 0 0 1-1.916 4.389c-0.469 0.446 0.173 1.146 0.68 0.728a7 7 0 0 0 2.236-5.117 7 7 0 0 0-2.225-5.111z"/>
|
||||
<path d="M 8.41,4.35 C 7.89,3.856 7.255,4.57 7.727,5.08 A 4,4 0 0 1 9,8 4,4 0 0 1 7.723,10.926 c -0.473,0.43 0.14,1.152 0.68,0.73 A 5,5 0 0 0 10,8 5,5 0 0 0 8.41,4.35 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 820 B |
11
svg/dark/audio-volume-low-symbolic.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(0 -.00047914)" fill="#FFFFFF">
|
||||
<rect y="6" width="5" height="4" ry="1" fill-rule="evenodd"/>
|
||||
<path d="m6 3-3 3v4l3 3z"/>
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M 13.139,1.428 C 12.594,1 12,1.652 12.455,2.16 A 8,8 0 0 1 15,8 8,8 0 0 1 12.446,13.852 C 12,14.323 12.626,15 13.123,14.58 A 9,9 0 0 0 16,8 9,9 0 0 0 13.139,1.428 Z" opacity=".35"/>
|
||||
<path d="m10.775 2.889c-0.587-0.535-1.199 0.225-0.684 0.732a6 6 0 0 1 1.909 4.379 6 6 0 0 1-1.916 4.389c-0.469 0.446 0.173 1.146 0.68 0.728a7 7 0 0 0 2.236-5.117 7 7 0 0 0-2.225-5.111z" opacity=".35"/>
|
||||
<path d="M 8.41,4.35 C 7.89,3.856 7.255,4.57 7.727,5.08 A 4,4 0 0 1 9,8 4,4 0 0 1 7.723,10.926 c -0.473,0.43 0.14,1.152 0.68,0.73 A 5,5 0 0 0 10,8 5,5 0 0 0 8.41,4.35 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 848 B |
11
svg/dark/audio-volume-medium-symbolic.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(0 -.00047914)" fill="#FFFFFF">
|
||||
<rect y="6" width="5" height="4" ry="1" fill-rule="evenodd"/>
|
||||
<path d="m6 3-3 3v4l3 3z"/>
|
||||
<g fill-rule="evenodd">
|
||||
<path d="M 13.139,1.428 C 12.594,1 12,1.652 12.455,2.16 A 8,8 0 0 1 15,8 8,8 0 0 1 12.446,13.852 C 12,14.323 12.626,15 13.123,14.58 A 9,9 0 0 0 16,8 9,9 0 0 0 13.139,1.428 Z" opacity=".35"/>
|
||||
<path d="m10.775 2.889c-0.587-0.535-1.199 0.225-0.684 0.732a6 6 0 0 1 1.909 4.379 6 6 0 0 1-1.916 4.389c-0.469 0.446 0.173 1.146 0.68 0.728a7 7 0 0 0 2.236-5.117 7 7 0 0 0-2.225-5.111z"/>
|
||||
<path d="M 8.41,4.35 C 7.89,3.856 7.255,4.57 7.727,5.08 A 4,4 0 0 1 9,8 4,4 0 0 1 7.723,10.926 c -0.473,0.43 0.14,1.152 0.68,0.73 A 5,5 0 0 0 10,8 5,5 0 0 0 8.41,4.35 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 834 B |
17
svg/dark/audio-volume-muted-symbolic.svg
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?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" width="16" height="16" version="1.1" id="svg16" sodipodi:docname="audio-volume-muted-symbolic.svg" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata id="metadata22">
|
||||
<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></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs20" />
|
||||
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="2062" inkscape:window-height="1410" id="namedview18" showgrid="false" inkscape:zoom="45.9375" inkscape:cx="8" inkscape:cy="8" inkscape:window-x="98" inkscape:window-y="30" inkscape:window-maximized="1" inkscape:current-layer="svg16" />
|
||||
<rect y="5.9995208" width="5" height="4" ry="1" fill-rule="evenodd" id="rect2" x="0" style="fill:white;fill-opacity:1" />
|
||||
<path d="m 6,2.9995209 -3,3 v 4 l 3,3.0000001 z" id="path4" style="fill:white;fill-opacity:1" />
|
||||
<path style="color:black;display:inline;overflow:visible;visibility:visible;opacity:1;fill:white;fill-opacity:0.69999999;fill-rule:nonzero;stroke:none;stroke-width:0.422161;marker:none;enable-background:accumulate" d="M 9.721371,4.37179 8.62099,5.4538899 11.210117,8.000004 8.62099,10.546115 9.721371,11.62821 12.310494,9.0821003 14.899622,11.62821 16,10.546115 13.410872,8.000004 16,5.4538899 14.899622,4.37179 12.310494,6.9179037 Z" id="rect3019" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc" />
|
||||
</svg>
|
After Width: | Height: | Size: 2 KiB |
68
svg/dark/battery-level-0-charging-symbolic.svg
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
enable-background="new"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="battery-level-0-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2062"
|
||||
inkscape:window-height="1405"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="98"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12"
|
||||
inkscape:document-rotation="0" />
|
||||
<title
|
||||
id="title2">Paper Symbolic Icon Theme</title>
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#d33636;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#d33636;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path8" />
|
||||
<path
|
||||
d="M 9.834,4 6.5,9 h 3 l -0.75,3 h 0.41602 l 3.334,-5 h -3 l 0.75,-3 z"
|
||||
enable-background="new"
|
||||
id="path8-3"
|
||||
style="fill:#d33636;fill-opacity:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
63
svg/dark/battery-level-0-symbolic.svg
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
enable-background="new"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="battery-level-0-charging-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2062"
|
||||
inkscape:window-height="1405"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="98"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12"
|
||||
inkscape:document-rotation="0" />
|
||||
<title
|
||||
id="title2">Paper Symbolic Icon Theme</title>
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#d33636;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#d33636;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path8" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
9
svg/dark/battery-level-10-charging-symbolic.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" fill-rule="evenodd" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" fill-rule="evenodd" style="paint-order:stroke fill markers"/>
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new"/>
|
||||
</g>
|
||||
<path d="m3.4824 5c-0.26703 0-0.48242 0.24253-0.48242 0.54492v4.9102c0 0.3024 0.21539 0.54492 0.48242 0.54492h2.0352c0.26703 0 0.48242-0.24253 0.48242-0.54492v-0.5918c-0.46977-0.27296-0.67079-0.90961-0.33203-1.418l0.33203-0.49805v-2.4023c0-0.3024-0.21539-0.54492-0.48242-0.54492h-2.0352z" enable-background="new" fill="#39BB5E" fill-rule="evenodd" style="paint-order:stroke fill markers"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
8
svg/dark/battery-level-10-symbolic.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#d33636" fill-rule="evenodd">
|
||||
<rect x="2" y="5" width="3" height="6" rx=".5048" ry=".54584" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 714 B |
11
svg/dark/battery-level-100-charging-symbolic.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m2.5215 5c-0.28865 0-0.52148 0.24253-0.52148 0.54492v4.9102c0 0.30239 0.23284 0.54492 0.52148 0.54492h4.4473l0.25-1h-1.7188c-0.79859-1.712e-4 -1.2749-0.89013-0.83203-1.5547l2.2969-3.4453h-4.4434zm7.5098 0-0.25 1h1.7188c0.79859 1.713e-4 1.2749 0.89013 0.83203 1.5547l-2.2969 3.4453h4.4434c0.28865 0 0.52148-0.24253 0.52148-0.54492v-4.9102c0-0.30239-0.23284-0.54492-0.52148-0.54492h-4.4473z" fill="#39BB5E" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
8
svg/dark/battery-level-100-symbolic.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#FFFFFF" fill-rule="evenodd">
|
||||
<rect x="2" y="5" width="13" height="6" rx=".52103" ry=".54584" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 716 B |
80
svg/dark/battery-level-20-charging-symbolic.svg
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
enable-background="new"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="battery-level-10-charging-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<title
|
||||
id="title2">Paper Symbolic Icon Theme</title>
|
||||
<g
|
||||
transform="translate(1)"
|
||||
fill="#FFFFFF"
|
||||
id="g10">
|
||||
<path
|
||||
d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z"
|
||||
enable-background="new"
|
||||
fill-rule="evenodd"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z"
|
||||
enable-background="new"
|
||||
fill-rule="evenodd"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
<path
|
||||
d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z"
|
||||
enable-background="new"
|
||||
id="path8" />
|
||||
</g>
|
||||
<path
|
||||
d="M 3.5145545,5 C 3.2297263,5 2.99998,5.24253 2.99998,5.54492 v 4.9102 c 0,0.3024 0.2297463,0.54492 0.5145745,0.54492 h 2.170851 c 0.2848282,0 0.5145745,-0.24253 0.5145745,-0.54492 V 9.86332 C 5.6988987,9.59036 5.4844802,8.95371 5.8458194,8.44532 L 6.19998,7.94727 v -2.4023 c 0,-0.3024 -0.2297463,-0.54492 -0.5145745,-0.54492 h -2.170851 z"
|
||||
enable-background="new"
|
||||
fill="#39bb5e"
|
||||
fill-rule="evenodd"
|
||||
style="stroke-width:1.03279;paint-order:stroke fill markers"
|
||||
id="path12" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
71
svg/dark/battery-level-20-symbolic.svg
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
enable-background="new"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="battery-level-10-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<title
|
||||
id="title2">Paper Symbolic Icon Theme</title>
|
||||
<rect
|
||||
x="3"
|
||||
y="5"
|
||||
width="3.2"
|
||||
height="6"
|
||||
rx="0.53845334"
|
||||
ry="0.54584002"
|
||||
style="fill:#d33636;fill-rule:evenodd;stroke-width:1.0328;paint-order:stroke fill markers"
|
||||
id="rect4" />
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#d33636;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#d33636;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path8" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
10
svg/dark/battery-level-30-charging-symbolic.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<svg width="22" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m3.5391 5c-0.29881 0-0.53906 0.24253-0.53906 0.54492v4.9102c0 0.3024 0.24025 0.54492 0.53906 0.54492h4.4297l0.25-1h-1.7188a1.0001 1.0001 0 0 1-0.83203-1.5547l2.2969-3.4453h-4.4258zm5.1289 2.5527-0.29883 0.44727h1.1152a1.0001 1.0001 0 0 1-0.81641-0.44727zm0.84766 0.44727a1.0001 1.0001 0 0 1 0.48438 0.13672v-0.13672h-0.48438z" fill="#39BB5E" stroke-width="1.1832" style="paint-order:stroke fill markers"/>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
70
svg/dark/battery-level-30-symbolic.svg
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
sodipodi:docname="battery-level-40-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs14" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview12"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg10"
|
||||
inkscape:document-rotation="0" />
|
||||
<rect
|
||||
x="3"
|
||||
y="5"
|
||||
width="5"
|
||||
height="6"
|
||||
rx="0"
|
||||
ry="0"
|
||||
stroke-width="0.999982"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="rect2" />
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
10
svg/dark/battery-level-40-charging-symbolic.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<svg width="22" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m3.5391 5c-0.29881 0-0.53906 0.24253-0.53906 0.54492v4.9102c0 0.3024 0.24025 0.54492 0.53906 0.54492h4.4297l0.25-1h-1.7188a1.0001 1.0001 0 0 1-0.83203-1.5547l2.2969-3.4453h-4.4258zm5.1289 2.5527-0.29883 0.44727h1.1152a1.0001 1.0001 0 0 1-0.81641-0.44727zm0.84766 0.44727a1.0001 1.0001 0 0 1 0.48438 0.13672v-0.13672h-0.48438z" fill="#39BB5E" stroke-width="1.1832" style="paint-order:stroke fill markers"/>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
69
svg/dark/battery-level-40-symbolic.svg
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
sodipodi:docname="battery-level-50-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs14" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="785"
|
||||
inkscape:window-height="498"
|
||||
id="namedview12"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="857"
|
||||
inkscape:window-y="158"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg10" />
|
||||
<rect
|
||||
x="3"
|
||||
y="5"
|
||||
width="5.5"
|
||||
height="6"
|
||||
rx="0"
|
||||
ry="0"
|
||||
stroke-width="1.04879"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="rect2" />
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
10
svg/dark/battery-level-50-charging-symbolic.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<svg width="22" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m3.5391 5c-0.29881 0-0.53906 0.24253-0.53906 0.54492v4.9102c0 0.3024 0.24025 0.54492 0.53906 0.54492h4.4297l0.25-1h-1.7188a1.0001 1.0001 0 0 1-0.83203-1.5547l2.2969-3.4453h-4.4258zm5.1289 2.5527-0.29883 0.44727h1.1152a1.0001 1.0001 0 0 1-0.81641-0.44727zm0.84766 0.44727a1.0001 1.0001 0 0 1 0.48438 0.13672v-0.13672h-0.48438z" fill="#39BB5E" stroke-width="1.1832" style="paint-order:stroke fill markers"/>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1 KiB |
7
svg/dark/battery-level-50-symbolic.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<svg width="22" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(1)" fill="#FFFFFF" fill-rule="evenodd">
|
||||
<rect x="2" y="5" width="7" height="6" rx="0" ry="0" stroke-width="1.1832" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 661 B |
78
svg/dark/battery-level-60-charging-symbolic.svg
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="battery-level-50-charging-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="M 3.6161086,5 C 3.2746114,5 3.00004,5.24253 3.00004,5.54492 v 4.9102 c 0,0.3024 0.2745714,0.54492 0.6160686,0.54492 h 5.0625142 l 0.2857144,-1 H 6.9999942 A 1.1429714,1.0001 0 0 1 6.0491028,8.44534 L 8.6741314,5.00004 H 3.6160742 Z m 5.8616,2.5527 -0.34152,0.44727 H 10.410703 A 1.1429714,1.0001 0 0 1 9.4776628,7.5527 Z M 10.446463,7.99997 A 1.1429714,1.0001 0 0 1 11.00004,8.13669 V 7.99997 Z"
|
||||
fill="#39bb5e"
|
||||
stroke-width="1.2649"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path2" />
|
||||
<g
|
||||
transform="translate(1)"
|
||||
fill="#FFFFFF"
|
||||
id="g12">
|
||||
<g
|
||||
fill-rule="evenodd"
|
||||
id="g8">
|
||||
<path
|
||||
d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z"
|
||||
enable-background="new"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z"
|
||||
enable-background="new"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
</g>
|
||||
<path
|
||||
d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z"
|
||||
enable-background="new"
|
||||
id="path10" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
69
svg/dark/battery-level-60-symbolic.svg
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
sodipodi:docname="battery-level-50-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs14" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview12"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg10" />
|
||||
<rect
|
||||
x="3"
|
||||
y="5"
|
||||
width="8"
|
||||
height="6"
|
||||
rx="0"
|
||||
ry="0"
|
||||
stroke-width="1.26489"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="rect2" />
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
78
svg/dark/battery-level-70-charging-symbolic.svg
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="battery-level-50-charging-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="M 3.6161086,5 C 3.2746114,5 3.00004,5.24253 3.00004,5.54492 v 4.9102 c 0,0.3024 0.2745714,0.54492 0.6160686,0.54492 h 5.0625142 l 0.2857144,-1 H 6.9999942 A 1.1429714,1.0001 0 0 1 6.0491028,8.44534 L 8.6741314,5.00004 H 3.6160742 Z m 5.8616,2.5527 -0.34152,0.44727 H 10.410703 A 1.1429714,1.0001 0 0 1 9.4776628,7.5527 Z M 10.446463,7.99997 A 1.1429714,1.0001 0 0 1 11.00004,8.13669 V 7.99997 Z"
|
||||
fill="#39bb5e"
|
||||
stroke-width="1.2649"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path2" />
|
||||
<g
|
||||
transform="translate(1)"
|
||||
fill="#FFFFFF"
|
||||
id="g12">
|
||||
<g
|
||||
fill-rule="evenodd"
|
||||
id="g8">
|
||||
<path
|
||||
d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z"
|
||||
enable-background="new"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z"
|
||||
enable-background="new"
|
||||
style="paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
</g>
|
||||
<path
|
||||
d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z"
|
||||
enable-background="new"
|
||||
id="path10" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
69
svg/dark/battery-level-70-symbolic.svg
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
sodipodi:docname="battery-level-50-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs14" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview12"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg10" />
|
||||
<rect
|
||||
x="3"
|
||||
y="5"
|
||||
width="8"
|
||||
height="6"
|
||||
rx="0"
|
||||
ry="0"
|
||||
stroke-width="1.26489"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="rect2" />
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
11
svg/dark/battery-level-80-charging-symbolic.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new" />
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2.5508 5c-0.30514 0-0.55078 0.24564-0.55078 0.55078v4.8984c0 0.30514 0.24564 0.55078 0.55078 0.55078h4.418l0.25-1h-1.7188c-0.79859-1.712e-4 -1.2749-0.89013-0.83203-1.5547l2.2969-3.4453h-4.4141zm7.4805 0-0.25 1h1.7188c0.1877 4.03e-5 0.35566 0.052848 0.5 0.13672v-0.58594c0-0.30514-0.24564-0.55078-0.55078-0.55078h-1.418zm1.9688 3.0527-1.9648 2.9473h1.4141c0.30514 0 0.55078-0.24564 0.55078-0.55078v-2.3965z" enable-background="new" fill="#39BB5E" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
8
svg/dark/battery-level-80-symbolic.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#FFFFFF" fill-rule="evenodd">
|
||||
<rect x="2" y="5" width="10" height="6" rx=".5236" ry=".54584" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 715 B |
11
svg/dark/battery-level-90-charging-symbolic.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<svg width="22" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Paper Symbolic Icon Theme</title>
|
||||
<g transform="translate(1)" fill="#FFFFFF">
|
||||
<path d="m8.834 4-3.334 5h3l-0.75 3h0.41602l3.334-5h-3l0.75-3z" enable-background="new" />
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m2 3c-1.108 0-2 0.892-2 2v6c0 1.108 0.892 2 2 2h13c1.108 0 2-0.892 2-2v-6c0-1.108-0.892-2-2-2zm0 1h13c0.554 0 1 0.446 1 1v6c0 0.554-0.446 1-1 1h-13c-0.554 0-1-0.446-1-1v-6c0-0.554 0.446-1 1-1z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
<path d="m2.5508 5c-0.30514 0-0.55078 0.24564-0.55078 0.55078v4.8984c0 0.30514 0.24564 0.55078 0.55078 0.55078h4.418l0.25-1h-1.7188c-0.79859-1.712e-4 -1.2749-0.89013-0.83203-1.5547l2.2969-3.4453h-4.4141zm7.4805 0-0.25 1h1.7188c0.1877 4.03e-5 0.35566 0.052848 0.5 0.13672v-0.58594c0-0.30514-0.24564-0.55078-0.55078-0.55078h-1.418zm1.9688 3.0527-1.9648 2.9473h1.4141c0.30514 0 0.55078-0.24564 0.55078-0.55078v-2.3965z" enable-background="new" fill="#39BB5E" style="paint-order:stroke fill markers"/>
|
||||
<path d="m18 6v4a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
72
svg/dark/battery-level-90-symbolic.svg
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?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"
|
||||
width="22"
|
||||
height="16"
|
||||
enable-background="new"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="battery-level-90-symbolic.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata
|
||||
id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2160"
|
||||
inkscape:window-height="1277"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="45.9375"
|
||||
inkscape:cx="11"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12"
|
||||
inkscape:document-rotation="0" />
|
||||
<title
|
||||
id="title2">Paper Symbolic Icon Theme</title>
|
||||
<rect
|
||||
x="3"
|
||||
y="5"
|
||||
width="11"
|
||||
height="6"
|
||||
rx="0.57595998"
|
||||
ry="0.54584002"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;stroke-width:1.04881;paint-order:stroke fill markers"
|
||||
id="rect4" />
|
||||
<path
|
||||
d="M 3,3 C 1.892,3 1,3.892 1,5 v 6 c 0,1.108 0.892,2 2,2 h 13 c 1.108,0 2,-0.892 2,-2 V 5 C 18,3.892 17.108,3 16,3 Z m 0,1 h 13 c 0.554,0 1,0.446 1,1 v 6 c 0,0.554 -0.446,1 -1,1 H 3 C 2.446,12 2,11.554 2,11 V 5 C 2,4.446 2.446,4 3,4 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path6" />
|
||||
<path
|
||||
d="m 19,6 v 4 A 2,2 0 0 0 21,8 2,2 0 0 0 19,6 Z"
|
||||
enable-background="new"
|
||||
style="fill:#FFFFFF;fill-rule:evenodd;paint-order:stroke fill markers"
|
||||
id="path8" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
16
svg/dark/brightness.svg
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?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" width="16" height="16" version="1.1" id="svg8" sodipodi:docname="display-brightness-low-symbolic.svg" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata id="metadata14">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs12" />
|
||||
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="2062" inkscape:window-height="1410" id="namedview10" showgrid="false" inkscape:zoom="45.9375" inkscape:cx="8" inkscape:cy="8" inkscape:window-x="98" inkscape:window-y="30" inkscape:window-maximized="1" inkscape:current-layer="svg8" />
|
||||
<g transform="translate(-613 191)" id="g4">
|
||||
<path d="M620.25-190a.25.25 0 0 0-.25.25v1.5c0 .139.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-1.5a.25.25 0 0 0-.25-.25zm-4.699 1.947a.25.25 0 0 0-.178.073l-.353.353a.25.25 0 0 0 0 .354l1.06 1.06a.25.25 0 0 0 .354 0l.353-.353a.25.25 0 0 0 0-.354l-1.06-1.06a.246.246 0 0 0-.176-.073zm9.898 0a.246.246 0 0 0-.175.073l-1.06 1.06a.25.25 0 0 0 0 .354l.353.353a.25.25 0 0 0 .353 0l1.06-1.06a.25.25 0 0 0 0-.354l-.353-.353a.25.25 0 0 0-.178-.073zM620.5-186a3.5 3.5 0 0 0-3.5 3.5 3.5 3.5 0 0 0 3.5 3.5 3.5 3.5 0 0 0 3.5-3.5 3.5 3.5 0 0 0-3.5-3.5zm0 1a2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5 2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5zm-7.25 2a.25.25 0 0 0-.25.25v.5c0 .139.112.25.25.25h1.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25zm13 0a.25.25 0 0 0-.25.25v.5c0 .139.112.25.25.25h1.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25zm-9.992 4.139a.252.252 0 0 0-.178.074l-1.06 1.06a.25.25 0 0 0 0 .354l.353.353a.25.25 0 0 0 .354 0l1.06-1.06a.25.25 0 0 0 0-.354l-.353-.353a.248.248 0 0 0-.176-.074zm8.484 0a.248.248 0 0 0-.175.074l-.354.353a.25.25 0 0 0 0 .354l1.06 1.06a.25.25 0 0 0 .354 0l.354-.353a.25.25 0 0 0 0-.354l-1.06-1.06a.252.252 0 0 0-.179-.074zM620.25-177a.25.25 0 0 0-.25.25v1.5c0 .139.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-1.5a.25.25 0 0 0-.25-.25z" fill="#EFEFEF" overflow="visible" style="isolation:auto;mix-blend-mode:normal" id="path2" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
23
svg/dark/close_normal.svg
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?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" sodipodi:docname="close_normal.svg" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" id="svg8" version="1.1" viewBox="0 0 7.9374997 7.9375002" height="30" width="30">
|
||||
<defs id="defs2" />
|
||||
<sodipodi:namedview inkscape:document-rotation="0" inkscape:pagecheckerboard="false" inkscape:window-maximized="0" inkscape:window-y="685" inkscape:window-x="1182" inkscape:window-height="981" inkscape:window-width="1436" units="px" showgrid="false" inkscape:current-layer="layer1" inkscape:document-units="mm" inkscape:cy="13.467799" inkscape:cx="-28.794643" inkscape:zoom="11.2" inkscape:pageshadow="2" inkscape:pageopacity="0.0" borderopacity="1.0" bordercolor="#666666" pagecolor="#ffffff" id="base">
|
||||
<inkscape:grid id="grid2560" type="xygrid" />
|
||||
</sodipodi:namedview>
|
||||
<metadata id="metadata5">
|
||||
<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:license rdf:resource="" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(0,-289.06248)" id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1">
|
||||
<g transform="matrix(0.26458333,0,0,0.26458333,11.895874,2.9564196)" inkscape:label="#g3842" id="4" />
|
||||
<g transform="matrix(0.26458333,0,0,0.26458333,8.2578527,2.6020669)" inkscape:label="#g3842" id="4-7" />
|
||||
<rect style="opacity:0;fill:black;fill-opacity:1;stroke:none;stroke-width:0.184334;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" id="rect1569-36" width="6.2093525" height="6.2267418" x="0.86407435" y="289.91785" ry="6.5889685e-06" />
|
||||
<polygon style="fill:white;fill-opacity:1;stroke:none" transform="matrix(0.62254902,0,0,0.62254902,-8.6378677,280.42461)" points="20.25,20.958 17.063,24.146 16.708,24.5 16,23.792 16.354,23.438 19.542,20.25 16.354,17.063 16,16.708 16.708,16 17.063,16.354 20.25,19.542 23.438,16.354 23.792,16 24.5,16.708 24.146,17.063 20.958,20.25 24.146,23.438 24.5,23.792 23.792,24.5 23.438,24.146 " id="polygon2562" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
17
svg/dark/control.svg
Normal file
|
@ -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:#FFFFFF;
|
||||
}
|
||||
.ColorScheme-Highlight {
|
||||
color:#3daee9;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
d="M18.5 6A3.5 3.5 0 0 0 15.04102 9H4V10H15.04A3.5 3.5 0 0 0 18.5 13 3.5 3.5 0 0 0 21.958984 10H28V9H21.961A3.5 3.5 0 0 0 18.5 6M7.5 19A3.5 3.5 0 0 0 4 22.5 3.5 3.5 0 0 0 7.5 26 3.5 3.5 0 0 0 10.960938 23H28V22H10.959A3.5 3.5 0 0 0 7.5 19m0 1A2.5 2.5 0 0 1 10 22.5 2.5 2.5 0 0 1 7.5 25 2.5 2.5 0 0 1 5 22.5 2.5 2.5 0 0 1 7.5 20"
|
||||
class="ColorScheme-Text"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 728 B |
4
svg/dark/media-playback-pause-symbolic.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="4" y="3" width="2" height="10" rx="1" ry="1" fill="#FFFFFF" stroke-width="1.8257"/>
|
||||
<rect x="10" y="3" width="2" height="10" rx="1" ry="1" fill="#FFFFFF" stroke-width="1.8257"/>
|
||||
</svg>
|
After Width: | Height: | Size: 298 B |
3
svg/dark/media-playback-start-symbolic.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m5.8812 3.0087c-0.2513 0.031145-0.45989 0.14032-0.62812 0.32931-0.16823 0.18899-0.25308 0.41133-0.25308 0.66471v7.9948c0 0.25338 0.084865 0.47572 0.25308 0.66471 0.16823 0.18899 0.37685 0.29815 0.62812 0.32931 0.2513 0.03116 0.47935-0.0244 0.68911-0.1677l5.7994-3.9973c0.18484-0.12669 0.31359-0.29945 0.38418-0.5092 0.07063-0.21183 0.07063-0.42139 0-0.63118-0.07063-0.20976-0.19836-0.38045-0.38114-0.5092l-5.8025-4.0005c-0.20907-0.14538-0.4385-0.19955-0.68911-0.1677z" fill="#FFFFFF" stroke-width="1.5611"/>
|
||||
</svg>
|
After Width: | Height: | Size: 627 B |
4
svg/dark/media-skip-backward-symbolic.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m13.119 3.0087c0.2513 0.031145 0.45989 0.14032 0.62812 0.32931s0.25308 0.41133 0.25308 0.66471v7.9948c0 0.25338-0.08487 0.47572-0.25308 0.66471-0.16823 0.18899-0.37685 0.29815-0.62812 0.32931-0.2513 0.03116-0.47935-0.0244-0.68911-0.1677l-5.7994-3.9973c-0.18484-0.12669-0.31359-0.29945-0.38418-0.5092-0.07063-0.21183-0.07063-0.42139 0-0.63118 0.07063-0.20976 0.19836-0.38045 0.38114-0.5092l5.8025-4.0005c0.20907-0.14538 0.4385-0.19955 0.68911-0.1677z" fill="#FFFFFF" stroke-width="1.5611"/>
|
||||
<rect x="2" y="3" width="2" height="10" rx="1" ry="1" fill="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4164"/>
|
||||
</svg>
|
After Width: | Height: | Size: 750 B |
4
svg/dark/media-skip-forward-symbolic.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m2.8812 3.0087c-0.2513 0.031145-0.45989 0.14032-0.62812 0.32931s-0.25308 0.41133-0.25308 0.66471v7.9948c0 0.25338 0.08487 0.47572 0.25308 0.66471 0.16823 0.18899 0.37685 0.29815 0.62812 0.32931 0.2513 0.03116 0.47935-0.0244 0.68911-0.1677l5.7994-3.9973c0.18484-0.12669 0.31359-0.29945 0.38418-0.5092 0.07063-0.21183 0.07063-0.42139 0-0.63118-0.07063-0.20976-0.19836-0.38045-0.38114-0.5092l-5.8025-4.0005c-0.20907-0.14538-0.4385-0.19955-0.68911-0.1677z" fill="#FFFFFF" stroke-width="1.5611"/>
|
||||
<rect transform="scale(-1,1)" x="-14" y="3" width="2" height="10" rx="1" ry="1" fill="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4164"/>
|
||||
</svg>
|
After Width: | Height: | Size: 778 B |
22
svg/dark/minimize_normal.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?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" sodipodi:docname="minimize_normal.svg" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" id="svg8" version="1.1" viewBox="0 0 7.9374997 7.9375002" height="30" width="30">
|
||||
<defs id="defs2" />
|
||||
<sodipodi:namedview inkscape:document-rotation="0" inkscape:pagecheckerboard="false" inkscape:window-maximized="1" inkscape:window-y="30" inkscape:window-x="96" inkscape:window-height="1375" inkscape:window-width="2064" units="px" showgrid="false" inkscape:current-layer="layer1" inkscape:document-units="mm" inkscape:cy="16.518502" inkscape:cx="-30.012016" inkscape:zoom="11.2" inkscape:pageshadow="2" inkscape:pageopacity="0.0" borderopacity="1.0" bordercolor="#666666" pagecolor="#ffffff" id="base">
|
||||
<inkscape:grid id="grid2560" type="xygrid" />
|
||||
</sodipodi:namedview>
|
||||
<metadata id="metadata5">
|
||||
<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:license rdf:resource="" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(0,-289.06248)" id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1">
|
||||
<g transform="matrix(0.26458333,0,0,0.26458333,11.895874,2.9564196)" inkscape:label="#g3842" id="4" />
|
||||
<g transform="matrix(0.26458333,0,0,0.26458333,5.9355757,3.5038878)" inkscape:label="#g3842" id="4-7" />
|
||||
<polygon fill="#ffffff" points="15.471,20 24.529,20 25,20 25,19 24.529,19 15.471,19 15,19 15,20 " id="polygon2" transform="matrix(0.52916667,0,0,0.52916667,-6.6145834,282.71248)" style="fill:#FFFFFF;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2 KiB |
4
svg/dark/network-wired-activated.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m4.667 7.5c-0.553 0-0.667 0.22414-0.667 0.5s0.114 0.5 0.667 0.5c0.035 0 0.07-0.0015 0.105-0.00375 0.026 7.496e-4 0.05 0.00375 0.077 0.00375h6.302c0.026 0 0.05-3e-3 0.074-0.00375 0.036 0.00225 0.072 0.00375 0.108 0.00375 0.553 0 0.667-0.22414 0.667-0.5s-0.114-0.5-0.667-0.5c-0.035 0-0.07 0.0015-0.105 0.00375-0.026-7.496e-4 -0.05-0.00375-0.077-0.00375h-6.301c-0.026 0-0.05 3e-3 -0.074 0.00375a1.49 1.1169 0 0 0-0.108-0.00375z" fill="#ffffff" stroke-width=".86581"/>
|
||||
<path d="m0.14153 8.3799 2.9889 3.4517c0.18936 0.21992 0.49832 0.22092 0.69067 3e-3a0.61592 0.61778 0 0 0 0.00199-0.79171l-2.6441-3.0539 2.665-3.0319a0.61692 0.61877 0 0 0 0.00199-0.79171 0.44649 0.44784 0 0 0-0.69067-3e-3l-3.0108 3.4278a0.59898 0.60078 0 0 0-0.14451 0.39486c0 0.14295 0.046842 0.2869 0.14152 0.39686zm15.717-0.75972-2.9889-3.4517a0.44649 0.44784 0 0 0-0.69067-3e-3 0.61592 0.61778 0 0 0-2e-3 0.79171l2.6441 3.0539-2.664 3.0319a0.61692 0.61877 0 0 0-2e-3 0.79171c0.18936 0.21992 0.49832 0.21992 0.69067 3e-3l3.0098-3.4268a0.59898 0.60078 0 0 0 0.14451-0.39486 0.59997 0.60178 0 0 0-0.14152-0.39686z" fill="#ffffff" stroke-width="1.4972"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
19
svg/dark/network-wired.svg
Normal file
|
@ -0,0 +1,19 @@
|
|||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(0 2)" fill="#dedede" stroke-width="1.5">
|
||||
<g transform="matrix(.43738 0 0 .5 -145.4 -266.68)">
|
||||
<g transform="matrix(0,-1.0825,-1.0825,0,1464.7,557.15)" fill="#dedede" stroke-width="1.5">
|
||||
<g transform="matrix(.00011827 .032712 -.032712 .00011827 18.269 1034.4)" fill="#dedede" stroke-width="1.5">
|
||||
<path d="m345.44 248.29-194.29 194.28c-12.359 12.365-32.397 12.365-44.75 0-12.354-12.354-12.354-32.391 0-44.744l171.91-171.91-171.91-171.9c-12.354-12.359-12.354-32.394 0-44.748 12.354-12.359 32.391-12.359 44.75 0l194.29 194.28c6.177 6.18 9.262 14.271 9.262 22.366 0 8.099-3.091 16.196-9.267 22.373z" fill="#dedede" stroke-width="1.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(-.43738 0 0 -.5 161.4 278.68)">
|
||||
<g transform="matrix(0,-1.0825,-1.0825,0,1464.7,557.15)" fill="#dedede" stroke-width="1.5">
|
||||
<g transform="matrix(.00011827 .032712 -.032712 .00011827 18.269 1034.4)" fill="#dedede" stroke-width="1.5">
|
||||
<path d="m345.44 248.29-194.29 194.28c-12.359 12.365-32.397 12.365-44.75 0-12.354-12.354-12.354-32.391 0-44.744l171.91-171.91-171.91-171.9c-12.354-12.359-12.354-32.394 0-44.748 12.354-12.359 32.391-12.359 44.75 0l194.29 194.28c6.177 6.18 9.262 14.271 9.262 22.366 0 8.099-3.091 16.196-9.267 22.373z" fill="#dedede" stroke-width="1.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path d="m5.5001 5.5001v1c0 0.276 0.1 0.538 0.281 0.719l0.781 0.781-0.78 0.781a1.015 1.015 0 0 0-0.282 0.719v1h1c0.276 0 0.538-0.1 0.719-0.281l0.781-0.781 0.781 0.78c0.181 0.182 0.443 0.282 0.719 0.282h1v-1c0-0.276-0.1-0.538-0.281-0.719l-0.782-0.781 0.782-0.781c0.18-0.181 0.281-0.443 0.281-0.719v-1h-1c-0.276 0-0.538 0.1-0.719 0.281l-0.781 0.781-0.781-0.78a1.015 1.015 0 0 0-0.719-0.282z" fill="#dedede"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
14
svg/dark/network-wireless-connected-00.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:0.5;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="m 7.9997737,2.5974132 c -3.0209991,0 -5.8744581,1.3332678 -7.82888544,3.6583298 -0.25960384,0.30878 -0.21870885,0.769328 0.0905674,1.028905 0.13683446,0.114927 0.30310611,0.170742 0.46916891,0.170742 0.2084413,0 0.41511123,-0.0879 0.55973643,-0.259824 1.6753731,-1.9933813 4.1208775,-3.1371963 6.7094127,-3.1371963 2.5885353,0 5.0340653,1.1442857 6.7094123,3.1371963 0.144651,0.171919 0.351269,0.259824 0.559737,0.259824 0.166089,0 0.333819,-0.05532 0.470654,-0.170742 0.308779,-0.259133 0.348685,-0.720622 0.08908,-1.028905 C 13.874728,3.930681 11.020773,2.5974132 7.9997737,2.5974132 Z m 0,3.0941398 c -2.1580059,0 -4.1956292,0.952804 -5.5914248,2.613092 -0.2595776,0.30878 -0.2201935,0.769328 0.089083,1.028906 0.1368345,0.114926 0.3030799,0.170742 0.4691689,0.170742 0.2084412,0 0.4155818,-0.08791 0.5597364,-0.259825 1.1167409,-1.329078 2.7478947,-2.091959 4.4734367,-2.091959 1.7255424,0 3.3561991,0.762881 4.4734371,2.091959 0.144651,0.172416 0.351791,0.259825 0.559736,0.259825 0.166088,0 0.332308,-0.05532 0.469168,-0.170742 0.309251,-0.259578 0.348634,-0.720597 0.08908,-1.028906 C 12.194877,6.644384 10.157776,5.691553 7.9997709,5.691553 Z m 0,3.214401 c -1.2954832,0 -2.5187558,0.570413 -3.3554487,1.566371 -0.2596039,0.308779 -0.2187089,0.769328 0.090567,1.028905 0.1368345,0.114926 0.30308,0.172226 0.4691689,0.172226 0.2084413,0 0.4155817,-0.08939 0.5597364,-0.261309 0.5586319,-0.6648 1.3734534,-1.045237 2.235976,-1.045237 0.8625228,0 1.6773704,0.380437 2.2359757,1.045237 0.144652,0.172416 0.351766,0.261309 0.559737,0.261309 0.166089,0 0.332334,-0.0568 0.469169,-0.172226 0.309276,-0.259604 0.350145,-0.720152 0.09057,-1.028905 C 10.518506,9.476367 9.2952333,8.905954 7.9997763,8.905954 Z m -0.062358,2.773442 C 7.3660438,11.733836 6.816513,12.161224 6.7971571,12.797384 6.7971571,13.461581 7.3355981,14 7.9997737,14 8.6639493,14 9.2023901,13.461581 9.2023901,12.797384 9.1007512,11.943462 8.5087874,11.624955 7.937416,11.679396 Z"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
14
svg/dark/network-wireless-connected-100.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="m 7.9997738,2.5974136 c -3.0209991,0 -5.8744581,1.3332678 -7.82888539,3.6583298 -0.25960384,0.30878 -0.21870885,0.769328 0.0905674,1.028905 0.13683446,0.114927 0.30310611,0.170742 0.46916891,0.170742 0.2084413,0 0.41511118,-0.0879 0.55973638,-0.259824 1.6753731,-1.9933813 4.1208775,-3.1371963 6.7094127,-3.1371963 2.5885352,0 5.0340652,1.1442857 6.7094122,3.1371963 0.144651,0.171919 0.351269,0.259824 0.559737,0.259824 0.166089,0 0.333819,-0.05532 0.470654,-0.170742 0.308779,-0.259133 0.348685,-0.720622 0.08908,-1.028905 C 13.874728,3.9306814 11.020773,2.5974136 7.9997738,2.5974136 Z m 0,3.0941398 c -2.1580059,0 -4.1956292,0.952804 -5.5914248,2.613092 -0.2595776,0.30878 -0.2201935,0.769328 0.089083,1.028906 0.1368345,0.114926 0.3030799,0.170742 0.4691689,0.170742 0.2084412,0 0.4155818,-0.08791 0.5597364,-0.259825 1.1167409,-1.329078 2.7478947,-2.091959 4.4734367,-2.091959 1.7255424,0 3.356199,0.762881 4.473437,2.091959 0.144651,0.172416 0.351791,0.259825 0.559736,0.259825 0.166088,0 0.332308,-0.05532 0.469168,-0.170742 0.309251,-0.259578 0.348634,-0.720597 0.08908,-1.028906 -1.396318,-1.660261 -3.433419,-2.613092 -5.591424,-2.613092 z m 0,3.214401 c -1.2954832,0 -2.5187558,0.570413 -3.3554487,1.5663706 -0.2596039,0.308779 -0.2187089,0.769328 0.090567,1.028905 0.1368345,0.114926 0.30308,0.172226 0.4691689,0.172226 0.2084413,0 0.4155817,-0.08939 0.5597364,-0.261309 0.5586319,-0.6648 1.3734534,-1.045237 2.235976,-1.045237 0.8625228,0 1.6773704,0.380437 2.2359756,1.045237 0.144652,0.172416 0.351766,0.261309 0.559737,0.261309 0.166089,0 0.332334,-0.0568 0.469169,-0.172226 0.309276,-0.259604 0.350145,-0.720152 0.09057,-1.028905 C 10.518506,9.4763674 9.2952334,8.9059544 7.9997764,8.9059544 Z M 7.9374158,11.679396 C 7.3660439,11.733836 6.8165131,12.161224 6.7971572,12.797384 6.7971572,13.461581 7.3355982,14 7.9997738,14 8.6639494,14 9.2023902,13.461581 9.2023902,12.797384 9.1007513,11.943462 8.5087875,11.624955 7.9374161,11.679396 Z"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
19
svg/dark/network-wireless-connected-25.svg
Normal file
|
@ -0,0 +1,19 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="M 7.937416,11.679396 C 7.3660438,11.733836 6.816513,12.161224 6.7971571,12.797384 6.7971571,13.461581 7.3355981,14 7.9997737,14 8.6639493,14 9.2023901,13.461581 9.2023901,12.797384 9.1007512,11.943462 8.5087874,11.624955 7.937416,11.679396 Z"
|
||||
/>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:0.5;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="m 7.9997737,2.5974132 c -3.0209991,0 -5.8744581,1.3332678 -7.82888544,3.6583298 -0.25960384,0.30878 -0.21870885,0.769328 0.0905674,1.028905 0.13683446,0.114927 0.30310611,0.170742 0.46916891,0.170742 0.2084413,0 0.41511123,-0.0879 0.55973643,-0.259824 1.6753731,-1.9933813 4.1208775,-3.1371963 6.7094127,-3.1371963 2.5885353,0 5.0340653,1.1442857 6.7094123,3.1371963 0.144651,0.171919 0.351269,0.259824 0.559737,0.259824 0.166089,0 0.333819,-0.05532 0.470654,-0.170742 0.308779,-0.259133 0.348685,-0.720622 0.08908,-1.028905 C 13.874728,3.930681 11.020773,2.5974132 7.9997737,2.5974132 Z m 0,3.0941398 c -2.1580059,0 -4.1956292,0.952804 -5.5914248,2.613092 -0.2595776,0.30878 -0.2201935,0.769328 0.089083,1.028906 0.1368345,0.114926 0.3030799,0.170742 0.4691689,0.170742 0.2084412,0 0.4155818,-0.08791 0.5597364,-0.259825 1.1167409,-1.329078 2.7478947,-2.091959 4.4734367,-2.091959 1.7255424,0 3.3561991,0.762881 4.4734371,2.091959 0.144651,0.172416 0.351791,0.259825 0.559736,0.259825 0.166088,0 0.332308,-0.05532 0.469168,-0.170742 0.309251,-0.259578 0.348634,-0.720597 0.08908,-1.028906 C 12.194877,6.644384 10.157776,5.691553 7.9997709,5.691553 Z m 0,3.214401 c -1.2954832,0 -2.5187558,0.570413 -3.3554487,1.566371 -0.2596039,0.308779 -0.2187089,0.769328 0.090567,1.028905 0.1368345,0.114926 0.30308,0.172226 0.4691689,0.172226 0.2084413,0 0.4155817,-0.08939 0.5597364,-0.261309 0.5586319,-0.6648 1.3734534,-1.045237 2.235976,-1.045237 0.8625228,0 1.6773704,0.380437 2.2359757,1.045237 0.144652,0.172416 0.351766,0.261309 0.559737,0.261309 0.166089,0 0.332334,-0.0568 0.469169,-0.172226 0.309276,-0.259604 0.350145,-0.720152 0.09057,-1.028905 C 10.518506,9.476367 9.2952333,8.905954 7.9997763,8.905954 Z"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
19
svg/dark/network-wireless-connected-50.svg
Normal file
|
@ -0,0 +1,19 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="m 7.9997736,8.9059536 c -1.2954831,0 -2.5187557,0.5704129 -3.3554486,1.5663714 -0.2596038,0.308779 -0.2187088,0.769328 0.090567,1.028905 0.1368345,0.114926 0.30308,0.172226 0.4691689,0.172226 0.2084413,0 0.4155817,-0.08939 0.5597364,-0.261309 0.5586319,-0.6648 1.3734534,-1.045237 2.2359759,-1.045237 0.8625229,0 1.67737,0.380437 2.2359754,1.045237 0.144652,0.172416 0.351766,0.261309 0.559737,0.261309 0.166089,0 0.332334,-0.0568 0.469169,-0.172226 0.309276,-0.259604 0.350145,-0.720152 0.09057,-1.028905 C 10.518503,9.4763665 9.2952306,8.9059536 7.9997736,8.9059536 Z M 7.9374167,11.679396 C 7.3660445,11.733839 6.8165138,12.161224 6.7971579,12.797384 6.7971579,13.461581 7.3355989,14 7.9997744,14 8.66395,14 9.2023908,13.461581 9.2023908,12.797384 9.1007519,11.943462 8.5087881,11.624955 7.9374167,11.679396 Z"
|
||||
/>
|
||||
<path
|
||||
style="fill:currentColor;fill-opacity:0.5;stroke:none"
|
||||
class="ColorScheme-Text"
|
||||
d="m 7.9997736,2.5974132 c -3.020999,0 -5.874458,1.3332678 -7.82888534,3.6583299 -0.25960384,0.3087796 -0.21870885,0.7693276 0.0905674,1.0289053 0.13683447,0.1149264 0.30310615,0.1707419 0.46916894,0.1707419 0.20844128,0 0.41511119,-0.087906 0.55973639,-0.2598246 1.6753731,-1.993381 4.1208775,-3.1371961 6.7094126,-3.1371961 2.5885354,0 5.0340654,1.1442857 6.7094124,3.1371961 0.144651,0.1719189 0.351269,0.2598246 0.559737,0.2598246 0.166089,0 0.333819,-0.055319 0.470654,-0.1707419 C 16.048356,7.0255152 16.088262,6.564026 15.828659,6.2557431 13.874728,3.930681 11.020773,2.5974132 7.9997736,2.5974132 Z m 0,3.0941394 c -2.1580058,0 -4.1956291,0.9528048 -5.5914247,2.6130925 -0.2595776,0.3087797 -0.2201935,0.7693279 0.089083,1.0289055 0.1368345,0.1149267 0.30308,0.1707424 0.4691689,0.1707424 0.2084413,0 0.4155818,-0.087906 0.5597364,-0.2598247 1.1167409,-1.3290779 2.7478947,-2.0919592 4.4734366,-2.0919592 1.7255421,0 3.3561994,0.7628813 4.4734374,2.0919592 0.144651,0.1724155 0.351791,0.2598247 0.559736,0.2598247 0.166088,0 0.332308,-0.055318 0.469168,-0.1707424 C 13.811366,9.073973 13.85075,8.6129543 13.591199,8.3046451 12.19488,6.6443835 10.157779,5.6915526 7.9997736,5.6915526 Z"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |