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 |