Import kdecoration_6.2.5.orig.tar.xz
authorAurélien COUDERC <coucouf@debian.org>
Sun, 5 Jan 2025 09:56:21 +0000 (10:56 +0100)
committerAurélien COUDERC <coucouf@debian.org>
Sun, 5 Jan 2025 09:56:21 +0000 (10:56 +0100)
[dgit import orig kdecoration_6.2.5.orig.tar.xz]

102 files changed:
.git-blame-ignore-revs [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.gitlab-ci.yml [new file with mode: 0644]
.kde-ci.yml [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
KDecoration2Config.cmake.in [new file with mode: 0644]
LICENSES/CC0-1.0.txt [new file with mode: 0644]
LICENSES/LGPL-2.1-only.txt [new file with mode: 0644]
LICENSES/LGPL-3.0-only.txt [new file with mode: 0644]
LICENSES/LicenseRef-KDE-Accepted-LGPL.txt [new file with mode: 0644]
README.md [new file with mode: 0644]
autotests/CMakeLists.txt [new file with mode: 0644]
autotests/decorationbuttontest.cpp [new file with mode: 0644]
autotests/decorationtest.cpp [new file with mode: 0644]
autotests/mockbridge.cpp [new file with mode: 0644]
autotests/mockbridge.h [new file with mode: 0644]
autotests/mockbutton.cpp [new file with mode: 0644]
autotests/mockbutton.h [new file with mode: 0644]
autotests/mockclient.cpp [new file with mode: 0644]
autotests/mockclient.h [new file with mode: 0644]
autotests/mockdecoration.cpp [new file with mode: 0644]
autotests/mockdecoration.h [new file with mode: 0644]
autotests/mocksettings.cpp [new file with mode: 0644]
autotests/mocksettings.h [new file with mode: 0644]
autotests/shadowtest.cpp [new file with mode: 0644]
metainfo.yaml [new file with mode: 0644]
po/ar/kdecoration.po [new file with mode: 0644]
po/ast/kdecoration.po [new file with mode: 0644]
po/az/kdecoration.po [new file with mode: 0644]
po/bg/kdecoration.po [new file with mode: 0644]
po/ca/kdecoration.po [new file with mode: 0644]
po/ca@valencia/kdecoration.po [new file with mode: 0644]
po/cs/kdecoration.po [new file with mode: 0644]
po/da/kdecoration.po [new file with mode: 0644]
po/de/kdecoration.po [new file with mode: 0644]
po/el/kdecoration.po [new file with mode: 0644]
po/en_GB/kdecoration.po [new file with mode: 0644]
po/eo/kdecoration.po [new file with mode: 0644]
po/es/kdecoration.po [new file with mode: 0644]
po/et/kdecoration.po [new file with mode: 0644]
po/eu/kdecoration.po [new file with mode: 0644]
po/fi/kdecoration.po [new file with mode: 0644]
po/fr/kdecoration.po [new file with mode: 0644]
po/gl/kdecoration.po [new file with mode: 0644]
po/he/kdecoration.po [new file with mode: 0644]
po/hi/kdecoration.po [new file with mode: 0644]
po/hu/kdecoration.po [new file with mode: 0644]
po/ia/kdecoration.po [new file with mode: 0644]
po/id/kdecoration.po [new file with mode: 0644]
po/is/kdecoration.po [new file with mode: 0644]
po/it/kdecoration.po [new file with mode: 0644]
po/ja/kdecoration.po [new file with mode: 0644]
po/ka/kdecoration.po [new file with mode: 0644]
po/ko/kdecoration.po [new file with mode: 0644]
po/lt/kdecoration.po [new file with mode: 0644]
po/lv/kdecoration.po [new file with mode: 0644]
po/ml/kdecoration.po [new file with mode: 0644]
po/nl/kdecoration.po [new file with mode: 0644]
po/nn/kdecoration.po [new file with mode: 0644]
po/pa/kdecoration.po [new file with mode: 0644]
po/pl/kdecoration.po [new file with mode: 0644]
po/pt/kdecoration.po [new file with mode: 0644]
po/pt_BR/kdecoration.po [new file with mode: 0644]
po/ro/kdecoration.po [new file with mode: 0644]
po/ru/kdecoration.po [new file with mode: 0644]
po/sa/kdecoration.po [new file with mode: 0644]
po/sk/kdecoration.po [new file with mode: 0644]
po/sl/kdecoration.po [new file with mode: 0644]
po/sv/kdecoration.po [new file with mode: 0644]
po/ta/kdecoration.po [new file with mode: 0644]
po/tr/kdecoration.po [new file with mode: 0644]
po/uk/kdecoration.po [new file with mode: 0644]
po/zh_CN/kdecoration.po [new file with mode: 0644]
po/zh_TW/kdecoration.po [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/Messages.sh [new file with mode: 0644]
src/decoratedclient.cpp [new file with mode: 0644]
src/decoratedclient.h [new file with mode: 0644]
src/decoration.cpp [new file with mode: 0644]
src/decoration.h [new file with mode: 0644]
src/decoration_p.h [new file with mode: 0644]
src/decorationbutton.cpp [new file with mode: 0644]
src/decorationbutton.h [new file with mode: 0644]
src/decorationbutton_p.h [new file with mode: 0644]
src/decorationbuttongroup.cpp [new file with mode: 0644]
src/decorationbuttongroup.h [new file with mode: 0644]
src/decorationbuttongroup_p.h [new file with mode: 0644]
src/decorationdefines.h [new file with mode: 0644]
src/decorationsettings.cpp [new file with mode: 0644]
src/decorationsettings.h [new file with mode: 0644]
src/decorationshadow.cpp [new file with mode: 0644]
src/decorationshadow.h [new file with mode: 0644]
src/decorationshadow_p.h [new file with mode: 0644]
src/decorationthemeprovider.cpp [new file with mode: 0644]
src/decorationthemeprovider.h [new file with mode: 0644]
src/private/CMakeLists.txt [new file with mode: 0644]
src/private/decoratedclientprivate.cpp [new file with mode: 0644]
src/private/decoratedclientprivate.h [new file with mode: 0644]
src/private/decorationbridge.cpp [new file with mode: 0644]
src/private/decorationbridge.h [new file with mode: 0644]
src/private/decorationsettingsprivate.cpp [new file with mode: 0644]
src/private/decorationsettingsprivate.h [new file with mode: 0644]

diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644 (file)
index 0000000..566bc68
--- /dev/null
@@ -0,0 +1,2 @@
+# clang-format
+2a523449997260eb1d4585a673f81477c47b9979
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5a6a58e
--- /dev/null
@@ -0,0 +1,7 @@
+.clang-format
+/compile_commands.json
+.clangd
+.idea
+/cmake-build*
+.cache
+/build*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..f6e2f69
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-FileCopyrightText: None
+# SPDX-License-Identifier: CC0-1.0
+
+include:
+  - project: sysadmin/ci-utilities
+    file:
+      - /gitlab-templates/linux-qt6.yml
+      - /gitlab-templates/freebsd-qt6.yml
diff --git a/.kde-ci.yml b/.kde-ci.yml
new file mode 100644 (file)
index 0000000..915f993
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: None
+# SPDX-License-Identifier: CC0-1.0
+
+Dependencies:
+- 'on': ['@all']
+  'require':
+    'frameworks/extra-cmake-modules': '@latest-kf6'
+    'frameworks/ki18n': '@latest-kf6'
+Options:
+  require-passing-tests-on: [ 'Linux', 'FreeBSD']
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..87c567b
--- /dev/null
@@ -0,0 +1,93 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(decoration-api)
+set(PROJECT_VERSION "6.2.5")
+set(PROJECT_VERSION_MAJOR 6)
+
+set(QT_MIN_VERSION "6.7.0")
+set(KF6_MIN_VERSION "6.5.0")
+set(KDE_COMPILERSETTINGS_LEVEL "5.82")
+
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
+# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} )
+
+include(KDEInstallDirs)
+include(KDECompilerSettings NO_POLICY_SCOPE)
+include(KDECMakeSettings)
+include(ECMSetupVersion)
+include(ECMGenerateHeaders)
+include(ECMGenerateExportHeader)
+include(FeatureSummary)
+include(GenerateExportHeader)
+include(CMakePackageConfigHelpers)
+include(KDEClangFormat)
+include(KDEGitCommitHooks)
+include(ECMDeprecationSettings)
+
+ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX KDECORATION2
+                        VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kdecoration2_version.h"
+                        PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KDecoration2ConfigVersion.cmake"
+                        SOVERSION ${PROJECT_VERSION_MAJOR})
+
+#dependencies
+find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
+    Core
+    Gui
+    Test
+)
+
+# require at least gcc 4.8
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    if ("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.8")
+        message(SEND_ERROR "Version ${CMAKE_CXX_COMPILER_VERSION} of the ${CMAKE_CXX_COMPILER_ID} C++ compiler is not supported. Please use version 4.8 or later.")
+    endif()
+endif()
+
+set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
+
+set(KDECORATION2_INCLUDEDIR "${KDE_INSTALL_INCLUDEDIR}/KDecoration2")
+find_package(KF6I18n ${KF6_MIN_VERSION} CONFIG REQUIRED)
+
+ecm_set_disabled_deprecation_versions(QT 5.15.2
+    KF 5.240.0
+    )
+
+add_definitions(-DQT_NO_KEYWORDS)
+
+# Subdirectories
+add_subdirectory(src)
+if(BUILD_TESTING)
+   add_subdirectory(autotests)
+endif()
+
+# add clang-format target for all our real source files
+file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h)
+kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
+kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)
+
+# create a Config.cmake and a ConfigVersion.cmake file and install them
+set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KDecoration2")
+
+configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KDecoration2Config.cmake.in"
+                                  "${CMAKE_CURRENT_BINARY_DIR}/KDecoration2Config.cmake"
+                                  INSTALL_DESTINATION  ${CMAKECONFIG_INSTALL_DIR}
+                                  )
+
+install(FILES  "${CMAKE_CURRENT_BINARY_DIR}/KDecoration2Config.cmake"
+               "${CMAKE_CURRENT_BINARY_DIR}/KDecoration2ConfigVersion.cmake"
+        DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
+        COMPONENT Devel )
+
+install(EXPORT KDecoration2Targets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KDecoration2Targets.cmake NAMESPACE KDecoration2:: )
+
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kdecoration2_version.h
+        DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF} COMPONENT Devel )
+
+feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
+
+ki18n_install(po)
diff --git a/KDecoration2Config.cmake.in b/KDecoration2Config.cmake.in
new file mode 100644 (file)
index 0000000..5f624d5
--- /dev/null
@@ -0,0 +1,10 @@
+@PACKAGE_INIT@
+
+include(CMakeFindDependencyMacro)
+find_dependency(Qt6Gui @QT_MIN_VERSION@)
+
+set(KDECORATION_PLUGIN_DIR "org.kde.kdecoration2")
+set(KDECORATION_KCM_PLUGIN_DIR "org.kde.kdecoration2.kcm")
+
+include("${CMAKE_CURRENT_LIST_DIR}/KDecoration2Targets.cmake")
+
diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt
new file mode 100644 (file)
index 0000000..0e259d4
--- /dev/null
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
diff --git a/LICENSES/LGPL-2.1-only.txt b/LICENSES/LGPL-2.1-only.txt
new file mode 100644 (file)
index 0000000..130dffb
--- /dev/null
@@ -0,0 +1,467 @@
+GNU LESSER GENERAL PUBLIC LICENSE
+
+Version 2.1, February 1999
+
+Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts as the
+successor of the GNU Library Public License, version 2, hence the version
+number 2.1.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share
+and change it. By contrast, the GNU General Public Licenses are intended to
+guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.
+
+This license, the Lesser General Public License, applies to some specially
+designated software packages--typically libraries--of the Free Software Foundation
+and other authors who decide to use it. You can use it too, but we suggest
+you first think carefully about whether this license or the ordinary General
+Public License is the better strategy to use in any particular case, based
+on the explanations below.
+
+When we speak of free software, we are referring to freedom of use, not price.
+Our General Public Licenses are designed to make sure that you have the freedom
+to distribute copies of free software (and charge for this service if you
+wish); that you receive source code or can get it if you want it; that you
+can change the software and use pieces of it in new free programs; and that
+you are informed that you can do these things.
+
+To protect your rights, we need to make restrictions that forbid distributors
+to deny you these rights or to ask you to surrender these rights. These restrictions
+translate to certain responsibilities for you if you distribute copies of
+the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis or for
+a fee, you must give the recipients all the rights that we gave you. You must
+make sure that they, too, receive or can get the source code. If you link
+other code with the library, you must provide complete object files to the
+recipients, so that they can relink them with the library after making changes
+to the library and recompiling it. And you must show them these terms so they
+know their rights.
+
+We protect your rights with a two-step method: (1) we copyright the library,
+and (2) we offer you this license, which gives you legal permission to copy,
+distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that there is no
+warranty for the free library. Also, if the library is modified by someone
+else and passed on, the recipients should know that what they have is not
+the original version, so that the original author's reputation will not be
+affected by problems that might be introduced by others.
+
+Finally, software patents pose a constant threat to the existence of any free
+program. We wish to make sure that a company cannot effectively restrict the
+users of a free program by obtaining a restrictive license from a patent holder.
+Therefore, we insist that any patent license obtained for a version of the
+library must be consistent with the full freedom of use specified in this
+license.
+
+Most GNU software, including some libraries, is covered by the ordinary GNU
+General Public License. This license, the GNU Lesser General Public License,
+applies to certain designated libraries, and is quite different from the ordinary
+General Public License. We use this license for certain libraries in order
+to permit linking those libraries into non-free programs.
+
+When a program is linked with a library, whether statically or using a shared
+library, the combination of the two is legally speaking a combined work, a
+derivative of the original library. The ordinary General Public License therefore
+permits such linking only if the entire combination fits its criteria of freedom.
+The Lesser General Public License permits more lax criteria for linking other
+code with the library.
+
+We call this license the "Lesser" General Public License because it does Less
+to protect the user's freedom than the ordinary General Public License. It
+also provides other free software developers Less of an advantage over competing
+non-free programs. These disadvantages are the reason we use the ordinary
+General Public License for many libraries. However, the Lesser license provides
+advantages in certain special circumstances.
+
+For example, on rare occasions, there may be a special need to encourage the
+widest possible use of a certain library, so that it becomes a de-facto standard.
+To achieve this, non-free programs must be allowed to use the library. A more
+frequent case is that a free library does the same job as widely used non-free
+libraries. In this case, there is little to gain by limiting the free library
+to free software only, so we use the Lesser General Public License.
+
+In other cases, permission to use a particular library in non-free programs
+enables a greater number of people to use a large body of free software. For
+example, permission to use the GNU C Library in non-free programs enables
+many more people to use the whole GNU operating system, as well as its variant,
+the GNU/Linux operating system.
+
+Although the Lesser General Public License is Less protective of the users'
+freedom, it does ensure that the user of a program that is linked with the
+Library has the freedom and the wherewithal to run that program using a modified
+version of the Library.
+
+The precise terms and conditions for copying, distribution and modification
+follow. Pay close attention to the difference between a "work based on the
+library" and a "work that uses the library". The former contains code derived
+from the library, whereas the latter must be combined with the library in
+order to run.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library or other program
+which contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Lesser General
+Public License (also called "this License"). Each licensee is addressed as
+"you".
+
+A "library" means a collection of software functions and/or data prepared
+so as to be conveniently linked with application programs (which use some
+of those functions and data) to form executables.
+
+The "Library", below, refers to any such software library or work which has
+been distributed under these terms. A "work based on the Library" means either
+the Library or any derivative work under copyright law: that is to say, a
+work containing the Library or a portion of it, either verbatim or with modifications
+and/or translated straightforwardly into another language. (Hereinafter, translation
+is included without limitation in the term "modification".)
+
+"Source code" for a work means the preferred form of the work for making modifications
+to it. For a library, complete source code means all the source code for all
+modules it contains, plus any associated interface definition files, plus
+the scripts used to control compilation and installation of the library.
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running a program
+using the Library is not restricted, and output from such a program is covered
+only if its contents constitute a work based on the Library (independent of
+the use of the Library in a tool for writing it). Whether that is true depends
+on what the Library does and what the program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's complete source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and disclaimer
+of warranty; keep intact all the notices that refer to this License and to
+the absence of any warranty; and distribute a copy of this License along with
+the Library.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Library or any portion of it,
+thus forming a work based on the Library, and copy and distribute such modifications
+or work under the terms of Section 1 above, provided that you also meet all
+of these conditions:
+
+      a) The modified work must itself be a software library.
+
+b) You must cause the files modified to carry prominent notices stating that
+you changed the files and the date of any change.
+
+c) You must cause the whole of the work to be licensed at no charge to all
+third parties under the terms of this License.
+
+d) If a facility in the modified Library refers to a function or a table of
+data to be supplied by an application program that uses the facility, other
+than as an argument passed when the facility is invoked, then you must make
+a good faith effort to ensure that, in the event an application does not supply
+such function or table, the facility still operates, and performs whatever
+part of its purpose remains meaningful.
+
+(For example, a function in a library to compute square roots has a purpose
+that is entirely well-defined independent of the application. Therefore, Subsection
+2d requires that any application-supplied function or table used by this function
+must be optional: if the application does not supply it, the square root function
+must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Library, and can be reasonably
+considered independent and separate works in themselves, then this License,
+and its terms, do not apply to those sections when you distribute them as
+separate works. But when you distribute the same sections as part of a whole
+which is a work based on the Library, the distribution of the whole must be
+on the terms of this License, whose permissions for other licensees extend
+to the entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise
+the right to control the distribution of derivative or collective works based
+on the Library.
+
+In addition, mere aggregation of another work not based on the Library with
+the Library (or with a work based on the Library) on a volume of a storage
+or distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public License
+instead of this License to a given copy of the Library. To do this, you must
+alter all the notices that refer to this License, so that they refer to the
+ordinary GNU General Public License, version 2, instead of to this License.
+(If a newer version than version 2 of the ordinary GNU General Public License
+has appeared, then you can specify that version instead if you wish.) Do not
+make any other change in these notices.
+
+Once this change is made in a given copy, it is irreversible for that copy,
+so the ordinary GNU General Public License applies to all subsequent copies
+and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the Library
+into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative of
+it, under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you accompany it with the complete corresponding
+machine-readable source code, which must be distributed under the terms of
+Sections 1 and 2 above on a medium customarily used for software interchange.
+
+If distribution of object code is made by offering access to copy from a designated
+place, then offering equivalent access to copy the source code from the same
+place satisfies the requirement to distribute the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+5. A program that contains no derivative of any portion of the Library, but
+is designed to work with the Library by being compiled or linked with it,
+is called a "work that uses the Library". Such a work, in isolation, is not
+a derivative work of the Library, and therefore falls outside the scope of
+this License.
+
+However, linking a "work that uses the Library" with the Library creates an
+executable that is a derivative of the Library (because it contains portions
+of the Library), rather than a "work that uses the library". The executable
+is therefore covered by this License. Section 6 states terms for distribution
+of such executables.
+
+When a "work that uses the Library" uses material from a header file that
+is part of the Library, the object code for the work may be a derivative work
+of the Library even though the source code is not. Whether this is true is
+especially significant if the work can be linked without the Library, or if
+the work is itself a library. The threshold for this to be true is not precisely
+defined by law.
+
+If such an object file uses only numerical parameters, data structure layouts
+and accessors, and small macros and small inline functions (ten lines or less
+in length), then the use of the object file is unrestricted, regardless of
+whether it is legally a derivative work. (Executables containing this object
+code plus portions of the Library will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may distribute
+the object code for the work under the terms of Section 6. Any executables
+containing that work also fall under Section 6, whether or not they are linked
+directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link a "work
+that uses the Library" with the Library to produce a work containing portions
+of the Library, and distribute that work under terms of your choice, provided
+that the terms permit modification of the work for the customer's own use
+and reverse engineering for debugging such modifications.
+
+You must give prominent notice with each copy of the work that the Library
+is used in it and that the Library and its use are covered by this License.
+You must supply a copy of this License. If the work during execution displays
+copyright notices, you must include the copyright notice for the Library among
+them, as well as a reference directing the user to the copy of this License.
+Also, you must do one of these things:
+
+a) Accompany the work with the complete corresponding machine-readable source
+code for the Library including whatever changes were used in the work (which
+must be distributed under Sections 1 and 2 above); and, if the work is an
+executable linked with the Library, with the complete machine-readable "work
+that uses the Library", as object code and/or source code, so that the user
+can modify the Library and then relink to produce a modified executable containing
+the modified Library. (It is understood that the user who changes the contents
+of definitions files in the Library will not necessarily be able to recompile
+the application to use the modified definitions.)
+
+b) Use a suitable shared library mechanism for linking with the Library. A
+suitable mechanism is one that (1) uses at run time a copy of the library
+already present on the user's computer system, rather than copying library
+functions into the executable, and (2) will operate properly with a modified
+version of the library, if the user installs one, as long as the modified
+version is interface-compatible with the version that the work was made with.
+
+c) Accompany the work with a written offer, valid for at least three years,
+to give the same user the materials specified in Subsection 6a, above, for
+a charge no more than the cost of performing this distribution.
+
+d) If distribution of the work is made by offering access to copy from a designated
+place, offer equivalent access to copy the above specified materials from
+the same place.
+
+e) Verify that the user has already received a copy of these materials or
+that you have already sent this user a copy.
+
+For an executable, the required form of the "work that uses the Library" must
+include any data and utility programs needed for reproducing the executable
+from it. However, as a special exception, the materials to be distributed
+need not include anything that is normally distributed (in either source or
+binary form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component itself
+accompanies the executable.
+
+It may happen that this requirement contradicts the license restrictions of
+other proprietary libraries that do not normally accompany the operating system.
+Such a contradiction means you cannot use both them and the Library together
+in an executable that you distribute.
+
+7. You may place library facilities that are a work based on the Library side-by-side
+in a single library together with other library facilities not covered by
+this License, and distribute such a combined library, provided that the separate
+distribution of the work based on the Library and of the other library facilities
+is otherwise permitted, and provided that you do these two things:
+
+a) Accompany the combined library with a copy of the same work based on the
+Library, uncombined with any other library facilities. This must be distributed
+under the terms of the Sections above.
+
+b) Give prominent notice with the combined library of the fact that part of
+it is a work based on the Library, and explaining where to find the accompanying
+uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the Library
+except as expressly provided under this License. Any attempt otherwise to
+copy, modify, sublicense, link with, or distribute the Library is void, and
+will automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will not
+have their licenses terminated so long as such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Library or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the Library
+(or any work based on the Library), you indicate your acceptance of this License
+to do so, and all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the Library),
+the recipient automatically receives a license from the original licensor
+to copy, distribute, link with or modify the Library subject to these terms
+and conditions. You may not impose any further restrictions on the recipients'
+exercise of the rights granted herein. You are not responsible for enforcing
+compliance by third parties with this License.
+
+11. If, as a consequence of a court judgment or allegation of patent infringement
+or for any other reason (not limited to patent issues), conditions are imposed
+on you (whether by court order, agreement or otherwise) that contradict the
+conditions of this License, they do not excuse you from the conditions of
+this License. If you cannot distribute so as to satisfy simultaneously your
+obligations under this License and any other pertinent obligations, then as
+a consequence you may not distribute the Library at all. For example, if a
+patent license would not permit royalty-free redistribution of the Library
+by all those who receive copies directly or indirectly through you, then the
+only way you could satisfy both it and this License would be to refrain entirely
+from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents
+or other property right claims or to contest validity of any such claims;
+this section has the sole purpose of protecting the integrity of the free
+software distribution system which is implemented by public license practices.
+Many people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose
+that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in certain
+countries either by patents or by copyrighted interfaces, the original copyright
+holder who places the Library under this License may add an explicit geographical
+distribution limitation excluding those countries, so that distribution is
+permitted only in or among countries not thus excluded. In such case, this
+License incorporates the limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new versions of
+the Lesser 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 Library specifies
+a version number of this License which applies to it and "any later version",
+you have the option of following the terms and conditions either of that version
+or of any later version published by the Free Software Foundation. If the
+Library does not specify a license version number, you may choose any version
+ever published by the Free Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free programs
+whose distribution conditions are incompatible with these, write to the author
+to ask for permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make exceptions
+for this. Our decision will be guided by the two goals of preserving the free
+status of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+   NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY
+"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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
+THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH
+HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Libraries
+
+If you develop a new library, and you want it to be of the greatest possible
+use to the public, we recommend making it free software that everyone can
+redistribute and change. You can do so by permitting redistribution under
+these terms (or, alternatively, under the terms of the ordinary General Public
+License).
+
+To apply these terms, attach the following notices to the library. It is safest
+to attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the "copyright"
+line and a pointer to where the full notice is found.
+
+< one line to give the library's name and an idea of what it does. >
+
+Copyright (C) < year > < name of author >
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free
+Software Foundation; either version 2.1 of the License, or (at your option)
+any later version.
+
+This library is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this library; if not, write to the Free Software Foundation, Inc., 51
+Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information
+on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your school,
+if any, to sign a "copyright disclaimer" for the library, if necessary. Here
+is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in
+
+the library `Frob' (a library for tweaking knobs) written
+
+by James Random Hacker.
+
+< signature of Ty Coon > , 1 April 1990
+
+Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/LICENSES/LGPL-3.0-only.txt b/LICENSES/LGPL-3.0-only.txt
new file mode 100644 (file)
index 0000000..bd405af
--- /dev/null
@@ -0,0 +1,163 @@
+GNU LESSER 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.
+
+This version of the GNU Lesser General Public License incorporates the terms
+and conditions of version 3 of the GNU General Public License, supplemented
+by the additional permissions listed below.
+
+   0. Additional Definitions.
+
+      
+
+As used herein, "this License" refers to version 3 of the GNU Lesser General
+Public License, and the "GNU GPL" refers to version 3 of the GNU General Public
+License.
+
+      
+
+"The Library" refers to a covered work governed by this License, other than
+an Application or a Combined Work as defined below.
+
+      
+
+An "Application" is any work that makes use of an interface provided by the
+Library, but which is not otherwise based on the Library. Defining a subclass
+of a class defined by the Library is deemed a mode of using an interface provided
+by the Library.
+
+      
+
+A "Combined Work" is a work produced by combining or linking an Application
+with the Library. The particular version of the Library with which the Combined
+Work was made is also called the "Linked Version".
+
+      
+
+The "Minimal Corresponding Source" for a Combined Work means the Corresponding
+Source for the Combined Work, excluding any source code for portions of the
+Combined Work that, considered in isolation, are based on the Application,
+and not on the Linked Version.
+
+      
+
+The "Corresponding Application Code" for a Combined Work means the object
+code and/or source code for the Application, including any data and utility
+programs needed for reproducing the Combined Work from the Application, but
+excluding the System Libraries of the Combined Work.
+
+   1. Exception to Section 3 of the GNU GPL.
+
+You may convey a covered work under sections 3 and 4 of this License without
+being bound by section 3 of the GNU GPL.
+
+   2. Conveying Modified Versions.
+
+If you modify a copy of the Library, and, in your modifications, a facility
+refers to a function or data to be supplied by an Application that uses the
+facility (other than as an argument passed when the facility is invoked),
+then you may convey a copy of the modified version:
+
+a) under this License, provided that you make a good faith effort to ensure
+that, in the event an Application does not supply the function or data, the
+facility still operates, and performs whatever part of its purpose remains
+meaningful, or
+
+b) under the GNU GPL, with none of the additional permissions of this License
+applicable to that copy.
+
+   3. Object Code Incorporating Material from Library Header Files.
+
+The object code form of an Application may incorporate material from a header
+file that is part of the Library. You may convey such object code under terms
+of your choice, provided that, if the incorporated material is not limited
+to numerical parameters, data structure layouts and accessors, or small macros,
+inline functions and templates (ten or fewer lines in length), you do both
+of the following:
+
+a) Give prominent notice with each copy of the object code that the Library
+is used in it and that the Library and its use are covered by this License.
+
+b) Accompany the object code with a copy of the GNU GPL and this license document.
+
+   4. Combined Works.
+
+You may convey a Combined Work under terms of your choice that, taken together,
+effectively do not restrict modification of the portions of the Library contained
+in the Combined Work and reverse engineering for debugging such modifications,
+if you also do each of the following:
+
+a) Give prominent notice with each copy of the Combined Work that the Library
+is used in it and that the Library and its use are covered by this License.
+
+b) Accompany the Combined Work with a copy of the GNU GPL and this license
+document.
+
+c) For a Combined Work that displays copyright notices during execution, include
+the copyright notice for the Library among these notices, as well as a reference
+directing the user to the copies of the GNU GPL and this license document.
+
+      d) Do one of the following:
+
+0) Convey the Minimal Corresponding Source under the terms of this License,
+and the Corresponding Application Code in a form suitable for, and under terms
+that permit, the user to recombine or relink the Application with a modified
+version of the Linked Version to produce a modified Combined Work, in the
+manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
+
+1) Use a suitable shared library mechanism for linking with the Library. A
+suitable mechanism is one that (a) uses at run time a copy of the Library
+already present on the user's computer system, and (b) will operate properly
+with a modified version of the Library that is interface-compatible with the
+Linked Version.
+
+e) Provide Installation Information, but only if you would otherwise be required
+to provide such information under section 6 of the GNU GPL, and only to the
+extent that such information is necessary to install and execute a modified
+version of the Combined Work produced by recombining or relinking the Application
+with a modified version of the Linked Version. (If you use option 4d0, the
+Installation Information must accompany the Minimal Corresponding Source and
+Corresponding Application Code. If you use option 4d1, you must provide the
+Installation Information in the manner specified by section 6 of the GNU GPL
+for conveying Corresponding Source.)
+
+   5. Combined Libraries.
+
+You may place library facilities that are a work based on the Library side
+by side in a single library together with other library facilities that are
+not Applications and are not covered by this License, and convey such a combined
+library under terms of your choice, if you do both of the following:
+
+a) Accompany the combined library with a copy of the same work based on the
+Library, uncombined with any other library facilities, conveyed under the
+terms of this License.
+
+b) Give prominent notice with the combined library that part of it is a work
+based on the Library, and explaining where to find the accompanying uncombined
+form of the same work.
+
+   6. Revised Versions of the GNU Lesser General Public License.
+
+The Free Software Foundation may publish revised and/or new versions of the
+GNU Lesser 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 Library as you
+received it specifies that a certain numbered version of the GNU Lesser General
+Public License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that published version or of
+any later version published by the Free Software Foundation. If the Library
+as you received it does not specify a version number of the GNU Lesser General
+Public License, you may choose any version of the GNU Lesser General Public
+License ever published by the Free Software Foundation.
+
+If the Library as you received it specifies that a proxy can decide whether
+future versions of the GNU Lesser General Public License shall apply, that
+proxy's public statement of acceptance of any version is permanent authorization
+for you to choose that version for the Library.
diff --git a/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt b/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt
new file mode 100644 (file)
index 0000000..232b3c5
--- /dev/null
@@ -0,0 +1,12 @@
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 3 of the license or (at your option) any later version
+that is accepted by the membership of KDE e.V. (or its successor
+approved by the membership of KDE e.V.), which shall act as a
+proxy as defined in Section 6 of version 3 of the license.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..e30f344
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+# KDecoration2
+
+Plugin based library to create window decorations.
+
+## Introduction
+
+KDecoration2 is a library to create window decorations. These window decorations can be used by
+for example an X11 based window manager which re-parents a Client window to a window decoration
+frame.
+
+The library consists of two parts:
+* Decoration API for implementing a Decoration theme
+* Private API to implement the backend part (e.g. from Window Manager side)
+
+## Providing a Decoration
+
+To provide a custom decoration one needs to create a plugin and provide an own implementation
+of KDecoration2::Decoration. For a framework to load and find the plugin it needs to be compiled
+with the proper json metadata. An example for such metadata (deco.json):
+
+```json
+{
+    "KPlugin": {
+        "Id": "org.kde.myAweseomeDecoration",
+        "ServiceTypes": [
+            "org.kde.kdecoration2"
+        ]
+    },
+    "X-KDE-ConfigModule": "kcm_name", /* comes with a configuration module */
+    "org.kde.kdecoration2": {
+        "blur": false, /* blur behind not needed */
+    }
+}
+```
+
+To simplify one can use the KPluginFactory macro from the KCoreAddons framework:
+
+```cpp
+K_PLUGIN_FACTORY_WITH_JSON(
+    MyAwesomeDecorationFactory,
+    "deco.json",
+    registerPlugin<MyAwesomeDecoration::Decoration>();
+)
+```
+
+The plugin needs to get installed to `${KDE_INSTALL_PLUGINDIR}/org.kde.kdecoration2`.
+
+## Configuring the Decoration
+
+It is possible to provide a configuration module to tweak some aspects of the decoration. This is done
+by creating a plugin that provides such a configuration module.
+
+The `kcmoduleName` specifies the name of the configuration module. It needs to be installed under
+`${KDE_INSTALL_PLUGINDIR}/org.kde.kdecoration2.kcm` so that it can be looked up.
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f8e5e81
--- /dev/null
@@ -0,0 +1,35 @@
+include(ECMMarkAsTest)
+
+set(decorationButtonTest_SRCS
+    mockbridge.cpp mockbridge.h
+    mockbutton.cpp mockbutton.h
+    mockclient.cpp mockclient.h
+    mockdecoration.cpp mockdecoration.h
+    mocksettings.cpp mocksettings.h
+    decorationbuttontest.cpp
+    )
+add_executable(decorationButtonTest ${decorationButtonTest_SRCS})
+target_link_libraries(decorationButtonTest kdecorations2 kdecorations2private Qt::Test)
+add_test(NAME kdecoration2-decorationButtonTest COMMAND decorationButtonTest)
+ecm_mark_as_test(decorationButtonTest)
+
+set(decorationTest_SRCS
+    mockbridge.cpp mockbridge.h
+    mockbutton.cpp mockbutton.h
+    mockclient.cpp mockclient.h
+    mockdecoration.cpp mockdecoration.h
+    mocksettings.cpp mocksettings.h
+    decorationtest.cpp
+    )
+add_executable(decorationTest ${decorationTest_SRCS})
+target_link_libraries(decorationTest kdecorations2 kdecorations2private Qt::Test)
+add_test(NAME kdecoration2-decorationTest COMMAND decorationTest)
+ecm_mark_as_test(decorationTest)
+
+set(decorationShadowTest_SRCS
+    shadowtest.cpp
+    )
+add_executable(decorationShadowTest ${decorationShadowTest_SRCS})
+target_link_libraries(decorationShadowTest kdecorations2 Qt::Test)
+add_test(NAME kdecoration2-decorationShadowTest COMMAND decorationShadowTest)
+ecm_mark_as_test(decorationShadowTest)
diff --git a/autotests/decorationbuttontest.cpp b/autotests/decorationbuttontest.cpp
new file mode 100644 (file)
index 0000000..f5aa8e1
--- /dev/null
@@ -0,0 +1,1372 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "../src/decoratedclient.h"
+#include "../src/decorationsettings.h"
+#include "mockbridge.h"
+#include "mockbutton.h"
+#include "mockclient.h"
+#include "mockdecoration.h"
+#include "mocksettings.h"
+#include <QSignalSpy>
+#include <QStyleHints>
+#include <QTest>
+
+Q_DECLARE_METATYPE(Qt::MouseButton)
+
+class DecorationButtonTest : public QObject
+{
+    Q_OBJECT
+private Q_SLOTS:
+    void testButton();
+    void testChecked();
+    void testEnabled();
+    void testPressIgnore_data();
+    void testPressIgnore();
+    void testReleaseIgnore_data();
+    void testReleaseIgnore();
+    void testHoverEnterIgnore_data();
+    void testHoverEnterIgnore();
+    void testHoverLeaveIgnore_data();
+    void testHoverLeaveIgnore();
+    void testHover();
+    void testMouseMove_data();
+    void testMouseMove();
+    void testClose();
+    void testMinimize();
+    void testQuickHelp();
+    void testKeepAbove();
+    void testKeepBelow();
+    void testShade();
+    void testMaximize();
+    void testOnAllDesktops();
+    void testMenu();
+    void testMenuDoubleClick();
+    void testMenuPressAndHold();
+    void testApplicationMenu();
+    void testContains_data();
+    void testContains();
+};
+
+void DecorationButtonTest::testButton()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    QCOMPARE(button.decoration(), &mockDecoration);
+    const MockButton &constRef(button);
+    QCOMPARE(constRef.decoration(), &mockDecoration);
+    QCOMPARE(button.type(), KDecoration2::DecorationButtonType::Custom);
+    QCOMPARE(button.acceptedButtons(), Qt::MouseButtons(Qt::LeftButton));
+    QCOMPARE(button.isCheckable(), false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isHovered(), false);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.size(), QSizeF(0, 0));
+    QCOMPARE(button.geometry(), QRectF());
+
+    // test setting the geometry
+    QSignalSpy geometryChangedSpy(&button, &KDecoration2::DecorationButton::geometryChanged);
+    QVERIFY(geometryChangedSpy.isValid());
+    // setting to default geometry shouldn't change
+    button.setGeometry(QRectF());
+    QCOMPARE(button.geometry(), QRectF());
+    QCOMPARE(geometryChangedSpy.count(), 0);
+    // setting to a proper geometry should change
+    const QRectF testGeometry = QRectF(0, 0, 10, 20);
+    button.setGeometry(testGeometry);
+    QCOMPARE(button.geometry(), testGeometry);
+    QCOMPARE(button.size(), testGeometry.size());
+    QCOMPARE(geometryChangedSpy.count(), 1);
+    QCOMPARE(geometryChangedSpy.first().first().toRectF(), testGeometry);
+
+    // test changing visibility
+    QSignalSpy visibilityChangedSpy(&button, &KDecoration2::DecorationButton::visibilityChanged);
+    QVERIFY(visibilityChangedSpy.isValid());
+    button.setVisible(true);
+    QCOMPARE(visibilityChangedSpy.count(), 0);
+    button.setVisible(false);
+    QCOMPARE(button.isVisible(), false);
+    QCOMPARE(visibilityChangedSpy.count(), 1);
+    QCOMPARE(visibilityChangedSpy.first().first().toBool(), false);
+}
+
+void DecorationButtonTest::testChecked()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    // without being checkable it should not get checked
+    QSignalSpy checkedChangedSpy(&button, &KDecoration2::DecorationButton::checkedChanged);
+    QVERIFY(checkedChangedSpy.isValid());
+    button.setChecked(true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(checkedChangedSpy.count(), 0);
+
+    // now let's set the checkable state
+    QSignalSpy checkableChangedSpy(&button, &KDecoration2::DecorationButton::checkableChanged);
+    QVERIFY(checkableChangedSpy.isValid());
+    // setting to same should not emit
+    button.setCheckable(false);
+    QCOMPARE(checkableChangedSpy.count(), 0);
+    button.setCheckable(true);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(checkableChangedSpy.count(), 1);
+    QCOMPARE(checkableChangedSpy.first().first().toBool(), true);
+
+    // now it should be possible to check the button
+    button.setChecked(true);
+    QCOMPARE(button.isChecked(), true);
+    QCOMPARE(checkedChangedSpy.count(), 1);
+    // setting again should not change
+    button.setChecked(true);
+    QCOMPARE(button.isChecked(), true);
+    QCOMPARE(checkedChangedSpy.count(), 1);
+    // and disable
+    button.setChecked(false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(checkedChangedSpy.count(), 2);
+    QCOMPARE(checkedChangedSpy.first().first().toBool(), true);
+    QCOMPARE(checkedChangedSpy.last().first().toBool(), false);
+
+    // last but not least let's disable the checkable again, this should disable a checked button
+    button.setChecked(true);
+    QCOMPARE(button.isChecked(), true);
+    checkedChangedSpy.clear();
+    QCOMPARE(checkedChangedSpy.count(), 0);
+    button.setCheckable(false);
+    QCOMPARE(button.isCheckable(), false);
+    QCOMPARE(checkableChangedSpy.count(), 2);
+    QCOMPARE(checkableChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(checkedChangedSpy.count(), 1);
+}
+
+void DecorationButtonTest::testEnabled()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    // enabling has influence on whether the button accepts events, so we need to fake events
+    QSignalSpy enabledChangedSpy(&button, &KDecoration2::DecorationButton::enabledChanged);
+    QVERIFY(enabledChangedSpy.isValid());
+    // setting to same shouldn't change
+    button.setEnabled(true);
+    QCOMPARE(enabledChangedSpy.count(), 0);
+    button.setEnabled(false);
+    QCOMPARE(button.isEnabled(), false);
+    QCOMPARE(enabledChangedSpy.count(), 1);
+    QCOMPARE(enabledChangedSpy.first().first().toBool(), false);
+
+    // now let's send it a hover entered event
+    QSignalSpy hoveredChangedSpy(&button, &KDecoration2::DecorationButton::hoveredChanged);
+    QVERIFY(hoveredChangedSpy.isValid());
+    QHoverEvent event(QEvent::HoverEnter, QPointF(1, 1), QPointF(-1, -1));
+    event.setAccepted(false);
+    button.event(&event);
+    QCOMPARE(event.isAccepted(), false);
+    QCOMPARE(hoveredChangedSpy.count(), 0);
+
+    // if we enable the button again we should get a hovered changed signal
+    button.setEnabled(true);
+    QCOMPARE(enabledChangedSpy.count(), 2);
+    QCOMPARE(enabledChangedSpy.last().first().toBool(), true);
+    button.event(&event);
+    QCOMPARE(event.isAccepted(), true);
+    QCOMPARE(hoveredChangedSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.first().first().toBool(), true);
+
+    // if we disable the button now we get a hovered disabled signal
+    button.setEnabled(false);
+    QCOMPARE(hoveredChangedSpy.count(), 2);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testPressIgnore_data()
+{
+    QTest::addColumn<bool>("enabled");
+    QTest::addColumn<bool>("visible");
+    QTest::addColumn<QPoint>("clickPos");
+    QTest::addColumn<Qt::MouseButton>("mouseButton");
+    QTest::addColumn<bool>("expectedAccepted");
+
+    QTest::newRow("all-disabled") << false << false << QPoint(0, 0) << Qt::LeftButton << false;
+    QTest::newRow("enabled") << true << false << QPoint(0, 0) << Qt::LeftButton << false;
+    QTest::newRow("visible") << false << true << QPoint(0, 0) << Qt::LeftButton << false;
+    QTest::newRow("outside") << true << true << QPoint(20, 20) << Qt::LeftButton << false;
+    QTest::newRow("wrong-button") << true << true << QPoint(0, 0) << Qt::RightButton << false;
+}
+
+void DecorationButtonTest::testPressIgnore()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+    button.setAcceptedButtons(Qt::LeftButton);
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QFETCH(bool, enabled);
+    QFETCH(bool, visible);
+    button.setEnabled(enabled);
+    button.setVisible(visible);
+
+    QFETCH(QPoint, clickPos);
+    QFETCH(Qt::MouseButton, mouseButton);
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, clickPos, mouseButton, mouseButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QTEST(pressEvent.isAccepted(), "expectedAccepted");
+    QCOMPARE(button.isPressed(), false);
+    QVERIFY(pressedSpy.isEmpty());
+    QVERIFY(pressedChangedSpy.isEmpty());
+}
+
+void DecorationButtonTest::testReleaseIgnore_data()
+{
+    QTest::addColumn<bool>("enabled");
+    QTest::addColumn<bool>("visible");
+    QTest::addColumn<QPoint>("clickPos");
+    QTest::addColumn<Qt::MouseButton>("mouseButton");
+    QTest::addColumn<bool>("expectedAccepted");
+    QTest::addColumn<bool>("expectedPressed");
+    QTest::addColumn<int>("expectedPressedChanged");
+
+    QTest::newRow("all-disabled") << false << false << QPoint(0, 0) << Qt::LeftButton << false << false << 2;
+    QTest::newRow("enabled") << true << false << QPoint(0, 0) << Qt::LeftButton << false << false << 2;
+    QTest::newRow("visible") << false << true << QPoint(0, 0) << Qt::LeftButton << false << false << 2;
+    QTest::newRow("outside") << true << true << QPoint(20, 20) << Qt::LeftButton << true << false << 2;
+    QTest::newRow("wrong-button") << true << true << QPoint(0, 0) << Qt::RightButton << false << true << 1;
+}
+
+void DecorationButtonTest::testReleaseIgnore()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+    button.setAcceptedButtons(Qt::LeftButton);
+    button.setEnabled(true);
+    button.setVisible(true);
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(0, 0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), true);
+
+    QFETCH(bool, enabled);
+    QFETCH(bool, visible);
+    button.setEnabled(enabled);
+    button.setVisible(visible);
+
+    QFETCH(QPoint, clickPos);
+    QFETCH(Qt::MouseButton, mouseButton);
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, clickPos, mouseButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QTEST(releaseEvent.isAccepted(), "expectedAccepted");
+    QTEST(button.isPressed(), "expectedPressed");
+    QCOMPARE(pressedSpy.count(), 1);
+    QFETCH(int, expectedPressedChanged);
+    QCOMPARE(pressedChangedSpy.count(), expectedPressedChanged);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), button.isPressed());
+    QCOMPARE(clickedSpy.count(), 0);
+}
+
+void DecorationButtonTest::testHoverEnterIgnore_data()
+{
+    QTest::addColumn<bool>("enabled");
+    QTest::addColumn<bool>("visible");
+    QTest::addColumn<QPoint>("enterPos");
+
+    QTest::newRow("all-disabled") << false << false << QPoint(0, 0);
+    QTest::newRow("enabled") << true << false << QPoint(0, 0);
+    QTest::newRow("visible") << false << true << QPoint(0, 0);
+    QTest::newRow("outside") << true << true << QPoint(20, 20);
+}
+
+void DecorationButtonTest::testHoverEnterIgnore()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+    QSignalSpy pointerEnteredSpy(&button, &KDecoration2::DecorationButton::pointerEntered);
+    QVERIFY(pointerEnteredSpy.isValid());
+    QSignalSpy hoveredChangedSpy(&button, &KDecoration2::DecorationButton::hoveredChanged);
+    QVERIFY(hoveredChangedSpy.isValid());
+
+    QFETCH(bool, enabled);
+    QFETCH(bool, visible);
+    button.setEnabled(enabled);
+    button.setVisible(visible);
+
+    QFETCH(QPoint, enterPos);
+    QHoverEvent enterEvent(QEvent::HoverEnter, enterPos, QPoint());
+    enterEvent.setAccepted(false);
+    button.event(&enterEvent);
+    QCOMPARE(enterEvent.isAccepted(), false);
+    QCOMPARE(button.isHovered(), false);
+    QCOMPARE(pointerEnteredSpy.count(), 0);
+    QCOMPARE(hoveredChangedSpy.count(), 0);
+
+    // send a HoverLeft event should not be processed
+    button.setEnabled(true);
+    button.setVisible(true);
+    QHoverEvent leftEvent(QEvent::HoverLeave, QPoint(20, 20), enterPos);
+    leftEvent.setAccepted(false);
+    button.event(&leftEvent);
+    QCOMPARE(leftEvent.isAccepted(), false);
+}
+
+void DecorationButtonTest::testHoverLeaveIgnore_data()
+{
+    QTest::addColumn<bool>("enabled");
+    QTest::addColumn<bool>("visible");
+    QTest::addColumn<QPoint>("leavePos");
+    QTest::addColumn<int>("expectedLeaveCount");
+    QTest::addColumn<int>("expectedHoverChangedCount");
+
+    QTest::newRow("all-disabled") << false << false << QPoint(20, 20) << 1 << 2;
+    QTest::newRow("enabled") << true << false << QPoint(20, 20) << 1 << 2;
+    QTest::newRow("visible") << false << true << QPoint(20, 20) << 1 << 2;
+    QTest::newRow("inside") << true << true << QPoint(5, 5) << 0 << 1;
+}
+
+void DecorationButtonTest::testHoverLeaveIgnore()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+    button.setEnabled(true);
+    button.setVisible(true);
+    QSignalSpy pointerEnteredSpy(&button, &KDecoration2::DecorationButton::pointerEntered);
+    QVERIFY(pointerEnteredSpy.isValid());
+    QSignalSpy hoveredChangedSpy(&button, &KDecoration2::DecorationButton::hoveredChanged);
+    QVERIFY(hoveredChangedSpy.isValid());
+    QSignalSpy pointerLeavedSpy(&button, &KDecoration2::DecorationButton::pointerLeft);
+    QVERIFY(pointerLeavedSpy.isValid());
+
+    QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(0, 0), QPoint());
+    enterEvent.setAccepted(false);
+    button.event(&enterEvent);
+    QCOMPARE(enterEvent.isAccepted(), true);
+    QCOMPARE(button.isHovered(), true);
+    QCOMPARE(pointerEnteredSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), true);
+
+    QFETCH(bool, enabled);
+    QFETCH(bool, visible);
+    button.setEnabled(enabled);
+    button.setVisible(visible);
+
+    QFETCH(QPoint, leavePos);
+    QHoverEvent leftEvent(QEvent::HoverLeave, leavePos, QPoint(0, 0));
+    leftEvent.setAccepted(false);
+    button.event(&leftEvent);
+    QCOMPARE(leftEvent.isAccepted(), false);
+    QCOMPARE(pointerEnteredSpy.count(), 1);
+    QFETCH(int, expectedLeaveCount);
+    QFETCH(int, expectedHoverChangedCount);
+    QCOMPARE(pointerLeavedSpy.count(), expectedLeaveCount);
+    QCOMPARE(hoveredChangedSpy.count(), expectedHoverChangedCount);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), button.isHovered());
+}
+
+void DecorationButtonTest::testHover()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRectF(0, 0, 10, 10));
+    button.setEnabled(true);
+    button.setVisible(true);
+    QSignalSpy pointerEnteredSpy(&button, &KDecoration2::DecorationButton::pointerEntered);
+    QVERIFY(pointerEnteredSpy.isValid());
+    QSignalSpy hoveredChangedSpy(&button, &KDecoration2::DecorationButton::hoveredChanged);
+    QVERIFY(hoveredChangedSpy.isValid());
+    QSignalSpy pointerLeavedSpy(&button, &KDecoration2::DecorationButton::pointerLeft);
+    QVERIFY(pointerLeavedSpy.isValid());
+
+    QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(0, 0), QPoint());
+    enterEvent.setAccepted(false);
+    button.event(&enterEvent);
+    QCOMPARE(enterEvent.isAccepted(), true);
+    QCOMPARE(button.isHovered(), true);
+    QCOMPARE(pointerEnteredSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), true);
+
+    // send in a hovermove event - it's passed through, but not used
+    QHoverEvent moveEvent(QEvent::HoverMove, QPoint(5, 0), QPoint(0, 0));
+    moveEvent.setAccepted(false);
+    button.event(&moveEvent);
+    QCOMPARE(moveEvent.isAccepted(), false);
+
+    QHoverEvent leftEvent(QEvent::HoverLeave, QPointF(10.1, 0.0), QPointF(0, 0));
+    leftEvent.setAccepted(false);
+    button.event(&leftEvent);
+    QCOMPARE(leftEvent.isAccepted(), true);
+    QCOMPARE(pointerEnteredSpy.count(), 1);
+    QCOMPARE(pointerLeavedSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.count(), 2);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testMouseMove_data()
+{
+    QTest::addColumn<bool>("enabled");
+    QTest::addColumn<bool>("visible");
+    QTest::addColumn<QPointF>("movePos");
+    QTest::addColumn<bool>("expectedAccepted");
+    QTest::addColumn<bool>("expectedHovered");
+    QTest::addColumn<int>("expectedChangedCount");
+
+    QTest::newRow("outside") << true << true << QPointF(10.1, 10) << true << false << 2;
+    QTest::newRow("inside") << true << true << QPointF(5, 5) << false << true << 1;
+    QTest::newRow("disabled") << false << true << QPointF(10, 10) << false << false << 2;
+    QTest::newRow("invisible") << true << false << QPointF(10, 10) << false << false << 2;
+}
+
+void DecorationButtonTest::testMouseMove()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    // create a custom button and verify the base settings
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRectF(0, 0, 10, 10));
+    button.setEnabled(true);
+    button.setVisible(true);
+    QSignalSpy hoveredChangedSpy(&button, &KDecoration2::DecorationButton::hoveredChanged);
+    QVERIFY(hoveredChangedSpy.isValid());
+    QSignalSpy pointerLeavedSpy(&button, &KDecoration2::DecorationButton::pointerLeft);
+    QVERIFY(pointerLeavedSpy.isValid());
+
+    QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(0, 0), QPoint());
+    enterEvent.setAccepted(false);
+    button.event(&enterEvent);
+    QCOMPARE(enterEvent.isAccepted(), true);
+    QCOMPARE(button.isHovered(), true);
+    QCOMPARE(hoveredChangedSpy.count(), 1);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), true);
+
+    QFETCH(bool, enabled);
+    button.setEnabled(enabled);
+    QFETCH(bool, visible);
+    button.setVisible(visible);
+
+    QFETCH(QPointF, movePos);
+    QMouseEvent mouseMoveEvent(QEvent::MouseMove, movePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    mouseMoveEvent.setAccepted(false);
+    button.event(&mouseMoveEvent);
+    QTEST(mouseMoveEvent.isAccepted(), "expectedAccepted");
+    QTEST(button.isHovered(), "expectedHovered");
+    QFETCH(int, expectedChangedCount);
+    QCOMPARE(hoveredChangedSpy.count(), expectedChangedCount);
+    QCOMPARE(hoveredChangedSpy.last().first().toBool(), button.isHovered());
+
+    // explicit further move event outside of button
+    QMouseEvent mouseMoveEvent2(QEvent::MouseMove, QPoint(50, 50), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    mouseMoveEvent2.setAccepted(false);
+    button.event(&mouseMoveEvent2);
+    QTEST(mouseMoveEvent2.isAccepted(), "expectedHovered");
+    QCOMPARE(button.isHovered(), false);
+}
+
+void DecorationButtonTest::testClose()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Close, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), false);
+    QCOMPARE(button.isCheckable(), false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // if the client is closeable the button should get enabled
+    QSignalSpy closeableChangedSpy(mockDecoration.client(), &KDecoration2::DecoratedClient::closeableChanged);
+    QVERIFY(closeableChangedSpy.isValid());
+    client->setCloseable(true);
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(closeableChangedSpy.count(), 1);
+    QCOMPARE(closeableChangedSpy.first().first().toBool(), true);
+
+    // clicking the button should trigger a request for close
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy closeRequestedSpy(client, &MockClient::closeRequested);
+    QVERIFY(closeRequestedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(closeRequestedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(closeRequestedSpy.wait());
+    QCOMPARE(closeRequestedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testMinimize()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Minimize, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), false);
+    QCOMPARE(button.isCheckable(), false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // if the client is minimizeable the button should get enabled
+    QSignalSpy minimizableChangedSpy(mockDecoration.client(), &KDecoration2::DecoratedClient::minimizeableChanged);
+    QVERIFY(minimizableChangedSpy.isValid());
+    client->setMinimizable(true);
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(minimizableChangedSpy.count(), 1);
+    QCOMPARE(minimizableChangedSpy.first().first().toBool(), true);
+
+    // clicking the button should trigger a request for minimize
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy minimizeRequestedSpy(client, &MockClient::minimizeRequested);
+    QVERIFY(minimizeRequestedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(minimizeRequestedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(minimizeRequestedSpy.wait());
+    QCOMPARE(minimizeRequestedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testQuickHelp()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::ContextHelp, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isCheckable(), false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), false);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // if the client provides quickhelp the button should get enabled
+    QSignalSpy providesContextHelpChangedSpy(mockDecoration.client(), &KDecoration2::DecoratedClient::providesContextHelpChanged);
+    QVERIFY(providesContextHelpChangedSpy.isValid());
+    client->setProvidesContextHelp(true);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(providesContextHelpChangedSpy.count(), 1);
+    QCOMPARE(providesContextHelpChangedSpy.first().first().toBool(), true);
+
+    // clicking the button should trigger a request for minimize
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy quickhelpRequestedSpy(client, &MockClient::quickHelpRequested);
+    QVERIFY(quickhelpRequestedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(quickhelpRequestedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(quickhelpRequestedSpy.wait());
+    QCOMPARE(quickhelpRequestedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testKeepAbove()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockButton button(KDecoration2::DecorationButtonType::KeepAbove, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // clicking the button should trigger a request for keep above changed
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy keepAboveChangedSpy(mockDecoration.client(), &KDecoration2::DecoratedClient::keepAboveChanged);
+    QVERIFY(keepAboveChangedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(keepAboveChangedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(keepAboveChangedSpy.wait());
+    QCOMPARE(keepAboveChangedSpy.count(), 1);
+    QCOMPARE(keepAboveChangedSpy.first().first().toBool(), true);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), true);
+
+    // click once more should change again
+    button.event(&pressEvent);
+    button.event(&releaseEvent);
+    QVERIFY(keepAboveChangedSpy.wait());
+    QCOMPARE(keepAboveChangedSpy.count(), 2);
+    QCOMPARE(keepAboveChangedSpy.first().first().toBool(), true);
+    QCOMPARE(keepAboveChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), false);
+}
+
+void DecorationButtonTest::testKeepBelow()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockButton button(KDecoration2::DecorationButtonType::KeepBelow, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // clicking the button should trigger a request for keep above changed
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy keepBelowChangedSpy(mockDecoration.client(), &KDecoration2::DecoratedClient::keepBelowChanged);
+    QVERIFY(keepBelowChangedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(keepBelowChangedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(keepBelowChangedSpy.wait());
+    QCOMPARE(keepBelowChangedSpy.count(), 1);
+    QCOMPARE(keepBelowChangedSpy.first().first().toBool(), true);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), true);
+
+    // click once more should change again
+    button.event(&pressEvent);
+    button.event(&releaseEvent);
+    QVERIFY(keepBelowChangedSpy.wait());
+    QCOMPARE(keepBelowChangedSpy.count(), 2);
+    QCOMPARE(keepBelowChangedSpy.first().first().toBool(), true);
+    QCOMPARE(keepBelowChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), false);
+}
+
+void DecorationButtonTest::testShade()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Shade, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), false);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // if the client is shadeable the button should get enabled
+    const auto decoClient = mockDecoration.client();
+    QSignalSpy shadeableChangedSpy(decoClient, &KDecoration2::DecoratedClient::shadeableChanged);
+    QVERIFY(shadeableChangedSpy.isValid());
+    client->setShadeable(true);
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(shadeableChangedSpy.count(), 1);
+    QCOMPARE(shadeableChangedSpy.first().first().toBool(), true);
+
+    // clicking the button should trigger a request for keep above changed
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy shadedChangedSpy(decoClient, &KDecoration2::DecoratedClient::shadedChanged);
+    QVERIFY(shadedChangedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(shadedChangedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(shadedChangedSpy.wait());
+    QCOMPARE(shadedChangedSpy.count(), 1);
+    QCOMPARE(shadedChangedSpy.first().first().toBool(), true);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), true);
+
+    // click once more should change again
+    button.event(&pressEvent);
+    button.event(&releaseEvent);
+    QVERIFY(shadedChangedSpy.wait());
+    QCOMPARE(shadedChangedSpy.count(), 2);
+    QCOMPARE(shadedChangedSpy.first().first().toBool(), true);
+    QCOMPARE(shadedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), false);
+}
+
+void DecorationButtonTest::testMaximize()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Maximize, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), false);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
+
+    // if the client is maximizable the button should get enabled
+    const auto decoClient = mockDecoration.client();
+    QSignalSpy maximizableChangedSpy(decoClient, &KDecoration2::DecoratedClient::maximizeableChanged);
+    QVERIFY(maximizableChangedSpy.isValid());
+    client->setMaximizable(true);
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(maximizableChangedSpy.count(), 1);
+    QCOMPARE(maximizableChangedSpy.first().first().toBool(), true);
+
+    // clicking the button should trigger a request for keep above changed
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy maximizedChangedSpy(decoClient, &KDecoration2::DecoratedClient::maximizedChanged);
+    QVERIFY(maximizedChangedSpy.isValid());
+    QSignalSpy maximizedVerticallyChangedSpy(decoClient, &KDecoration2::DecoratedClient::maximizedVerticallyChanged);
+    QVERIFY(maximizedVerticallyChangedSpy.isValid());
+    QSignalSpy maximizedHorizontallyChangedSpy(decoClient, &KDecoration2::DecoratedClient::maximizedHorizontallyChanged);
+    QVERIFY(maximizedHorizontallyChangedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent leftPressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    leftPressEvent.setAccepted(false);
+    button.event(&leftPressEvent);
+    QCOMPARE(leftPressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(maximizedChangedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent leftReleaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    leftReleaseEvent.setAccepted(false);
+    button.event(&leftReleaseEvent);
+    QCOMPARE(leftReleaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(maximizedChangedSpy.wait());
+    QCOMPARE(maximizedChangedSpy.count(), 1);
+    QCOMPARE(maximizedChangedSpy.first().first().toBool(), true);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), true);
+
+    // clicking again should set to restored
+    button.event(&leftPressEvent);
+    button.event(&leftReleaseEvent);
+    QVERIFY(maximizedChangedSpy.wait());
+    QCOMPARE(maximizedChangedSpy.count(), 2);
+    QCOMPARE(maximizedChangedSpy.first().first().toBool(), true);
+    QCOMPARE(maximizedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), false);
+
+    // test the other buttons
+    QMouseEvent rightPressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::RightButton, Qt::RightButton, Qt::NoModifier);
+    rightPressEvent.setAccepted(false);
+    button.event(&rightPressEvent);
+    QCOMPARE(rightPressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+
+    QMouseEvent middlePressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::MiddleButton, Qt::MiddleButton, Qt::NoModifier);
+    middlePressEvent.setAccepted(false);
+    button.event(&middlePressEvent);
+    QCOMPARE(middlePressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+
+    QMouseEvent middleReleaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::MiddleButton, Qt::NoButton, Qt::NoModifier);
+    middleReleaseEvent.setAccepted(false);
+    button.event(&middleReleaseEvent);
+    QCOMPARE(middleReleaseEvent.isAccepted(), true);
+    QVERIFY(maximizedHorizontallyChangedSpy.wait());
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 3);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(client->isMaximizedHorizontally(), true);
+    QCOMPARE(client->isMaximizedVertically(), false);
+
+    QMouseEvent rightReleaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::RightButton, Qt::NoButton, Qt::NoModifier);
+    rightReleaseEvent.setAccepted(false);
+    button.event(&rightReleaseEvent);
+    QCOMPARE(rightReleaseEvent.isAccepted(), true);
+    QVERIFY(maximizedVerticallyChangedSpy.wait());
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 4);
+    QCOMPARE(client->isMaximizedHorizontally(), true);
+    QCOMPARE(client->isMaximizedVertically(), true);
+    QCOMPARE(button.isChecked(), true);
+}
+
+void DecorationButtonTest::testOnAllDesktops()
+{
+    MockBridge bridge;
+    auto decoSettings = std::make_shared<KDecoration2::DecorationSettings>(&bridge);
+    MockDecoration mockDecoration(&bridge);
+    mockDecoration.setSettings(decoSettings);
+    MockButton button(KDecoration2::DecorationButtonType::OnAllDesktops, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), false);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+    const auto decoClient = mockDecoration.client();
+    QCOMPARE(decoClient->isOnAllDesktops(), false);
+
+    MockSettings *settings = bridge.lastCreatedSettings();
+    QVERIFY(settings);
+
+    QSignalSpy onAllDesktopsAvailableChangedSpy(decoSettings.get(), &KDecoration2::DecorationSettings::onAllDesktopsAvailableChanged);
+    QVERIFY(onAllDesktopsAvailableChangedSpy.isValid());
+    QSignalSpy visibleChangedSpy(&button, &KDecoration2::DecorationButton::visibilityChanged);
+    QVERIFY(visibleChangedSpy.isValid());
+
+    settings->setOnAllDesktopsAvailabe(true);
+    QCOMPARE(onAllDesktopsAvailableChangedSpy.count(), 1);
+    QCOMPARE(onAllDesktopsAvailableChangedSpy.last().first().toBool(), true);
+    QCOMPARE(visibleChangedSpy.count(), 1);
+    QCOMPARE(visibleChangedSpy.last().first().toBool(), true);
+
+    // clicking the button should trigger a request for on all desktops
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy onAllDesktopsChangedSpy(decoClient, &KDecoration2::DecoratedClient::onAllDesktopsChanged);
+    QVERIFY(onAllDesktopsChangedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(onAllDesktopsChangedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(onAllDesktopsChangedSpy.wait());
+    QCOMPARE(onAllDesktopsChangedSpy.count(), 1);
+    QCOMPARE(onAllDesktopsChangedSpy.first().first().toBool(), true);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+    QCOMPARE(button.isChecked(), true);
+}
+
+void DecorationButtonTest::testMenu()
+{
+    MockBridge bridge;
+    auto decoSettings = std::make_shared<KDecoration2::DecorationSettings>(&bridge);
+    MockDecoration mockDecoration(&bridge);
+    mockDecoration.setSettings(decoSettings);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Menu, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isCheckable(), false);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton | Qt::RightButton);
+
+    // clicking the button should trigger a request for menu button
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+    QSignalSpy menuRequestedSpy(client, &MockClient::menuRequested);
+    QVERIFY(menuRequestedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(menuRequestedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(menuRequestedSpy.wait());
+    QCOMPARE(menuRequestedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testMenuDoubleClick()
+{
+    MockBridge bridge;
+    auto decoSettings = std::make_shared<KDecoration2::DecorationSettings>(&bridge);
+    MockDecoration mockDecoration(&bridge);
+    mockDecoration.setSettings(decoSettings);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Menu, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    MockSettings *settings = bridge.lastCreatedSettings();
+    QVERIFY(settings);
+    QSignalSpy closeOnDoubleClickOnMenuChangedSpy(decoSettings.get(), &KDecoration2::DecorationSettings::closeOnDoubleClickOnMenuChanged);
+    QVERIFY(closeOnDoubleClickOnMenuChangedSpy.isValid());
+    settings->setCloseOnDoubleClickOnMenu(true);
+    QCOMPARE(closeOnDoubleClickOnMenuChangedSpy.count(), 1);
+    QCOMPARE(closeOnDoubleClickOnMenuChangedSpy.last().first().toBool(), true);
+
+    // button used a queued connection, so we need to run event loop
+    QCoreApplication::processEvents();
+
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy doubleClickedSpy(&button, &KDecoration2::DecorationButton::doubleClicked);
+    QVERIFY(doubleClickedSpy.isValid());
+    QSignalSpy closeRequestedSpy(client, &MockClient::closeRequested);
+    QVERIFY(closeRequestedSpy.isValid());
+    QSignalSpy menuRequestedSpy(client, &MockClient::menuRequested);
+    QVERIFY(menuRequestedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    // should not have emitted a clicked
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(doubleClickedSpy.count(), 0);
+
+    // another press should trigger the double click event
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QVERIFY(closeRequestedSpy.wait());
+    QCOMPARE(doubleClickedSpy.count(), 1);
+    QCOMPARE(closeRequestedSpy.count(), 1);
+    QCOMPARE(menuRequestedSpy.count(), 0);
+
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    // run events
+    QCoreApplication::processEvents();
+    QCOMPARE(closeRequestedSpy.count(), 1);
+    QCOMPARE(menuRequestedSpy.count(), 0);
+
+    // a double click of right button shouldn't trigger the double click event
+    QMouseEvent rightPressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::RightButton, Qt::RightButton, Qt::NoModifier);
+    rightPressEvent.setAccepted(false);
+    button.event(&rightPressEvent);
+    QCOMPARE(rightPressEvent.isAccepted(), true);
+    QMouseEvent rightReleaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::RightButton, Qt::NoButton, Qt::NoModifier);
+    rightReleaseEvent.setAccepted(false);
+    button.event(&rightReleaseEvent);
+    QCOMPARE(rightReleaseEvent.isAccepted(), true);
+    QCOMPARE(clickedSpy.count(), 1);
+    QVERIFY(menuRequestedSpy.wait());
+    QCOMPARE(menuRequestedSpy.count(), 1);
+    // second click
+    rightPressEvent.setAccepted(false);
+    button.event(&rightPressEvent);
+    QCOMPARE(rightPressEvent.isAccepted(), true);
+    rightReleaseEvent.setAccepted(false);
+    button.event(&rightReleaseEvent);
+    QCOMPARE(rightReleaseEvent.isAccepted(), true);
+    QCOMPARE(clickedSpy.count(), 2);
+    QVERIFY(menuRequestedSpy.wait());
+    QCOMPARE(menuRequestedSpy.count(), 2);
+}
+
+void DecorationButtonTest::testMenuPressAndHold()
+{
+    MockBridge bridge;
+    auto decoSettings = std::make_shared<KDecoration2::DecorationSettings>(&bridge);
+    MockDecoration mockDecoration(&bridge);
+    mockDecoration.setSettings(decoSettings);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::Menu, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    MockSettings *settings = bridge.lastCreatedSettings();
+    QVERIFY(settings);
+    QSignalSpy closeOnDoubleClickOnMenuChangedSpy(decoSettings.get(), &KDecoration2::DecorationSettings::closeOnDoubleClickOnMenuChanged);
+    QVERIFY(closeOnDoubleClickOnMenuChangedSpy.isValid());
+    settings->setCloseOnDoubleClickOnMenu(true);
+    QCOMPARE(closeOnDoubleClickOnMenuChangedSpy.count(), 1);
+    QCOMPARE(closeOnDoubleClickOnMenuChangedSpy.last().first().toBool(), true);
+
+    // button used a queued connection, so we need to run event loop
+    QCoreApplication::processEvents();
+
+    QSignalSpy menuRequestedSpy(client, &MockClient::menuRequested);
+    QVERIFY(menuRequestedSpy.isValid());
+    QSignalSpy doubleClickedSpy(&button, &KDecoration2::DecorationButton::doubleClicked);
+    QVERIFY(doubleClickedSpy.isValid());
+    QSignalSpy closeRequestedSpy(client, &MockClient::closeRequested);
+    QVERIFY(closeRequestedSpy.isValid());
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+
+    // send a press event
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+
+    // and wait
+    QVERIFY(menuRequestedSpy.wait());
+    QCOMPARE(menuRequestedSpy.count(), 1);
+    QCOMPARE(clickedSpy.count(), 1);
+
+    // send release event
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(clickedSpy.count(), 1);
+
+    QTest::qWait(QGuiApplication::styleHints()->mouseDoubleClickInterval() + 5);
+
+    // and it shouldn't be a double click
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+
+    // while waiting we disable click and hold
+    settings->setCloseOnDoubleClickOnMenu(false);
+    QCOMPARE(closeOnDoubleClickOnMenuChangedSpy.count(), 2);
+    QCOMPARE(closeOnDoubleClickOnMenuChangedSpy.last().first().toBool(), false);
+    // button used a queued connection, so we need to run event loop
+    QCoreApplication::processEvents();
+    // and releasing should emit the menu signal
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(clickedSpy.count(), 2);
+    QVERIFY(menuRequestedSpy.wait());
+    QCOMPARE(menuRequestedSpy.count(), 2);
+    // never got a dobule click
+    QCOMPARE(closeRequestedSpy.count(), 0);
+}
+
+void DecorationButtonTest::testApplicationMenu()
+{
+    MockBridge bridge;
+    auto decoSettings = std::make_shared<KDecoration2::DecorationSettings>(&bridge);
+    MockDecoration mockDecoration(&bridge);
+    mockDecoration.setSettings(decoSettings);
+    MockClient *client = bridge.lastCreatedClient();
+    MockButton button(KDecoration2::DecorationButtonType::ApplicationMenu, &mockDecoration);
+    button.setGeometry(QRect(0, 0, 10, 10));
+
+    QCOMPARE(button.isEnabled(), true);
+    QCOMPARE(button.isCheckable(), true);
+    QCOMPARE(button.isChecked(), false);
+    QCOMPARE(button.isVisible(), true);
+    QCOMPARE(button.acceptedButtons(), Qt::LeftButton);
+
+    // clicking the button should trigger a request for application menu
+    QSignalSpy clickedSpy(&button, &KDecoration2::DecorationButton::clicked);
+    QVERIFY(clickedSpy.isValid());
+    QSignalSpy pressedSpy(&button, &KDecoration2::DecorationButton::pressed);
+    QVERIFY(pressedSpy.isValid());
+    QSignalSpy releasedSpy(&button, &KDecoration2::DecorationButton::released);
+    QVERIFY(releasedSpy.isValid());
+    QSignalSpy pressedChangedSpy(&button, &KDecoration2::DecorationButton::pressedChanged);
+    QVERIFY(pressedChangedSpy.isValid());
+    QSignalSpy applicationMenuRequestedSpy(client, &MockClient::applicationMenuRequested);
+    QVERIFY(applicationMenuRequestedSpy.isValid());
+
+    QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+    pressEvent.setAccepted(false);
+    button.event(&pressEvent);
+    QCOMPARE(pressEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), true);
+    QCOMPARE(clickedSpy.count(), 0);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 0);
+    QCOMPARE(applicationMenuRequestedSpy.count(), 0);
+    QCOMPARE(pressedChangedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.first().first().toBool(), true);
+
+    QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(5, 5), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+    releaseEvent.setAccepted(false);
+    button.event(&releaseEvent);
+    QCOMPARE(releaseEvent.isAccepted(), true);
+    QCOMPARE(button.isPressed(), false);
+    QCOMPARE(clickedSpy.count(), 1);
+    QCOMPARE(clickedSpy.first().first().value<Qt::MouseButton>(), Qt::LeftButton);
+    QCOMPARE(pressedSpy.count(), 1);
+    QCOMPARE(releasedSpy.count(), 1);
+    QVERIFY(applicationMenuRequestedSpy.wait());
+    QCOMPARE(applicationMenuRequestedSpy.count(), 1);
+    QCOMPARE(pressedChangedSpy.count(), 2);
+    QCOMPARE(pressedChangedSpy.last().first().toBool(), false);
+}
+
+void DecorationButtonTest::testContains_data()
+{
+    QTest::addColumn<QPointF>("pos");
+    QTest::addColumn<bool>("contains");
+
+    // Button geometry: QRectF(0, 0, 10, 10).
+    QTest::newRow("on left edge") << QPointF(0, 5) << true;
+    QTest::newRow("on top edge") << QPointF(5, 0) << true;
+    QTest::newRow("on right edge") << QPointF(9, 5) << true;
+    QTest::newRow("on bottom edge") << QPointF(5, 9) << true;
+    QTest::newRow("inside") << QPointF(5, 5) << true;
+    QTest::newRow("outside 1") << QPointF(-1, 5) << false;
+    QTest::newRow("outside 2") << QPointF(5, -1) << false;
+    QTest::newRow("outside 3") << QPointF(10, 5) << false;
+    QTest::newRow("outside 4") << QPointF(5, 10) << false;
+}
+
+void DecorationButtonTest::testContains()
+{
+    MockBridge bridge;
+    MockDecoration mockDecoration(&bridge);
+
+    MockButton button(KDecoration2::DecorationButtonType::Custom, &mockDecoration);
+    button.setGeometry(QRectF(0, 0, 10, 10));
+    button.setEnabled(true);
+    button.setVisible(true);
+
+    QFETCH(QPointF, pos);
+    QTEST(button.contains(pos), "contains");
+}
+
+QTEST_MAIN(DecorationButtonTest)
+#include "decorationbuttontest.moc"
diff --git a/autotests/decorationtest.cpp b/autotests/decorationtest.cpp
new file mode 100644 (file)
index 0000000..09a87c8
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "../src/decorationsettings.h"
+#include "mockbridge.h"
+#include "mockclient.h"
+#include "mockdecoration.h"
+#include "mocksettings.h"
+#include <QSignalSpy>
+#include <QTest>
+#include <QVariant>
+
+class DecorationTest : public QObject
+{
+    Q_OBJECT
+private Q_SLOTS:
+    void testCreate();
+    void testOpaque();
+    void testSection_data();
+    void testSection();
+};
+
+#ifdef _MSC_VER
+QMap<QString, QVariant> makeMap(const QString &key, const QVariant &value);
+#endif
+void DecorationTest::testCreate()
+{
+    // just test that creating the Decoration doesn't crash
+    MockBridge bridge;
+    const QString bridgeKey = QStringLiteral("bridge");
+    MockDecoration deco1(nullptr,
+                         QVariantList({
+#ifdef _MSC_VER
+                             makeMap(bridgeKey, QVariant::fromValue(5)),
+#else
+                             QVariantMap({{bridgeKey, QVariant::fromValue(5)}}),
+#endif
+                             QVariant::fromValue(bridgeKey),
+                             QVariantMap(),
+#ifdef _MSC_VER
+                             makeMap(bridgeKey, QVariant::fromValue(&bridge)),
+#else
+                             QVariantMap({{bridgeKey, QVariant::fromValue(&bridge)}})
+#endif
+                         }));
+    QVERIFY(deco1.client());
+}
+
+void DecorationTest::testOpaque()
+{
+    MockBridge bridge;
+    MockDecoration deco(&bridge);
+    QSignalSpy opaqueChangedSpy(&deco, &KDecoration2::Decoration::opaqueChanged);
+    QVERIFY(opaqueChangedSpy.isValid());
+    QCOMPARE(deco.isOpaque(), false);
+    deco.setOpaque(false);
+    QVERIFY(opaqueChangedSpy.isEmpty());
+    deco.setOpaque(true);
+    QCOMPARE(opaqueChangedSpy.count(), 1);
+    QCOMPARE(opaqueChangedSpy.first().first().toBool(), true);
+    QCOMPARE(deco.isOpaque(), true);
+    deco.setOpaque(true);
+    QCOMPARE(opaqueChangedSpy.count(), 1);
+    deco.setOpaque(false);
+    QCOMPARE(opaqueChangedSpy.count(), 2);
+    QCOMPARE(opaqueChangedSpy.first().first().toBool(), true);
+    QCOMPARE(opaqueChangedSpy.last().first().toBool(), false);
+    QCOMPARE(deco.isOpaque(), false);
+}
+
+Q_DECLARE_METATYPE(QMargins)
+Q_DECLARE_METATYPE(Qt::WindowFrameSection)
+
+void DecorationTest::testSection_data()
+{
+    QTest::addColumn<QRect>("titleBar");
+    QTest::addColumn<QMargins>("margins");
+    QTest::addColumn<QPoint>("pos");
+    QTest::addColumn<Qt::WindowFrameSection>("expected");
+
+    QRect r(1, 1, 98, 8);
+    QMargins m(1, 10, 1, 1);
+    QTest::newRow("topLeft") << r << m << QPoint(0, 0) << Qt::TopLeftSection;
+    QTest::newRow("top@Left") << r << m << QPoint(1, 0) << Qt::TopSection;
+    QTest::newRow("top@Right") << r << m << QPoint(100, 0) << Qt::TopSection;
+    QTest::newRow("topRight") << r << m << QPoint(101, 0) << Qt::TopRightSection;
+    QTest::newRow("right@top") << r << m << QPoint(101, 1) << Qt::RightSection;
+    QTest::newRow("right@bottom") << r << m << QPoint(101, 109) << Qt::RightSection;
+    QTest::newRow("bottomRight") << r << m << QPoint(101, 110) << Qt::BottomRightSection;
+    QTest::newRow("bottom@right") << r << m << QPoint(100, 110) << Qt::BottomSection;
+    QTest::newRow("bottom@left") << r << m << QPoint(1, 110) << Qt::BottomSection;
+    QTest::newRow("bottomLeft") << r << m << QPoint(0, 110) << Qt::BottomLeftSection;
+    QTest::newRow("left@Top") << r << m << QPoint(0, 1) << Qt::LeftSection;
+    QTest::newRow("left@Bottom") << r << m << QPoint(0, 109) << Qt::LeftSection;
+    QTest::newRow("title") << r << m << QPoint(1, 1) << Qt::TitleBarArea;
+}
+
+void DecorationTest::testSection()
+{
+    MockBridge bridge;
+    auto decoSettings = std::make_shared<KDecoration2::DecorationSettings>(&bridge);
+    MockDecoration deco(&bridge);
+    deco.setSettings(decoSettings);
+
+    MockSettings *settings = bridge.lastCreatedSettings();
+    settings->setLargeSpacing(0);
+
+    MockClient *client = bridge.lastCreatedClient();
+    client->setWidth(100);
+    client->setHeight(100);
+    QCOMPARE(deco.size(), QSize(100, 100));
+    QCOMPARE(deco.borderLeft(), 0);
+    QCOMPARE(deco.borderTop(), 0);
+    QCOMPARE(deco.borderRight(), 0);
+    QCOMPARE(deco.borderBottom(), 0);
+    QCOMPARE(deco.titleBar(), QRect());
+    QCOMPARE(deco.sectionUnderMouse(), Qt::NoSection);
+
+    QFETCH(QRect, titleBar);
+    QFETCH(QMargins, margins);
+    deco.setBorders(margins);
+    QCOMPARE(deco.borderLeft(), margins.left());
+    QCOMPARE(deco.borderTop(), margins.top());
+    QCOMPARE(deco.borderRight(), margins.right());
+    QCOMPARE(deco.borderBottom(), margins.bottom());
+    deco.setTitleBar(titleBar);
+    QCOMPARE(deco.titleBar(), titleBar);
+    QCOMPARE(deco.size(), QSize(100 + deco.borderLeft() + deco.borderRight(), 100 + deco.borderTop() + deco.borderBottom()));
+
+    QSignalSpy spy(&deco, &KDecoration2::Decoration::sectionUnderMouseChanged);
+    QVERIFY(spy.isValid());
+    QFETCH(QPoint, pos);
+    QHoverEvent event(QEvent::HoverMove, QPointF(pos), QPointF(pos));
+    QCoreApplication::sendEvent(&deco, &event);
+    QFETCH(Qt::WindowFrameSection, expected);
+    QCOMPARE(deco.sectionUnderMouse(), expected);
+    QCOMPARE(spy.count(), 1);
+    QCOMPARE(spy.first().first().value<Qt::WindowFrameSection>(), expected);
+
+    QHoverEvent event2(QEvent::HoverMove, QPointF(50, 50), QPointF(50, 50));
+    QCoreApplication::sendEvent(&deco, &event2);
+    QCOMPARE(deco.sectionUnderMouse(), Qt::NoSection);
+    QCOMPARE(spy.count(), 2);
+    QCOMPARE(spy.first().first().value<Qt::WindowFrameSection>(), expected);
+    QCOMPARE(spy.last().first().value<Qt::WindowFrameSection>(), Qt::NoSection);
+}
+
+QTEST_MAIN(DecorationTest)
+#include "decorationtest.moc"
diff --git a/autotests/mockbridge.cpp b/autotests/mockbridge.cpp
new file mode 100644 (file)
index 0000000..22a1d61
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "mockbridge.h"
+#include "mockclient.h"
+#include "mocksettings.h"
+#include <QtGlobal>
+
+std::unique_ptr<KDecoration2::DecoratedClientPrivate> MockBridge::createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration)
+{
+    auto ptr = std::make_unique<MockClient>(client, decoration);
+    m_lastCreatedClient = ptr.get();
+    return ptr;
+}
+
+std::unique_ptr<KDecoration2::DecorationSettingsPrivate> MockBridge::settings(KDecoration2::DecorationSettings *parent)
+{
+    auto ptr = std::make_unique<MockSettings>(parent);
+    m_lastCreatedSettings = ptr.get();
+    return ptr;
+}
+
+#include "moc_mockbridge.cpp"
diff --git a/autotests/mockbridge.h b/autotests/mockbridge.h
new file mode 100644 (file)
index 0000000..245a547
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../src/private/decorationbridge.h"
+#include <QObject>
+
+class MockClient;
+class MockSettings;
+
+class MockBridge : public KDecoration2::DecorationBridge
+{
+    Q_OBJECT
+public:
+    std::unique_ptr<KDecoration2::DecoratedClientPrivate> createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration) override;
+    std::unique_ptr<KDecoration2::DecorationSettingsPrivate> settings(KDecoration2::DecorationSettings *parent) override;
+
+    MockClient *lastCreatedClient() const
+    {
+        return m_lastCreatedClient;
+    }
+    MockSettings *lastCreatedSettings() const
+    {
+        return m_lastCreatedSettings;
+    }
+
+private:
+    MockClient *m_lastCreatedClient = nullptr;
+    MockSettings *m_lastCreatedSettings = nullptr;
+};
diff --git a/autotests/mockbutton.cpp b/autotests/mockbutton.cpp
new file mode 100644 (file)
index 0000000..8e93435
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "mockbutton.h"
+
+MockButton::MockButton(KDecoration2::DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent)
+    : DecorationButton(type, decoration, parent)
+{
+}
+
+void MockButton::paint(QPainter *painter, const QRect &repaintRegion)
+{
+    Q_UNUSED(painter)
+    Q_UNUSED(repaintRegion)
+}
+
+#include "moc_mockbutton.cpp"
diff --git a/autotests/mockbutton.h b/autotests/mockbutton.h
new file mode 100644 (file)
index 0000000..7f1e660
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../src/decorationbutton.h"
+
+class MockButton : public KDecoration2::DecorationButton
+{
+    Q_OBJECT
+public:
+    MockButton(KDecoration2::DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent = nullptr);
+    void paint(QPainter *painter, const QRect &repaintRegion) override;
+};
diff --git a/autotests/mockclient.cpp b/autotests/mockclient.cpp
new file mode 100644 (file)
index 0000000..89fbbce
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "mockclient.h"
+#include <decoratedclient.h>
+
+#include <QPalette>
+
+MockClient::MockClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration)
+    : QObject()
+    , ApplicationMenuEnabledDecoratedClientPrivate(client, decoration)
+{
+}
+
+Qt::Edges MockClient::adjacentScreenEdges() const
+{
+    return Qt::Edges();
+}
+
+QString MockClient::caption() const
+{
+    return QString();
+}
+
+WId MockClient::decorationId() const
+{
+    return 0;
+}
+
+int MockClient::height() const
+{
+    return m_height;
+}
+
+QIcon MockClient::icon() const
+{
+    return QIcon();
+}
+
+bool MockClient::isActive() const
+{
+    return false;
+}
+
+bool MockClient::isCloseable() const
+{
+    return m_closeable;
+}
+
+bool MockClient::isKeepAbove() const
+{
+    return m_keepAbove;
+}
+
+bool MockClient::isKeepBelow() const
+{
+    return m_keepBelow;
+}
+
+bool MockClient::isMaximizeable() const
+{
+    return m_maximizable;
+}
+
+bool MockClient::isMaximized() const
+{
+    return isMaximizedHorizontally() && isMaximizedVertically();
+}
+
+bool MockClient::isMaximizedHorizontally() const
+{
+    return m_maximizedHorizontally;
+}
+
+bool MockClient::isMaximizedVertically() const
+{
+    return m_maximizedVertically;
+}
+
+bool MockClient::isMinimizeable() const
+{
+    return m_minimizable;
+}
+
+bool MockClient::isModal() const
+{
+    return false;
+}
+
+bool MockClient::isMoveable() const
+{
+    return false;
+}
+
+bool MockClient::isOnAllDesktops() const
+{
+    return m_onAllDesktops;
+}
+
+bool MockClient::isResizeable() const
+{
+    return false;
+}
+
+bool MockClient::isShadeable() const
+{
+    return m_shadeable;
+}
+
+bool MockClient::isShaded() const
+{
+    return m_shaded;
+}
+
+QPalette MockClient::palette() const
+{
+    return QPalette();
+}
+
+bool MockClient::hasApplicationMenu() const
+{
+    return true;
+}
+
+bool MockClient::isApplicationMenuActive() const
+{
+    return false;
+}
+
+bool MockClient::providesContextHelp() const
+{
+    return m_contextHelp;
+}
+
+void MockClient::requestClose()
+{
+    Q_EMIT closeRequested();
+}
+
+void MockClient::requestContextHelp()
+{
+    Q_EMIT quickHelpRequested();
+}
+
+void MockClient::requestToggleMaximization(Qt::MouseButtons buttons)
+{
+    bool maximizedHorizontally = m_maximizedHorizontally;
+    bool maximizedVertically = m_maximizedVertically;
+    if (buttons.testFlag(Qt::LeftButton)) {
+        maximizedHorizontally = !m_maximizedHorizontally;
+        maximizedVertically = !m_maximizedVertically;
+    }
+    if (buttons.testFlag(Qt::MiddleButton)) {
+        maximizedHorizontally = !m_maximizedHorizontally;
+    }
+    if (buttons.testFlag(Qt::RightButton)) {
+        maximizedVertically = !m_maximizedVertically;
+    }
+    const bool wasMaximized = isMaximized();
+    if (m_maximizedHorizontally != maximizedHorizontally) {
+        m_maximizedHorizontally = maximizedHorizontally;
+        Q_EMIT client()->maximizedHorizontallyChanged(m_maximizedHorizontally);
+    }
+    if (m_maximizedVertically != maximizedVertically) {
+        m_maximizedVertically = maximizedVertically;
+        Q_EMIT client()->maximizedVerticallyChanged(m_maximizedVertically);
+    }
+    if (wasMaximized != isMaximized()) {
+        Q_EMIT client()->maximizedChanged(isMaximized());
+    }
+}
+
+void MockClient::requestMinimize()
+{
+    Q_EMIT minimizeRequested();
+}
+
+void MockClient::requestShowWindowMenu(const QRect &rect)
+{
+    Q_EMIT menuRequested();
+}
+
+void MockClient::requestShowApplicationMenu(const QRect &rect, int actionId)
+{
+    Q_UNUSED(rect);
+    Q_UNUSED(actionId);
+    Q_EMIT applicationMenuRequested(); // FIXME TODO pass geometry
+}
+
+void MockClient::requestToggleKeepAbove()
+{
+    m_keepAbove = !m_keepAbove;
+    Q_EMIT client()->keepAboveChanged(m_keepAbove);
+}
+
+void MockClient::requestToggleKeepBelow()
+{
+    m_keepBelow = !m_keepBelow;
+    Q_EMIT client()->keepBelowChanged(m_keepBelow);
+}
+
+void MockClient::requestToggleOnAllDesktops()
+{
+    m_onAllDesktops = !m_onAllDesktops;
+    Q_EMIT client()->onAllDesktopsChanged(m_onAllDesktops);
+}
+
+void MockClient::requestToggleShade()
+{
+    m_shaded = !m_shaded;
+    Q_EMIT client()->shadedChanged(m_shaded);
+}
+
+void MockClient::requestShowToolTip(const QString &text)
+{
+    Q_UNUSED(text);
+}
+
+void MockClient::requestHideToolTip()
+{
+}
+
+QSize MockClient::size() const
+{
+    return QSize(m_width, m_height);
+}
+
+int MockClient::width() const
+{
+    return m_width;
+}
+
+QString MockClient::windowClass() const
+{
+    return QString();
+}
+
+WId MockClient::windowId() const
+{
+    return 0;
+}
+
+void MockClient::setCloseable(bool set)
+{
+    m_closeable = set;
+    Q_EMIT client()->closeableChanged(set);
+}
+
+void MockClient::setMinimizable(bool set)
+{
+    m_minimizable = set;
+    Q_EMIT client()->minimizeableChanged(set);
+}
+
+void MockClient::setProvidesContextHelp(bool set)
+{
+    m_contextHelp = set;
+    Q_EMIT client()->providesContextHelpChanged(set);
+}
+
+void MockClient::setShadeable(bool set)
+{
+    m_shadeable = set;
+    Q_EMIT client()->shadeableChanged(set);
+}
+
+void MockClient::setMaximizable(bool set)
+{
+    m_maximizable = set;
+    Q_EMIT client()->maximizeableChanged(set);
+}
+
+void MockClient::setWidth(int w)
+{
+    m_width = w;
+    Q_EMIT client()->widthChanged(w);
+}
+
+void MockClient::setHeight(int h)
+{
+    m_height = h;
+    Q_EMIT client()->heightChanged(h);
+}
+
+void MockClient::showApplicationMenu(int actionId)
+{
+    Q_UNUSED(actionId)
+}
+
+#include "moc_mockclient.cpp"
diff --git a/autotests/mockclient.h b/autotests/mockclient.h
new file mode 100644 (file)
index 0000000..1a5c982
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../src/private/decoratedclientprivate.h"
+
+#include <QObject>
+
+class MockClient : public QObject, public KDecoration2::ApplicationMenuEnabledDecoratedClientPrivate
+{
+    Q_OBJECT
+public:
+    explicit MockClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration);
+
+    Qt::Edges adjacentScreenEdges() const override;
+    QString caption() const override;
+    WId decorationId() const override;
+    int height() const override;
+    QIcon icon() const override;
+    bool isActive() const override;
+    bool isCloseable() const override;
+    bool isKeepAbove() const override;
+    bool isKeepBelow() const override;
+    bool isMaximizeable() const override;
+    bool isMaximized() const override;
+    bool isMaximizedHorizontally() const override;
+    bool isMaximizedVertically() const override;
+    bool isMinimizeable() const override;
+    bool isModal() const override;
+    bool isMoveable() const override;
+    bool isOnAllDesktops() const override;
+    bool isResizeable() const override;
+    bool isShadeable() const override;
+    bool isShaded() const override;
+    QPalette palette() const override;
+    bool hasApplicationMenu() const override;
+    bool isApplicationMenuActive() const override;
+    bool providesContextHelp() const override;
+    void requestClose() override;
+    void requestContextHelp() override;
+    void requestToggleMaximization(Qt::MouseButtons buttons) override;
+    void requestMinimize() override;
+    void requestShowWindowMenu(const QRect &rect) override;
+    void requestShowApplicationMenu(const QRect &rect, int actionId) override;
+    void requestToggleKeepAbove() override;
+    void requestToggleKeepBelow() override;
+    void requestToggleOnAllDesktops() override;
+    void requestToggleShade() override;
+    void requestShowToolTip(const QString &text) override;
+    void requestHideToolTip() override;
+    QSize size() const override;
+    int width() const override;
+    WId windowId() const override;
+    QString windowClass() const override;
+
+    void showApplicationMenu(int actionId) override;
+
+    void setCloseable(bool set);
+    void setMinimizable(bool set);
+    void setProvidesContextHelp(bool set);
+    void setShadeable(bool set);
+    void setMaximizable(bool set);
+
+    void setWidth(int w);
+    void setHeight(int h);
+
+Q_SIGNALS:
+    void closeRequested();
+    void minimizeRequested();
+    void quickHelpRequested();
+    void menuRequested();
+    void applicationMenuRequested();
+
+private:
+    bool m_closeable = false;
+    bool m_minimizable = false;
+    bool m_contextHelp = false;
+    bool m_keepAbove = false;
+    bool m_keepBelow = false;
+    bool m_shadeable = false;
+    bool m_shaded = false;
+    bool m_maximizable = false;
+    bool m_maximizedVertically = false;
+    bool m_maximizedHorizontally = false;
+    bool m_onAllDesktops = false;
+    int m_width = 0;
+    int m_height = 0;
+};
diff --git a/autotests/mockdecoration.cpp b/autotests/mockdecoration.cpp
new file mode 100644 (file)
index 0000000..fe65929
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "mockdecoration.h"
+#include "mockbridge.h"
+
+#include <QMap>
+#include <QVariantMap>
+#include <utility>
+
+MockDecoration::MockDecoration(QObject *parent, const QVariantList &args)
+    : Decoration(parent, args)
+{
+}
+
+#ifdef _MSC_VER
+QMap<QString, QVariant> makeMap(const QString &key, const QVariant &value)
+{
+    QMap<QString, QVariant> ret;
+    ret.insert(key, value);
+    return ret;
+}
+MockDecoration::MockDecoration(MockBridge *bridge)
+    : MockDecoration(nullptr, QVariantList({makeMap(QStringLiteral("bridge"), QVariant::fromValue(bridge))}))
+#else
+MockDecoration::MockDecoration(MockBridge *bridge)
+    : MockDecoration(nullptr, QVariantList({QVariantMap({{QStringLiteral("bridge"), QVariant::fromValue(bridge)}})}))
+#endif
+{
+}
+
+bool MockDecoration::init()
+{
+    return true;
+}
+
+void MockDecoration::paint(QPainter *painter, const QRect &repaintRegion)
+{
+    Q_UNUSED(painter)
+    Q_UNUSED(repaintRegion)
+}
+
+void MockDecoration::setOpaque(bool set)
+{
+    Decoration::setOpaque(set);
+}
+
+void MockDecoration::setBorders(const QMargins &m)
+{
+    Decoration::setBorders(m);
+}
+
+void MockDecoration::setTitleBar(const QRect &rect)
+{
+    Decoration::setTitleBar(rect);
+}
+
+#include "moc_mockdecoration.cpp"
diff --git a/autotests/mockdecoration.h b/autotests/mockdecoration.h
new file mode 100644 (file)
index 0000000..23dcbde
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../src/decoration.h"
+
+class MockBridge;
+
+class MockDecoration : public KDecoration2::Decoration
+{
+    Q_OBJECT
+public:
+    explicit MockDecoration(QObject *parent, const QVariantList &args);
+    explicit MockDecoration(MockBridge *bridge);
+    bool init() override;
+    void paint(QPainter *painter, const QRect &repaintRegion) override;
+    void setOpaque(bool set);
+    using Decoration::setBorders;
+    void setBorders(const QMargins &m);
+    using Decoration::setTitleBar;
+    void setTitleBar(const QRect &rect);
+};
diff --git a/autotests/mocksettings.cpp b/autotests/mocksettings.cpp
new file mode 100644 (file)
index 0000000..54e87f0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "mocksettings.h"
+#include "../src/decorationsettings.h"
+
+MockSettings::MockSettings(KDecoration2::DecorationSettings *parent)
+    : DecorationSettingsPrivate(parent)
+{
+}
+
+KDecoration2::BorderSize MockSettings::borderSize() const
+{
+    return KDecoration2::BorderSize::Normal;
+}
+
+QList<KDecoration2::DecorationButtonType> MockSettings::decorationButtonsLeft() const
+{
+    return QList<KDecoration2::DecorationButtonType>();
+}
+
+QList<KDecoration2::DecorationButtonType> MockSettings::decorationButtonsRight() const
+{
+    return QList<KDecoration2::DecorationButtonType>();
+}
+
+bool MockSettings::isAlphaChannelSupported() const
+{
+    return true;
+}
+
+bool MockSettings::isCloseOnDoubleClickOnMenu() const
+{
+    return m_closeDoubleClickOnMenu;
+}
+
+bool MockSettings::isOnAllDesktopsAvailable() const
+{
+    return m_onAllDesktopsAvailable;
+}
+
+void MockSettings::setOnAllDesktopsAvailabe(bool set)
+{
+    if (m_onAllDesktopsAvailable == set) {
+        return;
+    }
+    m_onAllDesktopsAvailable = set;
+    Q_EMIT decorationSettings()->onAllDesktopsAvailableChanged(m_onAllDesktopsAvailable);
+}
+
+void MockSettings::setCloseOnDoubleClickOnMenu(bool set)
+{
+    if (m_closeDoubleClickOnMenu == set) {
+        return;
+    }
+    m_closeDoubleClickOnMenu = set;
+    Q_EMIT decorationSettings()->closeOnDoubleClickOnMenuChanged(m_closeDoubleClickOnMenu);
+}
diff --git a/autotests/mocksettings.h b/autotests/mocksettings.h
new file mode 100644 (file)
index 0000000..bf5d084
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../src/private/decorationsettingsprivate.h"
+
+class MockSettings : public KDecoration2::DecorationSettingsPrivate
+{
+public:
+    explicit MockSettings(KDecoration2::DecorationSettings *parent);
+
+    KDecoration2::BorderSize borderSize() const override;
+    QList<KDecoration2::DecorationButtonType> decorationButtonsLeft() const override;
+    QList<KDecoration2::DecorationButtonType> decorationButtonsRight() const override;
+    bool isAlphaChannelSupported() const override;
+    bool isCloseOnDoubleClickOnMenu() const override;
+    bool isOnAllDesktopsAvailable() const override;
+
+    void setOnAllDesktopsAvailabe(bool set);
+    void setCloseOnDoubleClickOnMenu(bool set);
+
+private:
+    bool m_onAllDesktopsAvailable = false;
+    bool m_closeDoubleClickOnMenu = false;
+};
diff --git a/autotests/shadowtest.cpp b/autotests/shadowtest.cpp
new file mode 100644 (file)
index 0000000..c0aab64
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "../src/decorationshadow.h"
+#include <QSignalSpy>
+#include <QTest>
+
+Q_DECLARE_METATYPE(QMargins)
+
+class DecorationShadowTest : public QObject
+{
+    Q_OBJECT
+private Q_SLOTS:
+    void testPadding_data();
+    void testPadding();
+    void testSizes_data();
+    void testSizes();
+};
+
+void DecorationShadowTest::testPadding_data()
+{
+    QTest::addColumn<QByteArray>("propertyName");
+    QTest::addColumn<QMargins>("padding");
+
+    QTest::newRow("top") << QByteArrayLiteral("paddingTop") << QMargins(0, 10, 0, 0);
+    QTest::newRow("right") << QByteArrayLiteral("paddingRight") << QMargins(0, 0, 10, 0);
+    QTest::newRow("bottom") << QByteArrayLiteral("paddingBottom") << QMargins(0, 0, 0, 10);
+    QTest::newRow("left") << QByteArrayLiteral("paddingLeft") << QMargins(10, 0, 0, 0);
+}
+
+void DecorationShadowTest::testPadding()
+{
+    using namespace KDecoration2;
+    DecorationShadow shadow;
+
+    QFETCH(QByteArray, propertyName);
+
+    const int propertyIndex = shadow.metaObject()->indexOfProperty(propertyName.constData());
+    QVERIFY(propertyIndex != -1);
+    QMetaProperty metaProperty = shadow.metaObject()->property(propertyIndex);
+    QCOMPARE(metaProperty.isReadable(), true);
+    QCOMPARE(metaProperty.hasNotifySignal(), true);
+    QCOMPARE(metaProperty.type(), QVariant::Int);
+    QSignalSpy changedSpy(&shadow, &KDecoration2::DecorationShadow::paddingChanged);
+    QVERIFY(changedSpy.isValid());
+
+    QCOMPARE(shadow.property(propertyName.constData()).isValid(), true);
+    QCOMPARE(shadow.property(propertyName.constData()).toInt(), 0);
+    QFETCH(QMargins, padding);
+    shadow.setPadding(padding);
+    QCOMPARE(shadow.padding(), padding);
+    QCOMPARE(shadow.property(propertyName.constData()).toInt(), 10);
+    QCOMPARE(changedSpy.count(), 1);
+
+    // trying to set to same value shouldn't emit the signal
+    shadow.setPadding(padding);
+    QCOMPARE(shadow.property(propertyName.constData()).toInt(), 10);
+    QCOMPARE(changedSpy.count(), 1);
+
+    // changing to different value should emit signal
+    padding += 1;
+    shadow.setPadding(padding);
+    QCOMPARE(shadow.padding(), padding);
+    QCOMPARE(shadow.property(propertyName.constData()).toInt(), 11);
+    QCOMPARE(changedSpy.count(), 2);
+}
+
+void DecorationShadowTest::testSizes_data()
+{
+    QTest::addColumn<QByteArray>("propertyName");
+    QTest::addColumn<QRect>("innerShadowRect");
+    QTest::addColumn<QRect>("shadowRect");
+    QTest::addColumn<QSize>("shadowSize");
+
+    QTest::newRow("topLeft") << QByteArrayLiteral("topLeftGeometry") << QRect(1, 2, 5, 5) << QRect(0, 0, 1, 2) << QSize(6, 7);
+    QTest::newRow("top") << QByteArrayLiteral("topGeometry") << QRect(1, 2, 1, 5) << QRect(1, 0, 1, 2) << QSize(3, 7);
+    QTest::newRow("topRight") << QByteArrayLiteral("topRightGeometry") << QRect(0, 2, 2, 1) << QRect(2, 0, 1, 2) << QSize(3, 3);
+    QTest::newRow("right") << QByteArrayLiteral("rightGeometry") << QRect(0, 0, 1, 2) << QRect(1, 0, 1, 2) << QSize(2, 4);
+    QTest::newRow("bottomRight") << QByteArrayLiteral("bottomRightGeometry") << QRect(0, 0, 1, 4) << QRect(1, 4, 1, 2) << QSize(2, 6);
+    QTest::newRow("bottom") << QByteArrayLiteral("bottomGeometry") << QRect(0, 0, 1, 1) << QRect(0, 1, 1, 2) << QSize(1, 3);
+    QTest::newRow("bottomLeft") << QByteArrayLiteral("bottomLeftGeometry") << QRect(1, 0, 1, 1) << QRect(0, 1, 1, 2) << QSize(2, 3);
+    QTest::newRow("left") << QByteArrayLiteral("leftGeometry") << QRect(1, 0, 1, 2) << QRect(0, 0, 1, 2) << QSize(2, 2);
+}
+
+void DecorationShadowTest::testSizes()
+{
+    using namespace KDecoration2;
+    DecorationShadow shadow;
+
+    QFETCH(QByteArray, propertyName);
+
+    const int propertyIndex = shadow.metaObject()->indexOfProperty(propertyName.constData());
+    QVERIFY(propertyIndex != -1);
+    QMetaProperty metaProperty = shadow.metaObject()->property(propertyIndex);
+    QCOMPARE(metaProperty.isReadable(), true);
+    QCOMPARE(metaProperty.hasNotifySignal(), true);
+    QCOMPARE(metaProperty.type(), QVariant::Rect);
+    QSignalSpy changedSpy(&shadow, &KDecoration2::DecorationShadow::innerShadowRectChanged);
+    QVERIFY(changedSpy.isValid());
+
+    QCOMPARE(shadow.innerShadowRect(), QRect());
+    QCOMPARE(shadow.property(propertyName.constData()).isValid(), true);
+    QCOMPARE(shadow.property(propertyName.constData()).toRect(), QRect());
+    QFETCH(QRect, innerShadowRect);
+    QFETCH(QRect, shadowRect);
+    QFETCH(QSize, shadowSize);
+    shadow.setInnerShadowRect(innerShadowRect);
+    QCOMPARE(shadow.innerShadowRect(), innerShadowRect);
+    // property should still be invalid as the image is not yet set
+    QCOMPARE(shadow.property(propertyName.constData()).toRect(), QRect());
+    shadow.setShadow(QImage(shadowSize, QImage::Format_ARGB32));
+    QCOMPARE(shadow.property(propertyName.constData()).toRect(), shadowRect);
+    QCOMPARE(changedSpy.count(), 1);
+
+    // trying to set to same value shouldn't emit the signal
+    shadow.setInnerShadowRect(innerShadowRect);
+    QCOMPARE(shadow.property(propertyName.constData()).toRect(), shadowRect);
+    QCOMPARE(changedSpy.count(), 1);
+
+    // changing to different value should emit signal
+    shadow.setInnerShadowRect(innerShadowRect.adjusted(1, 1, 1, 1));
+    QCOMPARE(changedSpy.count(), 2);
+    QCOMPARE(shadow.innerShadowRect(), innerShadowRect.adjusted(1, 1, 1, 1));
+}
+
+QTEST_MAIN(DecorationShadowTest)
+#include "shadowtest.moc"
diff --git a/metainfo.yaml b/metainfo.yaml
new file mode 100644 (file)
index 0000000..c3adf2c
--- /dev/null
@@ -0,0 +1,18 @@
+maintainer: graesslin
+fancyname: KDecoration2
+description: Plugin based library to create window decorations.
+irc: kwin
+mailinglist: kwin
+type: integration
+platforms:
+    - name: Linux
+    - name: FreeBSD
+portingAid: false
+deprecated: false
+release: false
+libraries:
+    - cmake: KDecoration2::KDecoration
+cmakename: KDecoration2
+group: plasma
+
+public_lib: true
diff --git a/po/ar/kdecoration.po b/po/ar/kdecoration.po
new file mode 100644 (file)
index 0000000..d1f9cfd
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Zayed Al-Saidi <zayed.alsaidi@gmail.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-03-16 12:41+0400\n"
+"Last-Translator: Zayed Al-Saidi <zayed.alsaidi@gmail.com>\n"
+"Language-Team: ar\n"
+"Language: ar\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
+"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "إجراءات أكثر لهذه النافذة"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "قائمة التّطبيق"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "على سطح مكتب واحد"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "على كلّ أسطح المكتب"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "صغّر"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "استعد"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "كبّر"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "أغلق"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "مساعدة السياقية"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "ألغ التظليل"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "ظلل"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "لا تبقها أسفل النوافذ الأخرى"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "أبقها أسفل النوافذ الأخرى"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "لا تبقها أعلى النوافذ الأخرى"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "أبقها أعلى النوافذ الأخرى"
diff --git a/po/ast/kdecoration.po b/po/ast/kdecoration.po
new file mode 100644 (file)
index 0000000..e0427ab
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Enol P. <enolp@softastur.org>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-05-03 23:37+0200\n"
+"Last-Translator: Enol P. <enolp@softastur.org>\n"
+"Language-Team: \n"
+"Language: ast\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 23.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr ""
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr ""
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr ""
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr ""
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr ""
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr ""
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr ""
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr ""
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr ""
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr ""
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr ""
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr ""
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr ""
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr ""
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr ""
diff --git a/po/az/kdecoration.po b/po/az/kdecoration.po
new file mode 100644 (file)
index 0000000..578deab
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Xəyyam Qocayev <xxmn77@gmail.com>, 2020, 2021, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2022-07-03 13:56+0400\n"
+"Last-Translator: Kheyyam <xxmn77@gmail.com>\n"
+"Language-Team: Azerbaijani <kde-i18n-doc@kde.org>\n"
+"Language: az\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 22.04.2\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Bu pəncərə üçün daha çox əməllər"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Tətbiq menyusu"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "İş masasında"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Bütün İş Masalarında"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Kiçiltmək"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Bərpa etmək"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Tam açmaq"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Bağlamaq"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Uyğun kömək"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Kölgəsiz"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Kölgə"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Digər pəncərələrin altında tutmamaq"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Digər pəncərələrin altında tutmaq"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Digər pəncərələrin üzərində tutmamaq"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Digər pəncərələrin üzərində tutmaq"
+
+#~ msgid "Menu"
+#~ msgstr "Menyu"
+
+#~ msgid "Keep below"
+#~ msgstr "Aşağıda tutmaq"
+
+#~ msgid "Keep above"
+#~ msgstr "Yuxarıda tutmaq"
diff --git a/po/bg/kdecoration.po b/po/bg/kdecoration.po
new file mode 100644 (file)
index 0000000..894391c
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Mincho Kondarev <mkondarev@yahoo.de>, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2022-05-20 19:35+0200\n"
+"Last-Translator: Mincho Kondarev <mkondarev@yahoo.de>\n"
+"Language-Team: Bulgarian <kde-i18n-doc@kde.org>\n"
+"Language: bg\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 22.04.0\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Допълнителни действия за този прозорец"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Меню на приложение"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "На един работен плот"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "На всички работни плотове"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Минимизиране"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Възстановяване"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Максимизиране"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Затваряне"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Контекстна помощ"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Разгъване"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Сгъване"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Без задържане под другите прозорци"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Задържане под другите прозорците"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Без задържане над другите прозорци"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Задържане над другите прозорци"
diff --git a/po/ca/kdecoration.po b/po/ca/kdecoration.po
new file mode 100644 (file)
index 0000000..b77859d
--- /dev/null
@@ -0,0 +1,98 @@
+# Translation of kdecoration.po to Catalan
+# Copyright (C) 2018-2021 This_file_is_part_of_KDE
+# This file is distributed under the license LGPL version 2.1 or
+# version 3 or later versions approved by the membership of KDE e.V.
+#
+# Josep M. Ferrer <txemaq@gmail.com>, 2018.
+# Empar Montoro Martín <montoro_mde@gva.es>, 2019.
+# Antoni Bella Pérez <antonibella5@yahoo.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 16:55+0200\n"
+"Last-Translator: Antoni Bella Pérez <antonibella5@yahoo.com>\n"
+"Language-Team: Catalan <kde-i18n-ca@kde.org>\n"
+"Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 20.12.3\n"
+"X-Accelerator-Marker: &\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Més accions per a aquesta finestra"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menú d'aplicacions"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "A un escriptori"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "A tots els escriptoris"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimitza"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaura"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximitza"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Tanca"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Ajuda contextual"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Desplega"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Plega"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "No mantinguis per sota de les altres finestres"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Mantén per sota de les altres finestres"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "No mantinguis al damunt de les altres finestres"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Mantén al damunt de les altres finestres"
diff --git a/po/ca@valencia/kdecoration.po b/po/ca@valencia/kdecoration.po
new file mode 100644 (file)
index 0000000..71a013a
--- /dev/null
@@ -0,0 +1,98 @@
+# Translation of kdecoration.po to Catalan (Valencian)
+# Copyright (C) 2018-2021 This_file_is_part_of_KDE
+# This file is distributed under the license LGPL version 2.1 or
+# version 3 or later versions approved by the membership of KDE e.V.
+#
+# Josep M. Ferrer <txemaq@gmail.com>, 2018.
+# Empar Montoro Martín <montoro_mde@gva.es>, 2019.
+# Antoni Bella Pérez <antonibella5@yahoo.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 16:55+0200\n"
+"Last-Translator: Antoni Bella Pérez <antonibella5@yahoo.com>\n"
+"Language-Team: Catalan <kde-i18n-ca@kde.org>\n"
+"Language: ca@valencia\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 20.12.3\n"
+"X-Accelerator-Marker: &\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Més accions per a esta finestra"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menú d'aplicacions"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "A un escriptori"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "A tots els escriptoris"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimitza"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaura"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximitza"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Tanca"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Ajuda contextual"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Desplega"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Plega"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "No mantinges per davall de les altres finestres"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Mantín per davall de les altres finestres"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "No mantinges al damunt de les altres finestres"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Mantín al damunt de les altres finestres"
diff --git a/po/cs/kdecoration.po b/po/cs/kdecoration.po
new file mode 100644 (file)
index 0000000..50e1655
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+# Vit Pelcak <vit@pelcak.org>, 2018, 2020, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-13 13:38+0200\n"
+"Last-Translator: Vit Pelcak <vpelcak@suse.cz>\n"
+"Language-Team: Czech <kde-i18n-doc@kde.org>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"X-Generator: Lokalize 21.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Více činností pro toto okno"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Nabídka aplikací"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Na pracovní ploše"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Na všech plochách"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimalizovat"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Obnovit"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximalizovat"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Zavřít"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontextová nápověda"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Rozbalit"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Sbalit"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Neponechat pod ostatními okny"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Ponechat pod ostatními okny"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Neponechat nad jinými okny"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Podržet nad jinými okny"
diff --git a/po/da/kdecoration.po b/po/da/kdecoration.po
new file mode 100644 (file)
index 0000000..4aa090e
--- /dev/null
@@ -0,0 +1,104 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Martin Schlander <mschlander@opensuse.org>, 2018, 2019.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2019-05-07 13:23+0100\n"
+"Last-Translator: Martin Schlander <mschlander@opensuse.org>\n"
+"Language-Team: Danish <kde-i18n-doc@kde.org>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 2.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr ""
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Programmenu"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "På et skrivebord"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "På alle skriveborde"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimér"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Genskab"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maksimér"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Luk"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Sammenhængsafhængig hjælp"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Skyg ikke"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Skyg"
+
+#: decorationbutton.cpp:329
+#, fuzzy, kde-format
+#| msgid "Don't keep below"
+msgid "Don't keep below other windows"
+msgstr "Hold ikke under"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr ""
+
+#: decorationbutton.cpp:334
+#, fuzzy, kde-format
+#| msgid "Don't keep above"
+msgid "Don't keep above other windows"
+msgstr "Hold ikke over"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr ""
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Hold under"
+
+#~ msgid "Keep above"
+#~ msgstr "Hold over"
diff --git a/po/de/kdecoration.po b/po/de/kdecoration.po
new file mode 100644 (file)
index 0000000..867838e
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Frederik Schwarzer <schwarzer@kde.org>, 2018.
+# Burkhard Lück <lueck@hube-lueck.de>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 05:59+0200\n"
+"Last-Translator: Burkhard Lück <lueck@hube-lueck.de>\n"
+"Language-Team: German <kde-i18n-de@kde.org>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Weitere Aktionen für dieses Fenster"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Anwendungsmenü"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Auf einer Arbeitsfläche"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Auf allen Arbeitsflächen"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimieren"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Wiederherstellen"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximieren"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Schließen"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontexthilfe"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Einrollen rückgängig"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Einrollen"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Nicht hinter anderen Fenstern halten"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Fenster im Hintergrund halten"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Nicht vor anderen Fenstern halten"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Fenster im Vordergrund halten"
+
+#~ msgid "Menu"
+#~ msgstr "Menü"
+
+#~ msgid "Keep below"
+#~ msgstr "Im Hintergrund halten"
+
+#~ msgid "Keep above"
+#~ msgstr "Im Vordergrund halten"
diff --git a/po/el/kdecoration.po b/po/el/kdecoration.po
new file mode 100644 (file)
index 0000000..84ea067
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Stelios <sstavra@gmail.com>, 2020, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-06-14 16:27+0300\n"
+"Last-Translator: Stelios <sstavra@gmail.com>\n"
+"Language-Team: Greek <kde-i18n-el@kde.org>\n"
+"Language: el\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 20.04.2\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Περισσότερες ενέργειες για αυτό το παράθυρο"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Μενού εφαρμογής"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Σε μία επιφάνεια εργασίας"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Σε όλες τις επιφάνειες εργασίας"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Ελαχιστοποίηση"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Επαναφορά"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Μεγιστοποίηση"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Κλείσιμο"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Βοήθεια στο κείμενο"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Αναίρεση σκίασης"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Σκίαση"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Να μη μείνει κάτω από άλλα παράθυρα"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Να μείνει κάτω από άλλα παράθυρα"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Να μη μείνει πάνω από άλλα παράθυρα"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Να μείνει πάνω από άλλα παράθυρα"
+
+#~ msgid "Menu"
+#~ msgstr "Μενού"
+
+#~ msgid "Keep below"
+#~ msgstr "Να μείνει από κάτω"
+
+#~ msgid "Keep above"
+#~ msgstr "Να μείνει από πάνω"
diff --git a/po/en_GB/kdecoration.po b/po/en_GB/kdecoration.po
new file mode 100644 (file)
index 0000000..3faba43
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Steve Allewell <steve.allewell@gmail.com>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-06-12 14:20+0100\n"
+"Last-Translator: Steve Allewell <steve.allewell@gmail.com>\n"
+"Language-Team: British English <kde-l10n-en_gb@kde.org>\n"
+"Language: en_GB\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 21.04.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "More actions for this window"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Application menu"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "On one desktop"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "On all desktops"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimise"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restore"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximise"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Close"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Context help"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Unshade"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Shade"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Do not keep below other windows"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Keep below other windows"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Do not keep above other windows"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Keep above other windows"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Keep below"
+
+#~ msgid "Keep above"
+#~ msgstr "Keep above"
diff --git a/po/eo/kdecoration.po b/po/eo/kdecoration.po
new file mode 100644 (file)
index 0000000..68b3acb
--- /dev/null
@@ -0,0 +1,92 @@
+# translation of kdecoration.pot to Esperanto
+# Copyright (C) 2017 Free Software Foundation, Inc.
+# Oliver Kellogg <olivermkellogg@gmail.com>, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-04-28 23:02+0100\n"
+"Last-Translator: Oliver Kellogg <olivermkellogg@gmail.com>\n"
+"Language-Team: Esperanto <kde-i18n-eo@kde.org>\n"
+"Language: eo\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Pliaj agoj por ĉi tiu fenestro"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Aplikaĵa menuo"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Sur unu labortablo"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Sur ĉiuj labortabloj"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimumigi"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaŭri"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maksimumigi"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Fermi"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kunteksta helpo"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Malombrigi"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Ombrigi"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ne teni sub aliaj fenestroj"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Teni sub aliaj fenestroj"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ne teni super aliaj fenestroj"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Teni super aliaj fenestroj"
diff --git a/po/es/kdecoration.po b/po/es/kdecoration.po
new file mode 100644 (file)
index 0000000..7ea8233
--- /dev/null
@@ -0,0 +1,104 @@
+# Spanish translations for kdecoration.po package.
+# Copyright (C) 2018 This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Automatically generated, 2018.
+# Eloy Cuadra <ecuadra@eloihr.net>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 12:13+0200\n"
+"Last-Translator: Eloy Cuadra <ecuadra@eloihr.net>\n"
+"Language-Team: Spanish <kde-l10n-es@kde.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 21.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Más acciones para esta ventana"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menú de la aplicación"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "En un escritorio"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "En todos los escritorios"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizar"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaurar"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximizar"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Cerrar"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Ayuda de contexto"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Desenrollar"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Enrollar"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "No mantener por debajo de otras ventanas"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Mantener por debajo de otras ventanas"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "No mantener por encima de otras ventanas"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Mantener por encima de otras ventanas"
+
+#~ msgid "Menu"
+#~ msgstr "Menú"
+
+#~ msgid "Keep below"
+#~ msgstr "Mantener por debajo"
+
+#~ msgid "Keep above"
+#~ msgstr "Mantener por encima"
diff --git a/po/et/kdecoration.po b/po/et/kdecoration.po
new file mode 100644 (file)
index 0000000..3b2949d
--- /dev/null
@@ -0,0 +1,104 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Marek Laane <qiilaq69@gmail.com>, 2019.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2019-11-08 21:30+0200\n"
+"Last-Translator: Marek Laane <qiilaq69@gmail.com>\n"
+"Language-Team: Estonian <kde-et@lists.linux.ee>\n"
+"Language: et\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 19.08.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr ""
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Rakenduste menüü"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Ühel töölaual"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Kõigil töölaudadel"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimeeri"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Taasta"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maksimeeri"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Sulge"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontekstiabi"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Keri lahti"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Keri kokku"
+
+#: decorationbutton.cpp:329
+#, fuzzy, kde-format
+#| msgid "Don't keep below"
+msgid "Don't keep below other windows"
+msgstr "Ära hoia teiste all"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr ""
+
+#: decorationbutton.cpp:334
+#, fuzzy, kde-format
+#| msgid "Don't keep above"
+msgid "Don't keep above other windows"
+msgstr "Ära hoia teiste peal"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr ""
+
+#~ msgid "Menu"
+#~ msgstr "Menüü"
+
+#~ msgid "Keep below"
+#~ msgstr "Hoia teiste all"
+
+#~ msgid "Keep above"
+#~ msgstr "Hoia teiste peal"
diff --git a/po/eu/kdecoration.po b/po/eu/kdecoration.po
new file mode 100644 (file)
index 0000000..1ce6b5a
--- /dev/null
@@ -0,0 +1,106 @@
+# Translation for kdecoration.po to Euskara/Basque (eu).
+# Copyright (C) 2018, Free Software Foundation, Inc.
+# Copyright (C) 2019-2021, This file is copyright:
+# This file is distributed under the same license as kdecoration package.
+# KDE euskaratzeko proiektuko arduraduna <xalba@ni.eus>.
+#
+# Translators:
+# Iñigo Salvador Azurmendi <xalba@ni.eus>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-07-26 19:57+0200\n"
+"Last-Translator: Iñigo Salvador Azurmendi <xalba@ni.eus>\n"
+"Language-Team: Basque <kde-i18n-eu@kde.org>\n"
+"Language: eu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 21.04.3\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Leiho honetarako ekintza gehiago"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Aplikazio-menua"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Mahaigain bakarrean"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Mahaigain guztietan"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizatu"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Lehengoratu"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximizatu"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Itxi"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Testuinguru-laguntza"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Zabaldu"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Bildu"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ez eutsi beste leihoen azpian"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Eutsi beste leihoen azpian"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ez eutsi beste leihoen gainean"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Eutsi beste leiho batzuen gainean"
+
+#~ msgid "Menu"
+#~ msgstr "Menua"
+
+#~ msgid "Keep below"
+#~ msgstr "Egon azpian"
+
+#~ msgid "Keep above"
+#~ msgstr "Egon gainean"
diff --git a/po/fi/kdecoration.po b/po/fi/kdecoration.po
new file mode 100644 (file)
index 0000000..61cb9fa
--- /dev/null
@@ -0,0 +1,101 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+# Tommi Nieminen <translator@legisign.org>, 2018, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-07 11:01+0300\n"
+"Last-Translator: Tommi Nieminen <translator@legisign.org>\n"
+"Language-Team: Finnish <kde-i18n-doc@kde.org>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Lisää toimintoja tälle ikkunalle"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Sovellusvalikko"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Yhdellä työpöydällä"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Kaikilla työpöydillä"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Pienennä"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Palauta"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Suurenna"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Sulje"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontekstiohje"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Avaa rullaus"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Rullaa"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Älä pidä muiden ikkunoiden alla"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Pidä muiden ikkunoiden alla"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Älä pidä muiden ikkunoiden yllä"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Pidä muiden ikkunoiden yllä"
+
+#~ msgid "Menu"
+#~ msgstr "Valikko"
+
+#~ msgid "Keep below"
+#~ msgstr "Pidä alinna"
+
+#~ msgid "Keep above"
+#~ msgstr "Pidä ylinnä"
diff --git a/po/fr/kdecoration.po b/po/fr/kdecoration.po
new file mode 100644 (file)
index 0000000..ac6926d
--- /dev/null
@@ -0,0 +1,103 @@
+# Yoann Laissus <yoann.laissus@gmail.com>, 2018.
+# Xavier Besnard <xavier.besnard@kde.org>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 13:56+0200\n"
+"Last-Translator: Xavier Besnard <xavier.besnard@neuf.fr>\n"
+"Language-Team: French <kde-francophone@kde.org>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Lokalize 21.04.0\n"
+"X-Environment: kde\n"
+"X-Accelerator-Marker: &\n"
+"X-Text-Markup: kde4\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Plus d'actions pour cette fenêtre"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu d'application"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Sur un seul bureau"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Sur tous les bureaux"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimiser"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaurer"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximiser"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Fermer"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Aide contextuelle"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Enlever l'ombrage"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Ombre"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ne pas conserver en dessous des autres fenêtres"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Conserver en dessous des autres fenêtres"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ne pas conserver en dessus des autres fenêtres"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Conserver en dessus des autres fenêtres"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Conserver au-dessous "
+
+#~ msgid "Keep above"
+#~ msgstr "Conserver au-dessus "
diff --git a/po/gl/kdecoration.po b/po/gl/kdecoration.po
new file mode 100644 (file)
index 0000000..16b5b38
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+# Adrián Chaves (Gallaecio) <adrian@chaves.io>, 2018, 2019, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-04-28 17:26+0200\n"
+"Last-Translator: Adrián Chaves (Gallaecio) <adrian@chaves.io>\n"
+"Language-Team: Galician <proxecto@trasno.gal>\n"
+"Language: gl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 23.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Máis accións para esta xanela"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menú das aplicacións"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Nun escritorio"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "En todos os escritorios"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizar"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaurar"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximizar"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Pechar"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Axuda contextual"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Desenrolar"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Enrolar"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Non manter debaixo doutras xanelas"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Manter debaixo doutras xanelas"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Non manter enriba doutras xanelas"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Manter enriba doutras xanelas"
+
+#~ msgid "Menu"
+#~ msgstr "Menú"
+
+#~ msgid "Keep below"
+#~ msgstr "Manter debaixo"
+
+#~ msgid "Keep above"
+#~ msgstr "Manter enriba"
diff --git a/po/he/kdecoration.po b/po/he/kdecoration.po
new file mode 100644 (file)
index 0000000..f6fc1c6
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (C) 2024 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# SPDX-FileCopyrightText: 2024 Yaron Shahrabani <sh.yaron@gmail.com>
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2024-03-19 08:16+0200\n"
+"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
+"Language-Team: צוות התרגום של KDE ישראל\n"
+"Language: he\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
+"n % 10 == 0) ? 2 : 3));\n"
+"X-Generator: Lokalize 23.08.5\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "פעולות נוספות לחלון הזה"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "תפריט היישום"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "בשולחן עבודה אחד"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "בכל שולחנות העבודה"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "מזעור"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "שחזור"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "הגדלה"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "סגירה"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "עזרה לפי הקשר"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "ביטול הצללה"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "הצללה"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "לא להסתיר מאחורי חלונות אחרים"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "להסתיר מאחורי חלונות אחרים"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "לא לקדם מעל חלונות אחרים"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "לקדם מעל חלונות אחרים"
diff --git a/po/hi/kdecoration.po b/po/hi/kdecoration.po
new file mode 100644 (file)
index 0000000..a94efad
--- /dev/null
@@ -0,0 +1,97 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Sameer Singh <lumarzeli30@gmail.com>, 2021.
+# Raghavendra Kamath <raghu@raghukamath.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-06-29 17:56+0530\n"
+"Last-Translator: Raghavendra Kamath <raghu@raghukamath.com>\n"
+"Language-Team: kde-hindi\n"
+"Language: hi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+"X-Generator: Lokalize 21.04.2\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "इस विंडो के लिए और क्रियाएँ"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "अनुप्रयोग मेन्यू"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "एक डेस्कटॉप पर"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "सभी डेस्कटॉप पर"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "न्यूनतम"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "पुरानी स्तिथी में लाऐं"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "अधिकतम"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "बंद करें"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "प्रासंगिक सहायता"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "छाया हटाएँ"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "छाया"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "अन्य विंडो के नीचे न रखें"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "अन्य विंडो के नीचे रखें"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "अन्य विंडो के ऊपर न रखें"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "अन्य विंडो के ऊपर रखें"
+
+#~ msgid "Menu"
+#~ msgstr "मेन्यू"
diff --git a/po/hu/kdecoration.po b/po/hu/kdecoration.po
new file mode 100644 (file)
index 0000000..98c4723
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Kristóf Kiszel <ulysses@kubuntu.org>, 2019.
+# Kristof Kiszel <ulysses@fsf.hu>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-11-24 13:23+0100\n"
+"Last-Translator: Kristof Kiszel <ulysses@fsf.hu>\n"
+"Language-Team: Hungarian <kde-l10n-hu@kde.org>\n"
+"Language: hu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 21.08.3\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "További műveletek"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Alkalmazásmenü"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Egy asztalon"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Az összes asztalra"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimalizálás"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Visszaállítás"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximalizálás"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Bezárás"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Helyi súgó"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Világosítás"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Árnyékolás"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ne maradjon más ablakok alatt"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Maradjon más ablakok alatt"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ne maradjon más ablakok fölött"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Maradjon más ablakok fölött"
+
+#~ msgid "Menu"
+#~ msgstr "Menü"
+
+#~ msgid "Keep below"
+#~ msgstr "Mindig alul"
+
+#~ msgid "Keep above"
+#~ msgstr "Mindig felül"
diff --git a/po/ia/kdecoration.po b/po/ia/kdecoration.po
new file mode 100644 (file)
index 0000000..60653cb
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Giovanni Sora <g.sora@tiscali.it>, 2019, 2020, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-11 23:13+0100\n"
+"Last-Translator: Giovanni Sora <g.sora@tiscali.it>\n"
+"Language-Team: Interlingua <kde-i18n-doc@kde.org>\n"
+"Language: ia\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 2.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Altere actiones per iste fenestra"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu de application"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Sur un scriptorio"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Super omne scriptorios"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimisa"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restabili"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximiza"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Claude"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Adjuta de contexto"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "De-Umbra"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Umbra"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Non mantene infra altere fenestras"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Mantene infra altere fenestras"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Non mantene supra altere fenestras"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Mantene supra altere fenestras"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Mantene infra"
+
+#~ msgid "Keep above"
+#~ msgstr "Mantene supra"
diff --git a/po/id/kdecoration.po b/po/id/kdecoration.po
new file mode 100644 (file)
index 0000000..54f53b2
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+# Wantoyo <wantoyek@gmail.com>, 2018, 2019, 2022.
+# Aziz Adam Adrian <4.adam.adrian@gmail.com>, 2022.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2022-09-27 17:54+0700\n"
+"Last-Translator: Wantoyèk <wantoyek@gmail.com>\n"
+"Language-Team: Indonesian <kde-i18n-doc@kde.org>\n"
+"Language: id\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 21.12.3\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Aksi selebihnya untuk jendela ini"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu aplikasi"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Pada satu desktop"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Pada semua desktop"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimalkan"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Kembalikan"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maksimalkan"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Tutup"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Bantuan konteks"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Tak bertirai"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Tiraikan"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Jangan tetap di bawah jendela lainnya"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Tetap di bawah jendela lainnya"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Jangan tetap di atas jendela lainnya"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Tetap di atas jendela lainnya"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Tetap di bawah"
+
+#~ msgid "Keep above"
+#~ msgstr "Tetap di atas"
diff --git a/po/is/kdecoration.po b/po/is/kdecoration.po
new file mode 100644 (file)
index 0000000..8da1019
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (C) 2024 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Sveinn í Felli <sv1@fellsnet.is>, 2023.
+# SPDX-FileCopyrightText: 2024 Guðmundur Erlingsson <gudmundure@gmail.com>
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2024-03-25 13:52+0000\n"
+"Last-Translator: Guðmundur Erlingsson <gudmundure@gmail.com>\n"
+"Language-Team: Icelandic <kde-i18n-doc@kde.org>\n"
+"Language: is\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 23.08.3\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Fleiri aðgerðir fyrir þennan glugga"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Forritavalmynd"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Á einu skjáborði"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Á öllum skjáborðum"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Fela"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Endurheimta"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Fullstækka"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Loka"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Samhengishjálp"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Rúlla niður"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Rúlla upp"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ekki hafa undir öðrum gluggum"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Hafa undir öðrum gluggum"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ekki hafa yfir öðrum gluggum"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Hafa yfir öðrum gluggum"
diff --git a/po/it/kdecoration.po b/po/it/kdecoration.po
new file mode 100644 (file)
index 0000000..1a40bb1
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the kdecoration package.
+# Paolo Zamponi <feus73@gmail.com>, 2018, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-12 08:49+0200\n"
+"Last-Translator: Paolo Zamponi <zapaolo@email.it>\n"
+"Language-Team: Italian <kde-i18n-it@kde.org>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Lokalize 21.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Altre azioni per questa finestra"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu dell'applicazione"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Su un desktop"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Su tutti i desktop"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizza"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Ripristina"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Massimizza"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Chiudi"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Aiuto contestuale"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Srotola"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Arrotola"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Non tenere sotto le altre finestre"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Tieni sotto le altre finestre"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Non tenere sopra le altre finestre"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Tieni sopra le altre finestre"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Tieni sotto"
+
+#~ msgid "Keep above"
+#~ msgstr "Tieni sopra"
diff --git a/po/ja/kdecoration.po b/po/ja/kdecoration.po
new file mode 100644 (file)
index 0000000..ce2f501
--- /dev/null
@@ -0,0 +1,93 @@
+# Tomohiro Hyakutake <tomhioo@outlook.jp>, 2019.
+# Ryuichi Yamada <ryuichi_ya220@outlook.jp>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-05-18 00:36+0900\n"
+"Last-Translator: Ryuichi Yamada <ryuichi_ya220@outlook.jp>\n"
+"Language-Team: Japanese <kde-jp@kde.org>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Accelerator-Marker: &\n"
+"X-Text-Markup: kde4\n"
+"X-Generator: Lokalize 23.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "このウィンドウに対するその他のアクション"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "アプリケーションメニュー"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "一つのデスクトップに表示"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "すべてのデスクトップに表示"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "最小化"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "復元"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "最大化"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "閉じる"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "コンテキストヘルプ"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "シェード解除"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "シェード"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "他のウィンドウの下に保持しない"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "他のウィンドウより下に表示"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "他のウィンドウの上に保持しない"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "他のウィンドウより上に表示"
diff --git a/po/ka/kdecoration.po b/po/ka/kdecoration.po
new file mode 100644 (file)
index 0000000..6744058
--- /dev/null
@@ -0,0 +1,94 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2022-05-21 14:43+0200\n"
+"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
+"Language-Team: Georgian <kde-i18n-doc@kde.org>\n"
+"Language: ka\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 3.0.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "მეტი ქმედება ამ ფანჯრისთვის"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "პროგრამის მენიუ"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "1 სამუშაო მაგიდაზე"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "ყველა სამუშაო მაგიდაზე"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "ჩაკეცვა"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "აღდგენა"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "გადიდება"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "დახურვა"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "კონტექსტური დახმარება"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "განჩრდილვა"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "დაჩრდილვა"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "დანარჩენი ფანჯრების ქვემოთ ქონის გამორთვა"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "დანარჩენი ფანჯრების ქვემოთ ქონა"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "დანარჩენი ფანჯრების ზემოთ ქონის გამორთვა"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "დანარჩენი ფანჯრების ზემოთ ქონა"
diff --git a/po/ko/kdecoration.po b/po/ko/kdecoration.po
new file mode 100644 (file)
index 0000000..a465021
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+# Shinjo Park <kde@peremen.name>, 2018, 2020, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-16 21:48+0200\n"
+"Last-Translator: Shinjo Park <kde@peremen.name>\n"
+"Language-Team: Korean <kde-kr@kde.org>\n"
+"Language: ko\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Lokalize 20.12.3\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "이 창의 더 많은 동작"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "앱 메뉴"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "한 바탕 화면에만"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "모든 바탕 화면에 두기"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "최소화"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "복원"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "최대화"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "닫기"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "문맥 도움말"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "풀어 내리기"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "말아 올리기"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "다른 창 아래에 두지 않기"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "다른 창 아래에 두기"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "다른 창 위에 두지 않기"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "다른 창 위에 두기"
+
+#~ msgid "Menu"
+#~ msgstr "메뉴"
+
+#~ msgid "Keep below"
+#~ msgstr "항상 아래에 두기"
+
+#~ msgid "Keep above"
+#~ msgstr "항상 위에 두기"
diff --git a/po/lt/kdecoration.po b/po/lt/kdecoration.po
new file mode 100644 (file)
index 0000000..b88c1e3
--- /dev/null
@@ -0,0 +1,104 @@
+# Lithuanian translations for kdecoration package.
+# Copyright (C) 2019 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+# Automatically generated, 2019.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-06-15 22:43+0300\n"
+"Last-Translator: Moo\n"
+"Language-Team: lt\n"
+"Language: lt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10>=2 && (n%100<10 || n"
+"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3);\n"
+"X-Generator: Poedit 3.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Daugiau veiksmų šiam langui"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Programos meniu"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Viename darbalaukyje"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Visuose darbalaukiuose"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Suskleisti"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Grąžinti iš suskleidimo"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Išskleisti"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Užverti"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontekstinė pagalba"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Rodyti ne tik lango antraštės juostą"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Rodyti tik lango antraštės juostą"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Nelaikyti po kitais langais"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Laikyti po kitais langais"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Nelaikyti virš kitų langų"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Laikyti virš kitų langų"
+
+#~ msgid "Menu"
+#~ msgstr "Meniu"
+
+#~ msgid "Keep below"
+#~ msgstr "Laikyti apačioje"
+
+#~ msgid "Keep above"
+#~ msgstr "Laikyti viršuje"
diff --git a/po/lv/kdecoration.po b/po/lv/kdecoration.po
new file mode 100644 (file)
index 0000000..3410bd6
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (C) 2024 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# SPDX-FileCopyrightText: 2024 Toms Trasūns <toms.trasuns@posteo.net>
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2024-01-27 12:55+0200\n"
+"Last-Translator: Toms Trasūns <toms.trasuns@posteo.net>\n"
+"Language-Team: Latvian <kde-i18n-doc@kde.org>\n"
+"Language: lv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : "
+"2);\n"
+"X-Generator: Lokalize 23.08.4\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Vairāk darbību šim logam"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Programmas izvēlne"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Uz vienas darbvirsmas"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Uz visām darbvirsmām"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizēt"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Atjaunot"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maksimizēt"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Aizvērt"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Konteksta palīdzība"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Atritināt"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Saritināt"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Neturēt zem citiem logiem"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Turēt zem citiem logiem"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Neturēt virs citiem logiem"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Turēt virs citiem logiem"
diff --git a/po/ml/kdecoration.po b/po/ml/kdecoration.po
new file mode 100644 (file)
index 0000000..8a1cbbb
--- /dev/null
@@ -0,0 +1,94 @@
+# Malayalam translations for kdecoration package.
+# Copyright (C) 2019 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+# Automatically generated, 2019.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2018-08-16 09:14+0200\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: Swathanthra|സ്വതന്ത്ര Malayalam|മലയാളം Computing|കമ്പ്യൂട്ടിങ്ങ് <smc."
+"org.in>\n"
+"Language: ml\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr ""
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr ""
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr ""
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr ""
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr ""
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr ""
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr ""
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr ""
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr ""
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr ""
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr ""
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr ""
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr ""
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr ""
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr ""
diff --git a/po/nl/kdecoration.po b/po/nl/kdecoration.po
new file mode 100644 (file)
index 0000000..960e01b
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Freek de Kruijf <freekdekruijf@kde.nl>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 09:39+0200\n"
+"Last-Translator: Freek de Kruijf <freekdekruijf@kde.nl>\n"
+"Language-Team: Dutch <kde-i18n-nl@kde.org>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 21.04.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Meer acties voor dit venster"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu van toepassing"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Op één bureaublad"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Op alle bureaubladen"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimaliseren"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Herstellen"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximaliseren"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Sluiten"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Contexthelp"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Schaduw weghalen"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Oprollen"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Niet onder andere vensters houden"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Onder andere vensters houden"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Niet boven andere vensters houden"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Boven andere vensters houden"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Altijd op achtergrond"
+
+#~ msgid "Keep above"
+#~ msgstr "Altijd op voorgrond"
diff --git a/po/nn/kdecoration.po b/po/nn/kdecoration.po
new file mode 100644 (file)
index 0000000..53ad5b0
--- /dev/null
@@ -0,0 +1,96 @@
+# Translation of kdecoration to Norwegian Nynorsk
+#
+# Karl Ove Hufthammer <karl@huftis.org>, 2018, 2022.
+# Øystein Steffensen-Alværvik <oysteins.omsetting@protonmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2022-06-19 13:54+0200\n"
+"Last-Translator: Karl Ove Hufthammer <karl@huftis.org>\n"
+"Language-Team: Norwegian Nynorsk <l10n-no@lister.huftis.org>\n"
+"Language: nn\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 22.04.2\n"
+"X-Environment: kde\n"
+"X-Accelerator-Marker: &\n"
+"X-Text-Markup: kde4\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Fleire handlingar for vindauget"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Programmeny"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "På eitt skrivebord"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "På alle skriveborda"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimer"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Gjenopprett"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maksimer"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Lukk"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Emnehjelp"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Rull ned"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Rull opp"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ikkje hald under andre vindauge"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Hald under andre vindauge"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ikkje hald over andre vindauge"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Hald over andre vindauge"
diff --git a/po/pa/kdecoration.po b/po/pa/kdecoration.po
new file mode 100644 (file)
index 0000000..7a62f1e
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# A S Alam <aalam@satluj.org>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-05-19 20:09-0700\n"
+"Last-Translator: A S Alam <aalam@satluj.org>\n"
+"Language-Team: Punjabi <kde-i18n-doc@kde.org>\n"
+"Language: pa\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 23.04.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "ਇਸ ਵਿੰਡੋ ਲਈ ਹੋਰ ਕਾਰਵਾਈਆਂ"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "ਐਪਲੀਕੇਸ਼ਨ ਮੇਨੂ"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "ਇੱਕ ਡੈਸਕਟਾਪ ਉੱਤੇ"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "ਸਾਰੇ ਡੈਸਕਟਾਪਾਂ ਉੱਤੇ"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "ਘੱਟੋ-ਘੱਟ"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "ਬਹਾਲ ਕਰੋ"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "ਵੱਧੋ-ਵੱਧ"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "ਬੰਦ ਕਰੋ"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "ਪ੍ਰਸੰਗ ਮਦਦ"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "ਬਿਨਾਂ-ਸ਼ੇਡ"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "ਸ਼ੇਡ"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "ਹੋਰ ਵਿੰਡੋਆਂ ਦੇ ਹੇਠਾਂ ਨਾ ਰੱਖੋ"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "ਹੋਰ ਵਿੰਡੋਆਂ ਦੇ ਹੇਠਾਂ ਰੱਖੋ"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "ਹੋਰ ਵਿੰਡੋਆਂ ਦੇ ਉੱਤੇ ਨਾ ਰੱਖੋ"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "ਹੋਰ ਵਿੰਡੋਆਂ ਦੇ ਉੱਤੇ ਰੱਖੋ"
diff --git a/po/pl/kdecoration.po b/po/pl/kdecoration.po
new file mode 100644 (file)
index 0000000..623196f
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-12-30 13:22+0100\n"
+"Last-Translator: Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>\n"
+"Language-Team: Polish <kde-i18n-doc@kde.org>\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Więcej działań dla tego okna"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu programów"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Na pulpicie"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Na wszystkich pulpitach"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Zminimalizuj"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Przywróć"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Zmaksymalizuj"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Zamknij"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Pomoc podręczna"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Rozwiń"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Zwiń"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Nie utrzymuj pod innymi oknami"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Utrzymuj pod innymi oknami"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Nie utrzymuj nad innymi oknami"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Utrzymuj nad innymi oknami"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Zawsze pod spodem"
+
+#~ msgid "Keep above"
+#~ msgstr "Zawsze na wierzchu"
diff --git a/po/pt/kdecoration.po b/po/pt/kdecoration.po
new file mode 100644 (file)
index 0000000..995ac14
--- /dev/null
@@ -0,0 +1,88 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-06 16:43+0100\n"
+"Last-Translator: José Nuno Coelho Pires <zepires@gmail.com>\n"
+"Language-Team: Portuguese <kde-i18n-pt@kde.org>\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Mais acções para esta janela"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu da aplicação"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Num ecrã"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Em todos os ecrãs"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizar"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Repor"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximizar"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Fechar"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Ajuda de contexto"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Desenrolar"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Enrolar"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Não manter abaixo das outras janelas"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Manter abaixo das outras janelas"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Não manter acima das outras janelas"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Manter acima das outras janelas"
diff --git a/po/pt_BR/kdecoration.po b/po/pt_BR/kdecoration.po
new file mode 100644 (file)
index 0000000..4113caa
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Luiz Fernando Ranghetti <elchevive@opensuse.org>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-06 14:05-0300\n"
+"Last-Translator: Luiz Fernando Ranghetti <elchevive@opensuse.org>\n"
+"Language-Team: Brazilian Portuguese <kde-i18n-pt_BR@kde.org>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Lokalize 20.04.2\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Mais ações para esta janela"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Menu do aplicativo"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Em uma área de trabalho"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Em todas as áreas de trabalho"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizar"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restaurar"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximizar"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Fechar"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Ajuda de contexto"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Sem sombras"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Sombrear"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Não manter abaixo de outras janelas"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Manter abaixo de outras janelas"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Não manter acima de outras janelas"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Manter acima de outras janelas"
+
+#~ msgid "Menu"
+#~ msgstr "Menu"
+
+#~ msgid "Keep below"
+#~ msgstr "Manter abaixo"
+
+#~ msgid "Keep above"
+#~ msgstr "Manter acima"
diff --git a/po/ro/kdecoration.po b/po/ro/kdecoration.po
new file mode 100644 (file)
index 0000000..2052a70
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+# Sergiu Bivol <sergiu@cip.md>, 2020, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-06-02 20:19+0100\n"
+"Last-Translator: Sergiu Bivol <sergiu@cip.md>\n"
+"Language-Team: Romanian\n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
+"20)) ? 1 : 2;\n"
+"X-Generator: Lokalize 19.12.3\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Acțiuni suplimentare pentru această fereastră"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Meniul aplicației"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Pe un birou"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Pe toate birourile"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimizează"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Restabilește"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximizează"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Închide"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Ajutor contextual"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Desfășoară"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Strânge"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Nu ține sub alte ferestre"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Ține sub alte ferestre"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Nu ține deasupra altor ferestre"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Ține deasupra altor ferestre"
+
+#~ msgid "Menu"
+#~ msgstr "Meniu"
+
+#~ msgid "Keep below"
+#~ msgstr "Ține dedesubt"
+
+#~ msgid "Keep above"
+#~ msgstr "Ține deasupra"
diff --git a/po/ru/kdecoration.po b/po/ru/kdecoration.po
new file mode 100644 (file)
index 0000000..afb429a
--- /dev/null
@@ -0,0 +1,104 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Alexander Potashev <aspotashev@gmail.com>, 2018.
+# Alexander Yavorsky <kekcuha@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-06-08 16:54+0300\n"
+"Last-Translator: Alexander Yavorsky <kekcuha@gmail.com>\n"
+"Language-Team: Russian <kde-russian@lists.kde.ru>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n"
+"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Lokalize 21.04.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Дополнительные действия для этого окна"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Меню приложения"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "На одном рабочем столе"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "На всех рабочих столах"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Свернуть"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Восстановить"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Распахнуть"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Закрыть"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Контекстная справка"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Развернуть из заголовка"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Свернуть в заголовок"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Не удерживать ниже других окон"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Удерживать ниже других окон"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Не удерживать поверх других окон"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Удерживать поверх других окон"
+
+#~ msgid "Menu"
+#~ msgstr "Меню"
+
+#~ msgid "Keep below"
+#~ msgstr "Поддерживать на заднем плане"
+
+#~ msgid "Keep above"
+#~ msgstr "Поддерживать поверх других"
diff --git a/po/sa/kdecoration.po b/po/sa/kdecoration.po
new file mode 100644 (file)
index 0000000..8c8a827
--- /dev/null
@@ -0,0 +1,94 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-09-27 19:49+0530\n"
+"Last-Translator: \n"
+"Language-Team: Sanskrit <kde-i18n-doc@kde.org>\n"
+"Language: sa\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.3.2\n"
+"Plural-Forms: nplurals=2; plural=(n>2);\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "अस्य गवाक्ष कृते अधिकानि क्रियाणि"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "अनुप्रयोग सूचि"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "एकस्मिन् कार्यमुखे"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "सर्वेषु कार्यमुखेषु"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "न्यूनतमं करोतु"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "निर्यत्"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "अधिकतमं कुर्वन्तु"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "निमील्यताम्"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "सन्दर्भ सहाय्यम्"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "अनच्छाया"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "छाया"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "अन्येषां गवाक्षानां अधः न स्थापयन्तु"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "अन्येषां गवाक्षानां अधः स्थापयन्तु"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "अन्येषां गवाक्षानां उपरि न स्थापयन्तु"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "अन्येषां गवाक्षानां उपरि स्थापयन्तु"
diff --git a/po/sk/kdecoration.po b/po/sk/kdecoration.po
new file mode 100644 (file)
index 0000000..2bb8654
--- /dev/null
@@ -0,0 +1,101 @@
+# translation of kdecoration.po Slovak
+# Roman Paholík <wizzardsk@gmail.com>, 2018.
+# Matej Mrenica <matejm98mthw@gmail.com>, 2019, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-07-20 17:50+0200\n"
+"Last-Translator: Matej Mrenica <matejm98mthw@gmail.com>\n"
+"Language-Team: Slovak <kde-i18n-doc@kde.org>\n"
+"Language: sk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 21.07.80\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Viac akcií pre toto okno"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Aplikačná ponuka"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Na jednej ploche"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Na všetkých plochách"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimalizovať"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Obnoviť"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximalizovať"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Zavrieť"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontextový pomocník"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Odtieňovať"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Tieňovať"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Nedržať pod ostatnými oknami"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Držať pod ostatnými oknami"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Nedržať nad ostatnými oknami"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Držať nad ostatnými oknami"
+
+#~ msgid "Menu"
+#~ msgstr "Ponuka"
+
+#~ msgid "Keep below"
+#~ msgstr "Držať pod"
+
+#~ msgid "Keep above"
+#~ msgstr "Držať nad"
diff --git a/po/sl/kdecoration.po b/po/sl/kdecoration.po
new file mode 100644 (file)
index 0000000..6256e31
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# Matjaž Jeran <matjaz.jeran@amis.net>, 2020, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-08 08:39+0200\n"
+"Last-Translator: Matjaž Jeran <matjaz.jeran@amis.net>\n"
+"Language-Team: Slovenian <lugos-slo@lugos.si>\n"
+"Language: sl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 20.12.2\n"
+"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n"
+"%100==4 ? 3 : 0);\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Več dejavnosti za to okno"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Meni aplikacije"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Na enem namizju"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Na vseh namizjih"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Strni"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Obnovi"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Razpni"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Zapri"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Kontekstna pomoč"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Odpravi senčenje"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Osenči"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Ne zadržuj pod drugimi okni"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Zadržuj pod drugimi okni"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Ne zadržuj nad drugimi okni"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Zadržuj nad drugimi okni"
+
+#~ msgid "Menu"
+#~ msgstr "Meni"
+
+#~ msgid "Keep below"
+#~ msgstr "Zadržuj spodaj"
+
+#~ msgid "Keep above"
+#~ msgstr "Zadržuj na vrhu"
diff --git a/po/sv/kdecoration.po b/po/sv/kdecoration.po
new file mode 100644 (file)
index 0000000..ac90980
--- /dev/null
@@ -0,0 +1,102 @@
+# Copyright (C) YEAR This_file_is_part_of_KDE
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Stefan Asserhäll <stefan.asserhall@gmail.com>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 08:09+0200\n"
+"Last-Translator: Stefan Asserhäll <stefan.asserhall@gmail.com>\n"
+"Language-Team: Swedish <kde-i18n-doc@kde.org>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 20.08.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Fler åtgärder för fönstret"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Programmeny"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "På ett skrivbord"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "På alla skrivbord"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Minimera"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Återställ"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Maximera"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Stäng"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Sammanhangsberoende hjälp"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Rulla ner"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Rulla upp"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Behåll inte under andra fönster"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Behåll under andra fönster"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Behåll inte över andra fönster"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Behåll över andra fönster"
+
+#~ msgid "Menu"
+#~ msgstr "Meny"
+
+#~ msgid "Keep below"
+#~ msgstr "Behåll under"
+
+#~ msgid "Keep above"
+#~ msgstr "Behåll över"
diff --git a/po/ta/kdecoration.po b/po/ta/kdecoration.po
new file mode 100644 (file)
index 0000000..7c7263a
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) 2024 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# SPDX-FileCopyrightText: 2024 Kishore G <kishore96@gmail.com>
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2024-06-30 12:37+0530\n"
+"Last-Translator: Kishore G <kishore96@gmail.com>\n"
+"Language-Team: Tamil <kde-i18n-doc@kde.org>\n"
+"Language: ta\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 24.05.1\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "இச்சாளரத்திற்கான கூடுதல் செயல்கள்"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "செயலி பட்டி"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "ஒரு பணிமேடையில்"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "அனைத்து பணிமேடைகளிலும்"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "ஒதுக்கு"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "மீட்டெடு"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "அதிகபட்ச பெரிதாக்கு"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "மூடு"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "சூழலை பொறுத்த உதவி"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "நிழல்நீக்கு"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "நிழலிடு"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "மற்ற சாளரங்களுக்கு கீழே வைக்க வேண்டாம்"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "மற்ற சாளரங்களுக்கு கீழே வை"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "மற்ற சாளரங்களுக்கு மேலே வைக்க வேண்டாம்"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "மற்ற சாளரங்களுக்கு மேலே வை"
diff --git a/po/tr/kdecoration.po b/po/tr/kdecoration.po
new file mode 100644 (file)
index 0000000..084b543
--- /dev/null
@@ -0,0 +1,93 @@
+# Copyright (C) 2024 This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# SPDX-FileCopyrightText: 2022, 2023, 2024 Emir SARI <emir_sari@icloud.com>
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2024-06-20 13:53+0300\n"
+"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
+"Language-Team: Turkish <kde-l10n-tr@kde.org>\n"
+"Language: tr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Lokalize 24.07.70\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Bu pencere için daha fazla eylem"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Uygulama menüsü"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "Bir masaüstünde"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "Tüm masaüstlerinde"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Simge Durumuna Küçült"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Eski Haline Döndür"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Ekranı Kapla"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Kapat"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Bağlam Yardımı"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Panjuru Aç"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Panjuru Kapat"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Diğer pencerelerin altında tutma"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Diğer pencerelerin altında tut"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Diğer pencerelerin üzerinde tutma"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Diğer pencerelerin üzerinde tut"
diff --git a/po/uk/kdecoration.po b/po/uk/kdecoration.po
new file mode 100644 (file)
index 0000000..2259ad4
--- /dev/null
@@ -0,0 +1,105 @@
+# Translation of kdecoration.po to Ukrainian
+# Copyright (C) 2018 This_file_is_part_of_KDE
+# This file is distributed under the license LGPL version 2.1 or
+# version 3 or later versions approved by the membership of KDE e.V.
+#
+# Yuri Chornoivan <yurchor@ukr.net>, 2018, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2021-05-05 08:29+0300\n"
+"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
+"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
+"Language: uk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n"
+"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Lokalize 20.12.0\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "Додаткові дії для цього вікна"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "Меню програм"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "На одній стільниці"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "На всіх стільницях"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "Мінімізувати"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "Відновити"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "Максимізувати"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "Закрити"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "Контекстна довідка"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "Розгорнути"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "Згорнути"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "Не утримувати під іншими вікнами"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "Утримувати під іншими вікнами"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "Не утримувати над іншими вікнами"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "Утримувати над іншими вікнами"
+
+#~ msgid "Menu"
+#~ msgstr "Меню"
+
+#~ msgid "Keep below"
+#~ msgstr "Тримати знизу"
+
+#~ msgid "Keep above"
+#~ msgstr "Тримати зверху"
diff --git a/po/zh_CN/kdecoration.po b/po/zh_CN/kdecoration.po
new file mode 100644 (file)
index 0000000..9430595
--- /dev/null
@@ -0,0 +1,93 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: kdeorg\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2024-04-22 15:58\n"
+"Last-Translator: \n"
+"Language-Team: Chinese Simplified\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Crowdin-Project: kdeorg\n"
+"X-Crowdin-Project-ID: 269464\n"
+"X-Crowdin-Language: zh-CN\n"
+"X-Crowdin-File: /kf6-stable/messages/kdecoration/kdecoration.pot\n"
+"X-Crowdin-File-ID: 52644\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "此窗口的更多操作"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "应用程序菜单"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "在一个桌面"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "在全部桌面"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "最小化"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "还原"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "最大化"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "关闭"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "相关帮助"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "展开"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "折叠"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "不要保持在其他窗口之下"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "保持在其他窗口之下"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "不要保持在其他窗口之上"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "保持在其他窗口之上"
diff --git a/po/zh_TW/kdecoration.po b/po/zh_TW/kdecoration.po
new file mode 100644 (file)
index 0000000..a18cb9a
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (C) YEAR This file is copyright:
+# This file is distributed under the same license as the kdecoration package.
+#
+# pan93412 <pan93412@gmail.com>, 2019.
+# Kisaragi Hiu <mail@kisaragi-hiu.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: kdecoration\n"
+"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
+"POT-Creation-Date: 2024-02-10 00:40+0000\n"
+"PO-Revision-Date: 2023-02-02 23:03+0900\n"
+"Last-Translator: Kisaragi Hiu <mail@kisaragi-hiu.com>\n"
+"Language-Team: Traditional Chinese <zh-l10n@linux.org.tw>\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Lokalize 23.03.70\n"
+
+#: decorationbutton.cpp:303
+#, kde-format
+msgid "More actions for this window"
+msgstr "這個視窗的更多動作"
+
+#: decorationbutton.cpp:305
+#, kde-format
+msgid "Application menu"
+msgstr "應用程式選單"
+
+#: decorationbutton.cpp:308
+#, kde-format
+msgid "On one desktop"
+msgstr "僅在一個桌面上顯示"
+
+#: decorationbutton.cpp:310
+#, kde-format
+msgid "On all desktops"
+msgstr "在所有桌面上顯示"
+
+#: decorationbutton.cpp:312
+#, kde-format
+msgid "Minimize"
+msgstr "最小化"
+
+#: decorationbutton.cpp:315
+#, kde-format
+msgid "Restore"
+msgstr "回復大小"
+
+#: decorationbutton.cpp:317
+#, kde-format
+msgid "Maximize"
+msgstr "最大化"
+
+#: decorationbutton.cpp:319
+#, kde-format
+msgid "Close"
+msgstr "關閉"
+
+#: decorationbutton.cpp:321
+#, kde-format
+msgid "Context help"
+msgstr "內容說明"
+
+#: decorationbutton.cpp:324
+#, kde-format
+msgid "Unshade"
+msgstr "取消收起"
+
+#: decorationbutton.cpp:326
+#, kde-format
+msgid "Shade"
+msgstr "收起"
+
+#: decorationbutton.cpp:329
+#, kde-format
+msgid "Don't keep below other windows"
+msgstr "不要維持在其他視窗之下"
+
+#: decorationbutton.cpp:331
+#, kde-format
+msgid "Keep below other windows"
+msgstr "維持在其他視窗之下"
+
+#: decorationbutton.cpp:334
+#, kde-format
+msgid "Don't keep above other windows"
+msgstr "不要維持在其他視窗之上"
+
+#: decorationbutton.cpp:336
+#, kde-format
+msgid "Keep above other windows"
+msgstr "維持在其他視窗之上"
+
+#~ msgid "Menu"
+#~ msgstr "選單"
+
+#~ msgid "Keep below"
+#~ msgstr "保持於底部顯示"
+
+#~ msgid "Keep above"
+#~ msgstr "保持於頂部顯示"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..eb07869
--- /dev/null
@@ -0,0 +1,82 @@
+add_definitions(-DTRANSLATION_DOMAIN=\"kdecoration\")
+
+add_subdirectory(private)
+
+set(libkdecoration2_SRCS
+    decoratedclient.cpp
+    decoratedclient.h
+    decorationbutton.cpp
+    decorationbuttongroup.cpp
+    decorationbuttongroup.h
+    decorationbuttongroup_p.h
+    decorationbutton.h
+    decorationbutton_p.h
+    decoration.cpp
+    decorationdefines.h
+    decoration.h
+    decoration_p.h
+    decorationsettings.cpp
+    decorationsettings.h
+    decorationshadow.cpp
+    decorationshadow.h
+    decorationshadow_p.h
+    decorationthemeprovider.cpp
+    decorationthemeprovider.h
+
+)
+
+add_library(kdecorations2 SHARED ${libkdecoration2_SRCS})
+ecm_generate_export_header(kdecorations2
+    VERSION ${PROJECT_VERSION}
+    EXPORT_FILE_NAME kdecoration2/kdecoration2_export.h
+    DEPRECATION_VERSIONS 5.21
+    EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
+)
+
+add_library(KDecoration2::KDecoration ALIAS kdecorations2)
+
+target_link_libraries(kdecorations2
+    PUBLIC
+        Qt::Core
+        Qt::Gui
+    PRIVATE
+        kdecorations2private
+        KF6::I18n
+)
+
+target_include_directories(kdecorations2 INTERFACE "$<INSTALL_INTERFACE:${KDECORATION2_INCLUDEDIR}>" )
+
+set_target_properties(kdecorations2 PROPERTIES VERSION   ${KDECORATION2_VERSION}
+                                               SOVERSION ${KDECORATION2_SOVERSION}
+                                               EXPORT_NAME KDecoration
+)
+
+ecm_generate_headers(KDecoration2_CamelCase_HEADERS
+  HEADER_NAMES
+    DecoratedClient
+    Decoration
+    DecorationButton
+    DecorationButtonGroup
+    DecorationSettings
+    DecorationShadow
+    DecorationThemeProvider
+  PREFIX
+    KDecoration2
+  REQUIRED_HEADERS KDecoration2_HEADERS
+)
+install(FILES ${KDecoration2_CamelCase_HEADERS}
+        DESTINATION ${KDECORATION2_INCLUDEDIR}/KDecoration2
+        COMPONENT Devel)
+
+install(TARGETS kdecorations2 EXPORT KDecoration2Targets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
+
+install(
+    FILES
+        ${CMAKE_CURRENT_BINARY_DIR}/kdecoration2/kdecoration2_export.h
+        ${KDecoration2_HEADERS}
+        decorationdefines.h
+    DESTINATION
+        ${KDECORATION2_INCLUDEDIR}/kdecoration2
+    COMPONENT
+        Devel
+)
diff --git a/src/Messages.sh b/src/Messages.sh
new file mode 100644 (file)
index 0000000..f0f2522
--- /dev/null
@@ -0,0 +1,2 @@
+#! /usr/bin/env bash
+$XGETTEXT *.cpp -o $podir/kdecoration.pot
diff --git a/src/decoratedclient.cpp b/src/decoratedclient.cpp
new file mode 100644 (file)
index 0000000..e823c0d
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decoratedclient.h"
+#include "private/decoratedclientprivate.h"
+#include "private/decorationbridge.h"
+
+#include <QColor>
+
+namespace KDecoration2
+{
+DecoratedClient::DecoratedClient(Decoration *parent, DecorationBridge *bridge)
+    : QObject()
+    , d(bridge->createClient(this, parent))
+{
+}
+
+DecoratedClient::~DecoratedClient() = default;
+
+bool DecoratedClient::isActive() const
+{
+    return d->isActive();
+}
+
+QString DecoratedClient::caption() const
+{
+    return d->caption();
+}
+
+bool DecoratedClient::isOnAllDesktops() const
+{
+    return d->isOnAllDesktops();
+}
+
+bool DecoratedClient::isShaded() const
+{
+    return d->isShaded();
+}
+
+QIcon DecoratedClient::icon() const
+{
+    return d->icon();
+}
+
+bool DecoratedClient::isMaximized() const
+{
+    return d->isMaximized();
+}
+
+bool DecoratedClient::isMaximizedHorizontally() const
+{
+    return d->isMaximizedHorizontally();
+}
+
+bool DecoratedClient::isMaximizedVertically() const
+{
+    return d->isMaximizedVertically();
+}
+
+bool DecoratedClient::isKeepAbove() const
+{
+    return d->isKeepAbove();
+}
+
+bool DecoratedClient::isKeepBelow() const
+{
+    return d->isKeepBelow();
+}
+
+bool DecoratedClient::isCloseable() const
+{
+    return d->isCloseable();
+}
+
+bool DecoratedClient::isMaximizeable() const
+{
+    return d->isMaximizeable();
+}
+
+bool DecoratedClient::isMinimizeable() const
+{
+    return d->isMinimizeable();
+}
+
+bool DecoratedClient::providesContextHelp() const
+{
+    return d->providesContextHelp();
+}
+
+bool DecoratedClient::isModal() const
+{
+    return d->isModal();
+}
+
+bool DecoratedClient::isShadeable() const
+{
+    return d->isShadeable();
+}
+
+bool DecoratedClient::isMoveable() const
+{
+    return d->isMoveable();
+}
+
+bool DecoratedClient::isResizeable() const
+{
+    return d->isResizeable();
+}
+
+WId DecoratedClient::windowId() const
+{
+    return d->windowId();
+}
+
+WId DecoratedClient::decorationId() const
+{
+    return d->decorationId();
+}
+
+int DecoratedClient::width() const
+{
+    return d->width();
+}
+
+int DecoratedClient::height() const
+{
+    return d->height();
+}
+
+QSize DecoratedClient::size() const
+{
+    return d->size();
+}
+
+QPalette DecoratedClient::palette() const
+{
+    return d->palette();
+}
+
+Qt::Edges DecoratedClient::adjacentScreenEdges() const
+{
+    return d->adjacentScreenEdges();
+}
+
+QString DecoratedClient::windowClass() const
+{
+    return d->windowClass();
+}
+
+bool DecoratedClient::hasApplicationMenu() const
+{
+    if (const auto *appMenuEnabledPrivate = dynamic_cast<ApplicationMenuEnabledDecoratedClientPrivate *>(d.get())) {
+        return appMenuEnabledPrivate->hasApplicationMenu();
+    }
+    return false;
+}
+
+bool DecoratedClient::isApplicationMenuActive() const
+{
+    if (const auto *appMenuEnabledPrivate = dynamic_cast<ApplicationMenuEnabledDecoratedClientPrivate *>(d.get())) {
+        return appMenuEnabledPrivate->isApplicationMenuActive();
+    }
+    return false;
+}
+
+Decoration *DecoratedClient::decoration() const
+{
+    return d->decoration();
+}
+
+QColor DecoratedClient::color(QPalette::ColorGroup group, QPalette::ColorRole role) const
+{
+    return d->palette().color(group, role);
+}
+
+QColor DecoratedClient::color(ColorGroup group, ColorRole role) const
+{
+    return d->color(group, role);
+}
+
+void DecoratedClient::showApplicationMenu(int actionId)
+{
+    if (auto *appMenuEnabledPrivate = dynamic_cast<ApplicationMenuEnabledDecoratedClientPrivate *>(d.get())) {
+        appMenuEnabledPrivate->showApplicationMenu(actionId);
+    }
+}
+
+} // namespace
+
+#include "moc_decoratedclient.cpp"
diff --git a/src/decoratedclient.h b/src/decoratedclient.h
new file mode 100644 (file)
index 0000000..76c3fcd
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "decoration.h"
+#include "decorationdefines.h"
+#include <kdecoration2/kdecoration2_export.h>
+
+#include <QFont>
+#include <QIcon>
+#include <QObject>
+#include <QPalette>
+#include <QPointer>
+#include <QtGui/qwindowdefs.h>
+
+#include <memory>
+
+namespace KDecoration2
+{
+class DecorationBridge;
+class DecoratedClientPrivate;
+
+/**
+ * @brief The Client which gets decorated.
+ *
+ * The DecoratedClient provides access to all the properties relevant for decorating the Client.
+ * Each DecoratedClient is bound to one Decoration and each Decoration is bound to this one
+ * DecoratedClient.
+ *
+ * The DecoratedClient only exports properties, it does not provide any means to change the state.
+ * To change state one needs to call the methods on Decoration. This is as the backend might
+ * disallow state changes. Therefore any changes should be bound to the change signals of the
+ * DecoratedClient and not be bound to state changes of input elements (such as a button).
+ */
+class KDECORATIONS2_EXPORT DecoratedClient : public QObject
+{
+    Q_OBJECT
+    /**
+     * The Decoration of this DecoratedClient
+     **/
+    Q_PROPERTY(KDecoration2::Decoration *decoration READ decoration CONSTANT)
+    /**
+     * Whether the DecoratedClient is active (has focus) or is inactive.
+     **/
+    Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
+    /**
+     * The caption of the DecoratedClient.
+     **/
+    Q_PROPERTY(QString caption READ caption NOTIFY captionChanged)
+    /**
+     * Whether the DecoratedClient is on all desktops or on just one.
+     **/
+    Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops NOTIFY onAllDesktopsChanged)
+    /**
+     * Whether the DecoratedClient is shaded. Shaded means that the actual content is
+     * not visible, only the Decoration is visible.
+     **/
+    Q_PROPERTY(bool shaded READ isShaded NOTIFY shadedChanged)
+    /**
+     * The icon of the DecoratedClient. This can be used as the icon for the window menu button.
+     **/
+    Q_PROPERTY(QIcon icon READ icon NOTIFY iconChanged)
+    /**
+     * Whether the DecoratedClient is maximized. A DecoratedClient is maximized if it is both
+     * maximizedHorizontally and maximizedVertically. The Decoration of a maximized DecoratedClient
+     * should only consist of the title bar area.
+     **/
+    Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged)
+    /**
+     * Whether the DecoratedClient is maximized horizontally. A horizontally maximized DecoratedClient
+     * uses the maximal possible width.
+     **/
+    Q_PROPERTY(bool maximizedHorizontally READ isMaximizedHorizontally NOTIFY maximizedHorizontallyChanged)
+    /**
+     * Whether the DecoratedClient is maximized vertically. A vertically maximized DecoratedClient
+     * uses the maximal possible height.
+     **/
+    Q_PROPERTY(bool maximizedVertically READ isMaximizedVertically NOTIFY maximizedVerticallyChanged)
+    /**
+     * Whether the DecoratedClient is set to be kept above other DecoratedClients. There can be multiple
+     * DecoratedClients which are set to be kept above.
+     **/
+    Q_PROPERTY(bool keepAbove READ isKeepAbove NOTIFY keepAboveChanged)
+    /**
+     * Whether the DecoratedClient is set to be kept below other DecoratedClients. There can be multiple
+     * DecoratedClients which are set to be kept below.
+     **/
+    Q_PROPERTY(bool keepBelow READ isKeepBelow NOTIFY keepBelowChanged)
+
+    /**
+     * Whether the DecoratedClient can be closed. If this property is @c false a DecorationButton
+     * for closing the DecoratedClient should be disabled.
+     **/
+    Q_PROPERTY(bool closeable READ isCloseable NOTIFY closeableChanged)
+    /**
+     * Whether the DecoratedClient can be maximized. If this property is @c false a DecorationButton
+     * for maximizing the DecoratedClient should be disabled.
+     **/
+    Q_PROPERTY(bool maximizeable READ isMaximizeable NOTIFY maximizeableChanged)
+    /**
+     * Whether the DecoratedClient can be minimized. If this property is @c false a DecorationButton
+     * for minimizing the DecoratedClient should be disabled.
+     **/
+    Q_PROPERTY(bool minimizeable READ isMinimizeable NOTIFY minimizeableChanged)
+    /**
+     * Whether the DecoratedClient provides context help.
+     * The Decoration should only show a context help button if this property is @c true.
+     **/
+    Q_PROPERTY(bool providesContextHelp READ providesContextHelp NOTIFY providesContextHelpChanged)
+    /**
+     * Whether the DecoratedClient is a modal dialog.
+     **/
+    Q_PROPERTY(bool modal READ isModal CONSTANT)
+    /**
+     * Whether the DecoratedClient can be shaded. If this property is @c false a DecorationButton
+     * for shading the DecoratedClient should be disabled.
+     **/
+    Q_PROPERTY(bool shadeable READ isShadeable NOTIFY shadeableChanged)
+    /**
+     * Whether the DecoratedClient can be moved.
+     **/
+    Q_PROPERTY(bool moveable READ isMoveable NOTIFY moveableChanged)
+    /**
+     * Whether the DecoratedClient can be resized.
+     **/
+    Q_PROPERTY(bool resizeable READ isResizeable NOTIFY resizeableChanged)
+
+    /**
+     * The width of the DecoratedClient.
+     **/
+    Q_PROPERTY(int width READ width NOTIFY widthChanged)
+    /**
+     * The height of the DecoratedClient.
+     **/
+    Q_PROPERTY(int height READ height NOTIFY heightChanged)
+    /**
+     * The size of the DecoratedClient.
+     **/
+    Q_PROPERTY(QSize size READ size NOTIFY sizeChanged)
+    /**
+     * The palette this DecoratedClient uses. The palette might be different for each
+     * DecoratedClient and the Decoration should honor the palette.
+     **/
+    Q_PROPERTY(QPalette palette READ palette NOTIFY paletteChanged)
+    /**
+     * The Edges which are adjacent to a screen edge. E.g. for a maximized DecoratedClient this
+     * will include all Edges. The Decoration can use this information to hide borders.
+     **/
+    Q_PROPERTY(Qt::Edges adjacentScreenEdges READ adjacentScreenEdges NOTIFY adjacentScreenEdgesChanged)
+    /**
+     * Whether the DecoratedClient has an application menu
+     * @since 5.9
+     */
+    Q_PROPERTY(bool hasApplicationMenu READ hasApplicationMenu NOTIFY hasApplicationMenuChanged)
+    /**
+     * Whether the application menu for this DecoratedClient is currently shown to the user
+     * The Decoration can use this information to highlight the respective button.
+     * @since 5.9
+     */
+    Q_PROPERTY(bool applicationMenuActive READ isApplicationMenuActive NOTIFY applicationMenuActiveChanged)
+
+    // TODO: properties for windowId and decorationId?
+
+public:
+    DecoratedClient() = delete;
+    ~DecoratedClient() override;
+    bool isActive() const;
+    QString caption() const;
+    bool isOnAllDesktops() const;
+    bool isShaded() const;
+    QIcon icon() const;
+    bool isMaximized() const;
+    bool isMaximizedHorizontally() const;
+    bool isMaximizedVertically() const;
+    bool isKeepAbove() const;
+    bool isKeepBelow() const;
+
+    bool isCloseable() const;
+    bool isMaximizeable() const;
+    bool isMinimizeable() const;
+    bool providesContextHelp() const;
+    bool isModal() const;
+    bool isShadeable() const;
+    bool isMoveable() const;
+    bool isResizeable() const;
+
+    Qt::Edges adjacentScreenEdges() const;
+
+    WId windowId() const;
+    WId decorationId() const;
+
+    QString windowClass() const;
+
+    int width() const;
+    int height() const;
+    QSize size() const;
+
+    Decoration *decoration() const;
+    QPalette palette() const;
+    /**
+     * Used to get colors in QPalette.
+     * @param group The color group
+     * @param role The color role
+     * @return palette().color(group, role)
+     * @since 5.3
+     **/
+    QColor color(QPalette::ColorGroup group, QPalette::ColorRole role) const;
+    /**
+     * Used to get additional colors that are not in QPalette.
+     * @param group The color group
+     * @param role The color role
+     * @return The color if provided for combination of group and role, otherwise invalid QColor.
+     * @since 5.3
+     **/
+    QColor color(ColorGroup group, ColorRole role) const;
+
+    /**
+     * Whether the DecoratedClient has an application menu
+     * @since 5.9
+     */
+    bool hasApplicationMenu() const;
+    /**
+     * Whether the application menu for this DecoratedClient is currently shown to the user
+     * The Decoration can use this information to highlight the respective button.
+     * @since 5.9
+     */
+    bool isApplicationMenuActive() const;
+
+    /**
+     * Request the application menu to be shown to the user
+     * @param actionId The DBus menu ID of the action that should be highlighted, 0 for none.
+     */
+    void showApplicationMenu(int actionId);
+
+Q_SIGNALS:
+    void activeChanged(bool);
+    void captionChanged(QString);
+    void onAllDesktopsChanged(bool);
+    void shadedChanged(bool);
+    void iconChanged(QIcon);
+    void maximizedChanged(bool);
+    void maximizedHorizontallyChanged(bool);
+    void maximizedVerticallyChanged(bool);
+    void keepAboveChanged(bool);
+    void keepBelowChanged(bool);
+
+    void closeableChanged(bool);
+    void maximizeableChanged(bool);
+    void minimizeableChanged(bool);
+    void providesContextHelpChanged(bool);
+    void shadeableChanged(bool);
+    void moveableChanged(bool);
+    void resizeableChanged(bool);
+
+    void widthChanged(int);
+    void heightChanged(int);
+    void sizeChanged(const QSize &size);
+    void paletteChanged(const QPalette &palette);
+    void adjacentScreenEdgesChanged(Qt::Edges edges);
+
+    void hasApplicationMenuChanged(bool);
+    void applicationMenuActiveChanged(bool);
+
+private:
+    friend class Decoration;
+    DecoratedClient(Decoration *parent, DecorationBridge *bridge);
+    const std::unique_ptr<DecoratedClientPrivate> d;
+};
+
+} // namespace
diff --git a/src/decoration.cpp b/src/decoration.cpp
new file mode 100644 (file)
index 0000000..7178e0c
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decoration.h"
+#include "decoratedclient.h"
+#include "decoration_p.h"
+#include "decorationbutton.h"
+#include "decorationsettings.h"
+#include "private/decoratedclientprivate.h"
+#include "private/decorationbridge.h"
+
+#include <QCoreApplication>
+#include <QHoverEvent>
+
+#include <cmath>
+
+namespace KDecoration2
+{
+namespace
+{
+DecorationBridge *findBridge(const QVariantList &args)
+{
+    for (const auto &arg : args) {
+        if (auto bridge = arg.toMap().value(QStringLiteral("bridge")).value<DecorationBridge *>()) {
+            return bridge;
+        }
+    }
+    Q_UNREACHABLE();
+}
+}
+
+Decoration::Private::Private(Decoration *deco, const QVariantList &args)
+    : sectionUnderMouse(Qt::NoSection)
+    , bridge(findBridge(args))
+    , client(std::shared_ptr<DecoratedClient>(new DecoratedClient(deco, bridge)))
+    , opaque(false)
+    , q(deco)
+{
+}
+
+void Decoration::Private::setSectionUnderMouse(Qt::WindowFrameSection section)
+{
+    if (sectionUnderMouse == section) {
+        return;
+    }
+    sectionUnderMouse = section;
+    Q_EMIT q->sectionUnderMouseChanged(sectionUnderMouse);
+}
+
+void Decoration::Private::updateSectionUnderMouse(const QPoint &mousePosition)
+{
+    if (titleBar.contains(mousePosition)) {
+        setSectionUnderMouse(Qt::TitleBarArea);
+        return;
+    }
+    const QSize size = q->size();
+    const int corner = 2 * settings->largeSpacing();
+    const bool left = mousePosition.x() < borders.left();
+    const bool top = mousePosition.y() < borders.top();
+    const bool bottom = size.height() - mousePosition.y() <= borders.bottom();
+    const bool right = size.width() - mousePosition.x() <= borders.right();
+    if (left) {
+        if (top && mousePosition.y() < titleBar.top() + corner) {
+            setSectionUnderMouse(Qt::TopLeftSection);
+        } else if (size.height() - mousePosition.y() <= borders.bottom() + corner && mousePosition.y() > titleBar.bottom()) {
+            setSectionUnderMouse(Qt::BottomLeftSection);
+        } else {
+            setSectionUnderMouse(Qt::LeftSection);
+        }
+        return;
+    }
+    if (right) {
+        if (top && mousePosition.y() < titleBar.top() + corner) {
+            setSectionUnderMouse(Qt::TopRightSection);
+        } else if (size.height() - mousePosition.y() <= borders.bottom() + corner && mousePosition.y() > titleBar.bottom()) {
+            setSectionUnderMouse(Qt::BottomRightSection);
+        } else {
+            setSectionUnderMouse(Qt::RightSection);
+        }
+        return;
+    }
+    if (bottom) {
+        if (mousePosition.y() > titleBar.bottom()) {
+            if (mousePosition.x() < borders.left() + corner) {
+                setSectionUnderMouse(Qt::BottomLeftSection);
+            } else if (size.width() - mousePosition.x() <= borders.right() + corner) {
+                setSectionUnderMouse(Qt::BottomRightSection);
+            } else {
+                setSectionUnderMouse(Qt::BottomSection);
+            }
+        } else {
+            setSectionUnderMouse(Qt::TitleBarArea);
+        }
+        return;
+    }
+    if (top) {
+        if (mousePosition.y() < titleBar.top()) {
+            if (mousePosition.x() < borders.left() + corner) {
+                setSectionUnderMouse(Qt::TopLeftSection);
+            } else if (size.width() - mousePosition.x() <= borders.right() + corner) {
+                setSectionUnderMouse(Qt::TopRightSection);
+            } else {
+                setSectionUnderMouse(Qt::TopSection);
+            }
+        } else {
+            setSectionUnderMouse(Qt::TitleBarArea);
+        }
+        return;
+    }
+    setSectionUnderMouse(Qt::NoSection);
+}
+
+void Decoration::Private::addButton(DecorationButton *button)
+{
+    Q_ASSERT(!buttons.contains(button));
+    buttons << button;
+    QObject::connect(button, &QObject::destroyed, q, [this](QObject *o) {
+        auto it = buttons.begin();
+        while (it != buttons.end()) {
+            if (*it == static_cast<DecorationButton *>(o)) {
+                it = buttons.erase(it);
+            } else {
+                it++;
+            }
+        }
+    });
+}
+
+Decoration::Decoration(QObject *parent, const QVariantList &args)
+    : QObject(parent)
+    , d(new Private(this, args))
+{
+    connect(this, &Decoration::bordersChanged, this, [this] {
+        update();
+    });
+}
+
+Decoration::~Decoration() = default;
+
+DecoratedClient *Decoration::client() const
+{
+    return d->client.get();
+}
+
+void Decoration::requestClose()
+{
+    d->client->d->requestClose();
+}
+
+void Decoration::requestContextHelp()
+{
+    d->client->d->requestContextHelp();
+}
+
+void Decoration::requestMinimize()
+{
+    d->client->d->requestMinimize();
+}
+
+void Decoration::requestToggleOnAllDesktops()
+{
+    d->client->d->requestToggleOnAllDesktops();
+}
+
+void Decoration::requestToggleShade()
+{
+    d->client->d->requestToggleShade();
+}
+
+void Decoration::requestToggleKeepAbove()
+{
+    d->client->d->requestToggleKeepAbove();
+}
+
+void Decoration::requestToggleKeepBelow()
+{
+    d->client->d->requestToggleKeepBelow();
+}
+
+#if KDECORATIONS2_ENABLE_DEPRECATED_SINCE(5, 21)
+void Decoration::requestShowWindowMenu()
+{
+    requestShowWindowMenu(QRect());
+}
+#endif
+
+void Decoration::requestShowWindowMenu(const QRect &rect)
+{
+    d->client->d->requestShowWindowMenu(rect);
+}
+
+void Decoration::requestShowToolTip(const QString &text)
+{
+    d->client->d->requestShowToolTip(text);
+}
+
+void Decoration::requestHideToolTip()
+{
+    d->client->d->requestHideToolTip();
+}
+
+void Decoration::requestToggleMaximization(Qt::MouseButtons buttons)
+{
+    d->client->d->requestToggleMaximization(buttons);
+}
+
+void Decoration::showApplicationMenu(int actionId)
+{
+    const auto it = std::find_if(d->buttons.constBegin(), d->buttons.constEnd(), [](DecorationButton *button) {
+        return button->type() == DecorationButtonType::ApplicationMenu;
+    });
+    if (it != d->buttons.constEnd()) {
+        requestShowApplicationMenu((*it)->geometry().toRect(), actionId);
+    }
+}
+
+void Decoration::requestShowApplicationMenu(const QRect &rect, int actionId)
+{
+    if (auto *appMenuEnabledPrivate = dynamic_cast<ApplicationMenuEnabledDecoratedClientPrivate *>(d->client->d.get())) {
+        appMenuEnabledPrivate->requestShowApplicationMenu(rect, actionId);
+    }
+}
+
+void Decoration::setBlurRegion(const QRegion &region)
+{
+    if (d->blurRegion != region) {
+        d->blurRegion = region;
+        Q_EMIT blurRegionChanged();
+    }
+}
+
+void Decoration::setBorders(const QMargins &borders)
+{
+    if (d->borders != borders) {
+        d->borders = borders;
+        Q_EMIT bordersChanged();
+    }
+}
+
+void Decoration::setResizeOnlyBorders(const QMargins &borders)
+{
+    if (d->resizeOnlyBorders != borders) {
+        d->resizeOnlyBorders = borders;
+        Q_EMIT resizeOnlyBordersChanged();
+    }
+}
+
+void Decoration::setTitleBar(const QRect &rect)
+{
+    if (d->titleBar != rect) {
+        d->titleBar = rect;
+        Q_EMIT titleBarChanged();
+    }
+}
+
+void Decoration::setOpaque(bool opaque)
+{
+    if (d->opaque != opaque) {
+        d->opaque = opaque;
+        Q_EMIT opaqueChanged(opaque);
+    }
+}
+
+void Decoration::setShadow(const std::shared_ptr<DecorationShadow> &shadow)
+{
+    if (d->shadow != shadow) {
+        d->shadow = shadow;
+        Q_EMIT shadowChanged(shadow);
+    }
+}
+
+QRegion Decoration::blurRegion() const
+{
+    return d->blurRegion;
+}
+
+QMargins Decoration::borders() const
+{
+    return d->borders;
+}
+
+QMargins Decoration::resizeOnlyBorders() const
+{
+    return d->resizeOnlyBorders;
+}
+
+QRect Decoration::titleBar() const
+{
+    return d->titleBar;
+}
+
+Qt::WindowFrameSection Decoration::sectionUnderMouse() const
+{
+    return d->sectionUnderMouse;
+}
+
+std::shared_ptr<DecorationShadow> Decoration::shadow() const
+{
+    return d->shadow;
+}
+
+bool Decoration::isOpaque() const
+{
+    return d->opaque;
+}
+
+int Decoration::borderLeft() const
+{
+    return d->borders.left();
+}
+
+int Decoration::resizeOnlyBorderLeft() const
+{
+    return d->resizeOnlyBorders.left();
+}
+
+int Decoration::borderRight() const
+{
+    return d->borders.right();
+}
+
+int Decoration::resizeOnlyBorderRight() const
+{
+    return d->resizeOnlyBorders.right();
+}
+
+int Decoration::borderTop() const
+{
+    return d->borders.top();
+}
+
+int Decoration::resizeOnlyBorderTop() const
+{
+    return d->resizeOnlyBorders.top();
+}
+
+int Decoration::borderBottom() const
+{
+    return d->borders.bottom();
+}
+
+int Decoration::resizeOnlyBorderBottom() const
+{
+    return d->resizeOnlyBorders.bottom();
+}
+
+QSize Decoration::size() const
+{
+    const QMargins &b = d->borders;
+    return QSize(d->client->width() + b.left() + b.right(), //
+                 (d->client->isShaded() ? 0 : d->client->height()) + b.top() + b.bottom());
+}
+
+QRect Decoration::rect() const
+{
+    return QRect(QPoint(0, 0), size());
+}
+
+bool Decoration::event(QEvent *event)
+{
+    switch (event->type()) {
+    case QEvent::HoverEnter:
+        hoverEnterEvent(static_cast<QHoverEvent *>(event));
+        return true;
+    case QEvent::HoverLeave:
+        hoverLeaveEvent(static_cast<QHoverEvent *>(event));
+        return true;
+    case QEvent::HoverMove:
+        hoverMoveEvent(static_cast<QHoverEvent *>(event));
+        return true;
+    case QEvent::MouseButtonPress:
+        mousePressEvent(static_cast<QMouseEvent *>(event));
+        return true;
+    case QEvent::MouseButtonRelease:
+        mouseReleaseEvent(static_cast<QMouseEvent *>(event));
+        return true;
+    case QEvent::MouseMove:
+        mouseMoveEvent(static_cast<QMouseEvent *>(event));
+        return true;
+    case QEvent::Wheel:
+        wheelEvent(static_cast<QWheelEvent *>(event));
+        return true;
+    default:
+        return QObject::event(event);
+    }
+}
+
+void Decoration::hoverEnterEvent(QHoverEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        QCoreApplication::instance()->sendEvent(button, event);
+    }
+    auto flooredPos = QPoint(std::floor(event->position().x()), std::floor(event->position().y()));
+    d->updateSectionUnderMouse(flooredPos);
+}
+
+void Decoration::hoverLeaveEvent(QHoverEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        QCoreApplication::instance()->sendEvent(button, event);
+    }
+    d->setSectionUnderMouse(Qt::NoSection);
+}
+
+void Decoration::hoverMoveEvent(QHoverEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        if (!button->isEnabled() || !button->isVisible()) {
+            continue;
+        }
+        const bool hovered = button->isHovered();
+        const bool contains = button->contains(event->position());
+        if (!hovered && contains) {
+            QHoverEvent e(QEvent::HoverEnter, event->position(), event->oldPosF(), event->modifiers());
+            QCoreApplication::instance()->sendEvent(button, &e);
+        } else if (hovered && !contains) {
+            QHoverEvent e(QEvent::HoverLeave, event->position(), event->oldPosF(), event->modifiers());
+            QCoreApplication::instance()->sendEvent(button, &e);
+        } else if (hovered && contains) {
+            QCoreApplication::instance()->sendEvent(button, event);
+        }
+    }
+    auto flooredPos = QPoint(std::floor(event->position().x()), std::floor(event->position().y()));
+    d->updateSectionUnderMouse(flooredPos);
+}
+
+void Decoration::mouseMoveEvent(QMouseEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        if (button->isPressed()) {
+            QCoreApplication::instance()->sendEvent(button, event);
+            return;
+        }
+    }
+    // not handled, take care ourselves
+}
+
+void Decoration::mousePressEvent(QMouseEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        if (button->isHovered()) {
+            if (button->acceptedButtons().testFlag(event->button())) {
+                QCoreApplication::instance()->sendEvent(button, event);
+            }
+            event->setAccepted(true);
+            return;
+        }
+    }
+}
+
+void Decoration::mouseReleaseEvent(QMouseEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        if (button->isPressed() && button->acceptedButtons().testFlag(event->button())) {
+            QCoreApplication::instance()->sendEvent(button, event);
+            return;
+        }
+    }
+    // not handled, take care ourselves
+    d->updateSectionUnderMouse(event->pos());
+}
+
+void Decoration::wheelEvent(QWheelEvent *event)
+{
+    for (DecorationButton *button : d->buttons) {
+        if (button->contains(event->position())) {
+            QCoreApplication::instance()->sendEvent(button, event);
+            event->setAccepted(true);
+        }
+    }
+}
+
+void Decoration::update(const QRect &r)
+{
+    Q_EMIT damaged(r.isNull() ? rect() : r);
+}
+
+void Decoration::update()
+{
+    update(QRect());
+}
+
+void Decoration::setSettings(const std::shared_ptr<DecorationSettings> &settings)
+{
+    d->settings = settings;
+}
+
+std::shared_ptr<DecorationSettings> Decoration::settings() const
+{
+    return d->settings;
+}
+
+} // namespace
+
+#include "moc_decoration.cpp"
diff --git a/src/decoration.h b/src/decoration.h
new file mode 100644 (file)
index 0000000..45d637c
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "decorationshadow.h"
+#include <kdecoration2/kdecoration2_export.h>
+
+#include <QMargins>
+#include <QObject>
+#include <QRect>
+
+class QHoverEvent;
+class QMouseEvent;
+class QPainter;
+class QWheelEvent;
+
+/**
+ * @brief Framework for creating window decorations.
+ *
+ **/
+namespace KDecoration2
+{
+class DecorationPrivate;
+class DecoratedClient;
+class DecorationButton;
+class DecorationSettings;
+
+/**
+ * @brief Base class for the Decoration.
+ *
+ * To provide a Decoration one needs to inherit from this class. The framework will instantiate
+ * an instance of the inherited class for each DecoratedClient.
+ *
+ * The main tasks of the Decoration is to provide borders around the DecoratedClient. For this
+ * the Deocration provides border sizes: those should be adjusted depending on the state of the
+ * DecoratedClient. E.g. commonly a maximized DecoratedClient does not have borders on the side,
+ * only the title bar.
+ *
+ * Whenever the visual representation of the Decoration changes the slot @link Decoration::update @endlink
+ * should be invoked to request a repaint. The framework will in return invoke the
+ * @link Decoration::paint @endlink method. This method needs to be implemented by inheriting
+ * classes.
+ *
+ * A Decoration commonly provides buttons for interaction. E.g. a close button to close the
+ * DecoratedClient. For such actions the Decoration provides slots which should be connected to
+ * the clicked signals of the buttons. For convenience the framework provides the @link DecorationButton @endlink
+ * and the @link DecorationButtonGroup @endlink for easier layout. It is not required to use those,
+ * if one uses different ways to represent the actions one needs to filter the events accordingly.
+ *
+ * @see DecoratedClient
+ * @see DecorationButton
+ * @see DecorationButtonGroup
+ **/
+class KDECORATIONS2_EXPORT Decoration : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QMargins borders READ borders NOTIFY bordersChanged)
+    Q_PROPERTY(int borderLeft READ borderLeft NOTIFY bordersChanged)
+    Q_PROPERTY(int borderRight READ borderRight NOTIFY bordersChanged)
+    Q_PROPERTY(int borderTop READ borderTop NOTIFY bordersChanged)
+    Q_PROPERTY(int borderBottom READ borderBottom NOTIFY bordersChanged)
+    Q_PROPERTY(QMargins resizeOnlyBorders READ resizeOnlyBorders NOTIFY resizeOnlyBordersChanged)
+    Q_PROPERTY(int resizeOnlyBorderLeft READ resizeOnlyBorderLeft NOTIFY resizeOnlyBordersChanged)
+    Q_PROPERTY(int resizeOnlyBorderRight READ resizeOnlyBorderRight NOTIFY resizeOnlyBordersChanged)
+    Q_PROPERTY(int resizeOnlyBorderTop READ resizeOnlyBorderTop NOTIFY resizeOnlyBordersChanged)
+    Q_PROPERTY(int resizeOnlyBorderBottom READ resizeOnlyBorderBottom NOTIFY resizeOnlyBordersChanged)
+    /**
+     * This property denotes the part of the Decoration which is currently under the mouse pointer.
+     * It gets automatically updated whenever a QMouseEvent or QHoverEvent gets processed.
+     **/
+    Q_PROPERTY(Qt::WindowFrameSection sectionUnderMouse READ sectionUnderMouse NOTIFY sectionUnderMouseChanged)
+    /**
+     * The titleBar is the area inside the Decoration containing all controls (e.g. Buttons)
+     * and the caption. The titleBar is the main interaction area, while all other areas of the
+     * Decoration are normally used as resize areas.
+     **/
+    Q_PROPERTY(QRect titleBar READ titleBar NOTIFY titleBarChanged)
+    /**
+     * Whether the Decoration is fully opaque. By default a Decoration is considered to
+     * use the alpha channel and this property has the value @c false. But for e.g. a maximized
+     * DecoratedClient it is possible that the Decoration is fully opaque. In this case the
+     * Decoration should set this property to @c true.
+     **/
+    Q_PROPERTY(bool opaque READ isOpaque NOTIFY opaqueChanged)
+public:
+    ~Decoration() override;
+
+    /**
+     * The DecoratedClient for this Decoration.
+     **/
+    DecoratedClient *client() const;
+
+    QMargins borders() const;
+    int borderLeft() const;
+    int borderRight() const;
+    int borderTop() const;
+    int borderBottom() const;
+    QMargins resizeOnlyBorders() const;
+    int resizeOnlyBorderLeft() const;
+    int resizeOnlyBorderRight() const;
+    int resizeOnlyBorderTop() const;
+    int resizeOnlyBorderBottom() const;
+    Qt::WindowFrameSection sectionUnderMouse() const;
+    QRect titleBar() const;
+    bool isOpaque() const;
+
+    /**
+     * DecorationShadow for this Decoration. It is recommended that multiple Decorations share
+     * the same DecorationShadow. E.g one DecorationShadow for all inactive Decorations and one
+     * for the active Decoration.
+     **/
+    std::shared_ptr<DecorationShadow> shadow() const;
+
+    /**
+     * The decoration's geometry in local coordinates.
+     *
+     * Basically the size of the DecoratedClient combined with the borders.
+     **/
+    QRect rect() const;
+    QSize size() const;
+
+    /**
+     * The decoration's blur region in local coordinates
+     */
+    QRegion blurRegion() const;
+
+    /**
+     * Invoked by the framework to set the Settings for this Decoration before
+     * init is invoked.
+     * @internal
+     **/
+    void setSettings(const std::shared_ptr<DecorationSettings> &settings);
+    /**
+     * @returns The DecorationSettings used for this Decoration.
+     **/
+    std::shared_ptr<DecorationSettings> settings() const;
+
+    /**
+     * Implement this method in inheriting classes to provide the rendering.
+     *
+     * The @p painter is set up to paint on an internal QPaintDevice. The painting is
+     * implicitly double buffered.
+     *
+     * @param painter The painter which needs to be used for rendering
+     * @param repaintArea The region which needs to be repainted.
+     **/
+    virtual void paint(QPainter *painter, const QRect &repaintArea) = 0;
+
+    bool event(QEvent *event) override;
+
+public Q_SLOTS:
+    void requestClose();
+    void requestToggleMaximization(Qt::MouseButtons buttons);
+    void requestMinimize();
+    void requestContextHelp();
+    void requestToggleOnAllDesktops();
+    void requestToggleShade();
+    void requestToggleKeepAbove();
+    void requestToggleKeepBelow();
+
+#if KDECORATIONS2_ENABLE_DEPRECATED_SINCE(5, 21)
+    /**
+     * @deprecated
+     * @see requestShowWindowMenu(const QRect &rect)
+     */
+    KDECORATIONS2_DEPRECATED_VERSION(5, 21, "Use Decoration::requestShowWindowMenu(QRect)")
+    void requestShowWindowMenu();
+#endif
+
+    /**
+     * @param rect the location at which to show the window menu
+     */
+    void requestShowWindowMenu(const QRect &rect);
+    void requestShowToolTip(const QString &text);
+    void requestHideToolTip();
+
+    void showApplicationMenu(int actionId);
+    void requestShowApplicationMenu(const QRect &rect, int actionId);
+
+    void update(const QRect &rect);
+    void update();
+
+    /**
+     * This method gets invoked from the framework once the Decoration is created and
+     * completely setup.
+     *
+     * An inheriting class should override this method and perform all initialization in
+     * this method instead of the constructor.
+     *
+     * @return true if initialization has been successful,
+     * false otherwise (for example, a QML component could not be loaded)
+     **/
+    virtual bool init() = 0;
+
+Q_SIGNALS:
+    void blurRegionChanged();
+    void bordersChanged();
+    void resizeOnlyBordersChanged();
+    void sectionUnderMouseChanged(Qt::WindowFrameSection);
+    void titleBarChanged();
+    void opaqueChanged(bool);
+    void shadowChanged(const std::shared_ptr<DecorationShadow> &shadow);
+    void damaged(const QRegion &region);
+
+protected:
+    /**
+     * Constructor for the Decoration.
+     *
+     * The @p args are used by the decoration framework to pass meta information
+     * to the Decoration. An inheriting class is supposed to pass the args to the
+     * parent class.
+     *
+     * @param parent The parent of the Decoration
+     * @param args Additional arguments passed in from the framework
+     **/
+    explicit Decoration(QObject *parent, const QVariantList &args);
+    void setBorders(const QMargins &borders);
+    void setResizeOnlyBorders(const QMargins &borders);
+    void setBlurRegion(const QRegion &region);
+    /**
+     * An implementation has to invoke this method whenever the area
+     * containing the controls and caption changes.
+     * @param rect The new geometry of the titleBar in Decoration coordinates
+     **/
+    void setTitleBar(const QRect &rect);
+    void setOpaque(bool opaque);
+    void setShadow(const std::shared_ptr<DecorationShadow> &shadow);
+
+    virtual void hoverEnterEvent(QHoverEvent *event);
+    virtual void hoverLeaveEvent(QHoverEvent *event);
+    virtual void hoverMoveEvent(QHoverEvent *event);
+    virtual void mouseMoveEvent(QMouseEvent *event);
+    virtual void mousePressEvent(QMouseEvent *event);
+    virtual void mouseReleaseEvent(QMouseEvent *event);
+    virtual void wheelEvent(QWheelEvent *event);
+
+private:
+    friend class DecorationButton;
+    class Private;
+    std::unique_ptr<Private> d;
+};
+
+} // namespace
+
+Q_DECLARE_METATYPE(KDecoration2::Decoration *)
diff --git a/src/decoration_p.h b/src/decoration_p.h
new file mode 100644 (file)
index 0000000..b827b43
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+#include "decoration.h"
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+namespace KDecoration2
+{
+class Decoration;
+class DecorationBridge;
+class DecorationButton;
+class DecoratedClient;
+class DecorationSettings;
+class DecorationShadow;
+
+class Q_DECL_HIDDEN Decoration::Private
+{
+public:
+    Private(Decoration *decoration, const QVariantList &args);
+
+    QMargins borders;
+    QMargins resizeOnlyBorders;
+
+    Qt::WindowFrameSection sectionUnderMouse;
+    void setSectionUnderMouse(Qt::WindowFrameSection section);
+    void updateSectionUnderMouse(const QPoint &mousePosition);
+
+    QRect titleBar;
+    QRegion blurRegion;
+
+    void addButton(DecorationButton *button);
+
+    std::shared_ptr<DecorationSettings> settings;
+    DecorationBridge *bridge;
+    std::shared_ptr<DecoratedClient> client;
+    bool opaque;
+    QList<DecorationButton *> buttons;
+    std::shared_ptr<DecorationShadow> shadow;
+
+private:
+    Decoration *q;
+};
+
+} // namespace
diff --git a/src/decorationbutton.cpp b/src/decorationbutton.cpp
new file mode 100644 (file)
index 0000000..294ba99
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decorationbutton.h"
+#include "decoratedclient.h"
+#include "decoration.h"
+#include "decoration_p.h"
+#include "decorationbutton_p.h"
+#include "decorationsettings.h"
+
+#include <KLocalizedString>
+
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QGuiApplication>
+#include <QHoverEvent>
+#include <QStyleHints>
+#include <QTimer>
+
+#include <cmath>
+
+#ifndef K_DOXYGEN
+size_t qHash(const KDecoration2::DecorationButtonType &type, size_t seed)
+{
+    return qHash(uint(type), seed);
+}
+#endif
+
+namespace KDecoration2
+{
+
+DecorationButton::Private::Private(DecorationButtonType type, const QPointer<Decoration> &decoration, DecorationButton *parent)
+    : decoration(decoration)
+    , type(type)
+    , hovered(false)
+    , enabled(true)
+    , checkable(false)
+    , checked(false)
+    , visible(true)
+    , acceptedButtons(Qt::LeftButton)
+    , doubleClickEnabled(false)
+    , pressAndHold(false)
+    , q(parent)
+    , m_pressed(Qt::NoButton)
+{
+    init();
+}
+
+DecorationButton::Private::~Private() = default;
+
+void DecorationButton::Private::init()
+{
+    auto c = decoration->client();
+    auto settings = decoration->settings();
+    switch (type) {
+    case DecorationButtonType::Menu:
+        QObject::connect(
+            q,
+            &DecorationButton::clicked,
+            decoration.data(),
+            [this](Qt::MouseButton button) {
+                Q_UNUSED(button)
+                decoration->requestShowWindowMenu(q->geometry().toRect());
+            },
+            Qt::QueuedConnection);
+        QObject::connect(q, &DecorationButton::doubleClicked, decoration.data(), &Decoration::requestClose, Qt::QueuedConnection);
+        QObject::connect(
+            settings.get(),
+            &DecorationSettings::closeOnDoubleClickOnMenuChanged,
+            q,
+            [this](bool enabled) {
+                doubleClickEnabled = enabled;
+                setPressAndHold(enabled);
+            },
+            Qt::QueuedConnection);
+        doubleClickEnabled = settings->isCloseOnDoubleClickOnMenu();
+        setPressAndHold(settings->isCloseOnDoubleClickOnMenu());
+        setAcceptedButtons(Qt::LeftButton | Qt::RightButton);
+        break;
+    case DecorationButtonType::ApplicationMenu:
+        setVisible(c->hasApplicationMenu());
+        setCheckable(true); // will be "checked" whilst the menu is opened
+        // FIXME TODO connect directly and figure out the button geometry/offset stuff
+        QObject::connect(
+            q,
+            &DecorationButton::clicked,
+            decoration.data(),
+            [this] {
+                decoration->requestShowApplicationMenu(q->geometry().toRect(), 0 /* actionId */);
+            },
+            Qt::QueuedConnection); //&Decoration::requestShowApplicationMenu, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::hasApplicationMenuChanged, q, &DecorationButton::setVisible);
+        QObject::connect(c, &DecoratedClient::applicationMenuActiveChanged, q, &DecorationButton::setChecked);
+        break;
+    case DecorationButtonType::OnAllDesktops:
+        setVisible(settings->isOnAllDesktopsAvailable());
+        setCheckable(true);
+        setChecked(c->isOnAllDesktops());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestToggleOnAllDesktops, Qt::QueuedConnection);
+        QObject::connect(settings.get(), &DecorationSettings::onAllDesktopsAvailableChanged, q, &DecorationButton::setVisible);
+        QObject::connect(c, &DecoratedClient::onAllDesktopsChanged, q, &DecorationButton::setChecked);
+        break;
+    case DecorationButtonType::Minimize:
+        setEnabled(c->isMinimizeable());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestMinimize, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::minimizeableChanged, q, &DecorationButton::setEnabled);
+        break;
+    case DecorationButtonType::Maximize:
+        setEnabled(c->isMaximizeable());
+        setCheckable(true);
+        setChecked(c->isMaximized());
+        setAcceptedButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestToggleMaximization, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::maximizeableChanged, q, &DecorationButton::setEnabled);
+        QObject::connect(c, &DecoratedClient::maximizedChanged, q, &DecorationButton::setChecked);
+        break;
+    case DecorationButtonType::Close:
+        setEnabled(c->isCloseable());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestClose, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::closeableChanged, q, &DecorationButton::setEnabled);
+        break;
+    case DecorationButtonType::ContextHelp:
+        setVisible(c->providesContextHelp());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestContextHelp, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::providesContextHelpChanged, q, &DecorationButton::setVisible);
+        break;
+    case DecorationButtonType::KeepAbove:
+        setCheckable(true);
+        setChecked(c->isKeepAbove());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestToggleKeepAbove, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::keepAboveChanged, q, &DecorationButton::setChecked);
+        break;
+    case DecorationButtonType::KeepBelow:
+        setCheckable(true);
+        setChecked(c->isKeepBelow());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestToggleKeepBelow, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::keepBelowChanged, q, &DecorationButton::setChecked);
+        break;
+    case DecorationButtonType::Shade:
+        setEnabled(c->isShadeable());
+        setCheckable(true);
+        setChecked(c->isShaded());
+        QObject::connect(q, &DecorationButton::clicked, decoration.data(), &Decoration::requestToggleShade, Qt::QueuedConnection);
+        QObject::connect(c, &DecoratedClient::shadedChanged, q, &DecorationButton::setChecked);
+        QObject::connect(c, &DecoratedClient::shadeableChanged, q, &DecorationButton::setEnabled);
+        break;
+    case DecorationButtonType::Spacer:
+        setEnabled(false);
+        break;
+    default:
+        // nothing
+        break;
+    }
+}
+
+void DecorationButton::Private::setHovered(bool set)
+{
+    if (hovered == set) {
+        return;
+    }
+    hovered = set;
+    Q_EMIT q->hoveredChanged(hovered);
+}
+
+void DecorationButton::Private::setEnabled(bool set)
+{
+    if (enabled == set) {
+        return;
+    }
+    enabled = set;
+    Q_EMIT q->enabledChanged(enabled);
+    if (!enabled) {
+        setHovered(false);
+        if (isPressed()) {
+            m_pressed = Qt::NoButton;
+            Q_EMIT q->pressedChanged(false);
+        }
+    }
+}
+
+void DecorationButton::Private::setVisible(bool set)
+{
+    if (visible == set) {
+        return;
+    }
+    visible = set;
+    Q_EMIT q->visibilityChanged(set);
+    if (!visible) {
+        setHovered(false);
+        if (isPressed()) {
+            m_pressed = Qt::NoButton;
+            Q_EMIT q->pressedChanged(false);
+        }
+    }
+}
+
+void DecorationButton::Private::setChecked(bool set)
+{
+    if (!checkable || checked == set) {
+        return;
+    }
+    checked = set;
+    Q_EMIT q->checkedChanged(checked);
+}
+
+void DecorationButton::Private::setCheckable(bool set)
+{
+    if (checkable == set) {
+        return;
+    }
+    if (!set) {
+        setChecked(false);
+    }
+    checkable = set;
+    Q_EMIT q->checkableChanged(checkable);
+}
+
+void DecorationButton::Private::setPressed(Qt::MouseButton button, bool pressed)
+{
+    if (pressed) {
+        m_pressed = m_pressed | button;
+    } else {
+        m_pressed = m_pressed & ~button;
+    }
+    Q_EMIT q->pressedChanged(isPressed());
+}
+
+void DecorationButton::Private::setAcceptedButtons(Qt::MouseButtons buttons)
+{
+    if (acceptedButtons == buttons) {
+        return;
+    }
+    acceptedButtons = buttons;
+    Q_EMIT q->acceptedButtonsChanged(acceptedButtons);
+}
+
+void DecorationButton::Private::startDoubleClickTimer()
+{
+    if (!doubleClickEnabled) {
+        return;
+    }
+    if (!m_doubleClickTimer) {
+        m_doubleClickTimer = std::make_unique<QElapsedTimer>();
+    }
+    m_doubleClickTimer->start();
+}
+
+void DecorationButton::Private::invalidateDoubleClickTimer()
+{
+    if (!m_doubleClickTimer) {
+        return;
+    }
+    m_doubleClickTimer->invalidate();
+}
+
+bool DecorationButton::Private::wasDoubleClick() const
+{
+    if (!m_doubleClickTimer || !m_doubleClickTimer->isValid()) {
+        return false;
+    }
+    return !m_doubleClickTimer->hasExpired(QGuiApplication::styleHints()->mouseDoubleClickInterval());
+}
+
+void DecorationButton::Private::setPressAndHold(bool enable)
+{
+    if (pressAndHold == enable) {
+        return;
+    }
+    pressAndHold = enable;
+    if (!pressAndHold) {
+        m_pressAndHoldTimer.reset();
+    }
+}
+
+void DecorationButton::Private::startPressAndHold()
+{
+    if (!pressAndHold) {
+        return;
+    }
+    if (!m_pressAndHoldTimer) {
+        m_pressAndHoldTimer.reset(new QTimer());
+        m_pressAndHoldTimer->setSingleShot(true);
+        QObject::connect(m_pressAndHoldTimer.get(), &QTimer::timeout, q, [this]() {
+            q->clicked(Qt::LeftButton);
+        });
+    }
+    m_pressAndHoldTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval());
+}
+
+void DecorationButton::Private::stopPressAndHold()
+{
+    if (m_pressAndHoldTimer) {
+        m_pressAndHoldTimer->stop();
+    }
+}
+
+QString DecorationButton::Private::typeToString(DecorationButtonType type)
+{
+    switch (type) {
+    case DecorationButtonType::Menu:
+        return i18n("More actions for this window");
+    case DecorationButtonType::ApplicationMenu:
+        return i18n("Application menu");
+    case DecorationButtonType::OnAllDesktops:
+        if (this->q->isChecked())
+            return i18n("On one desktop");
+        else
+            return i18n("On all desktops");
+    case DecorationButtonType::Minimize:
+        return i18n("Minimize");
+    case DecorationButtonType::Maximize:
+        if (this->q->isChecked())
+            return i18n("Restore");
+        else
+            return i18n("Maximize");
+    case DecorationButtonType::Close:
+        return i18n("Close");
+    case DecorationButtonType::ContextHelp:
+        return i18n("Context help");
+    case DecorationButtonType::Shade:
+        if (this->q->isChecked())
+            return i18n("Unshade");
+        else
+            return i18n("Shade");
+    case DecorationButtonType::KeepBelow:
+        if (this->q->isChecked())
+            return i18n("Don't keep below other windows");
+        else
+            return i18n("Keep below other windows");
+    case DecorationButtonType::KeepAbove:
+        if (this->q->isChecked())
+            return i18n("Don't keep above other windows");
+        else
+            return i18n("Keep above other windows");
+    default:
+        return QString();
+    }
+}
+
+DecorationButton::DecorationButton(DecorationButtonType type, Decoration *decoration, QObject *parent)
+    : QObject(parent)
+    , d(new Private(type, decoration, this))
+{
+    decoration->d->addButton(this);
+    connect(this, &DecorationButton::geometryChanged, this, static_cast<void (DecorationButton::*)(const QRectF &)>(&DecorationButton::update));
+    auto updateSlot = static_cast<void (DecorationButton::*)()>(&DecorationButton::update);
+    connect(this, &DecorationButton::hoveredChanged, this, updateSlot);
+    connect(this, &DecorationButton::hoveredChanged, this, [this](bool hovered) {
+        if (hovered) {
+            // TODO: show tooltip if hovered and hide if not
+            const QString type = this->d->typeToString(this->type());
+            this->decoration()->requestShowToolTip(type);
+        } else {
+            this->decoration()->requestHideToolTip();
+        }
+    });
+    connect(this, &DecorationButton::pressedChanged, this, updateSlot);
+    connect(this, &DecorationButton::pressedChanged, this, [this](bool pressed) {
+        if (pressed) {
+            this->decoration()->requestHideToolTip();
+        }
+    });
+    connect(this, &DecorationButton::checkedChanged, this, updateSlot);
+    connect(this, &DecorationButton::enabledChanged, this, updateSlot);
+    connect(this, &DecorationButton::visibilityChanged, this, updateSlot);
+    connect(this, &DecorationButton::hoveredChanged, this, [this](bool hovered) {
+        if (hovered) {
+            Q_EMIT pointerEntered();
+        } else {
+            Q_EMIT pointerLeft();
+        }
+    });
+    connect(this, &DecorationButton::pressedChanged, this, [this](bool p) {
+        if (p) {
+            Q_EMIT pressed();
+        } else {
+            Q_EMIT released();
+        }
+    });
+}
+
+DecorationButton::~DecorationButton() = default;
+
+void DecorationButton::update(const QRectF &rect)
+{
+    decoration()->update(rect.isNull() ? geometry().toRect() : rect.toRect());
+}
+
+void DecorationButton::update()
+{
+    update(QRectF());
+}
+
+QSizeF DecorationButton::size() const
+{
+    return d->geometry.size();
+}
+
+bool DecorationButton::isPressed() const
+{
+    return d->isPressed();
+}
+
+bool DecorationButton::isHovered() const
+{
+    return d->hovered;
+}
+
+bool DecorationButton::isEnabled() const
+{
+    return d->enabled;
+}
+
+bool DecorationButton::isChecked() const
+{
+    return d->checked;
+}
+
+bool DecorationButton::isCheckable() const
+{
+    return d->checkable;
+}
+
+bool DecorationButton::isVisible() const
+{
+    return d->visible;
+}
+
+QRectF DecorationButton::geometry() const
+{
+    return d->geometry;
+}
+
+Decoration *DecorationButton::decoration() const
+{
+    return d->decoration;
+}
+
+Qt::MouseButtons DecorationButton::acceptedButtons() const
+{
+    return d->acceptedButtons;
+}
+
+DecorationButtonType DecorationButton::type() const
+{
+    return d->type;
+}
+
+void DecorationButton::setAcceptedButtons(Qt::MouseButtons value)
+{
+    d->setAcceptedButtons(value);
+}
+
+void DecorationButton::setEnabled(bool value)
+{
+    d->setEnabled(value);
+}
+
+void DecorationButton::setChecked(bool value)
+{
+    d->setChecked(value);
+}
+
+void DecorationButton::setCheckable(bool value)
+{
+    d->setCheckable(value);
+}
+
+void DecorationButton::setVisible(bool value)
+{
+    d->setVisible(value);
+}
+
+void DecorationButton::setGeometry(const QRectF &geometry)
+{
+    if (d->geometry == geometry) {
+        return;
+    }
+    d->geometry = geometry;
+    Q_EMIT geometryChanged(d->geometry);
+}
+
+bool DecorationButton::contains(const QPointF &pos) const
+{
+    auto flooredPoint = QPoint(std::floor(pos.x()), std::floor(pos.y()));
+    return d->geometry.toRect().contains(flooredPoint);
+}
+
+bool DecorationButton::event(QEvent *event)
+{
+    switch (event->type()) {
+    case QEvent::HoverEnter:
+        hoverEnterEvent(static_cast<QHoverEvent *>(event));
+        return true;
+    case QEvent::HoverLeave:
+        hoverLeaveEvent(static_cast<QHoverEvent *>(event));
+        return true;
+    case QEvent::HoverMove:
+        hoverMoveEvent(static_cast<QHoverEvent *>(event));
+        return true;
+    case QEvent::MouseButtonPress:
+        mousePressEvent(static_cast<QMouseEvent *>(event));
+        return true;
+    case QEvent::MouseButtonRelease:
+        mouseReleaseEvent(static_cast<QMouseEvent *>(event));
+        return true;
+    case QEvent::MouseMove:
+        mouseMoveEvent(static_cast<QMouseEvent *>(event));
+        return true;
+    case QEvent::Wheel:
+        wheelEvent(static_cast<QWheelEvent *>(event));
+        return true;
+    default:
+        return QObject::event(event);
+    }
+}
+
+void DecorationButton::hoverEnterEvent(QHoverEvent *event)
+{
+    if (!d->enabled || !d->visible || !contains(event->position())) {
+        return;
+    }
+    d->setHovered(true);
+    event->setAccepted(true);
+}
+
+void DecorationButton::hoverLeaveEvent(QHoverEvent *event)
+{
+    if (!d->enabled || !d->visible || !d->hovered || contains(event->position())) {
+        return;
+    }
+    d->setHovered(false);
+    event->setAccepted(true);
+}
+
+void DecorationButton::hoverMoveEvent(QHoverEvent *event)
+{
+    Q_UNUSED(event)
+}
+
+void DecorationButton::mouseMoveEvent(QMouseEvent *event)
+{
+    if (!d->enabled || !d->visible || !d->hovered) {
+        return;
+    }
+    if (!contains(event->position())) {
+        d->setHovered(false);
+        event->setAccepted(true);
+    }
+}
+
+void DecorationButton::mousePressEvent(QMouseEvent *event)
+{
+    if (!d->enabled || !d->visible || !contains(event->position()) || !d->acceptedButtons.testFlag(event->button())) {
+        return;
+    }
+    d->setPressed(event->button(), true);
+    event->setAccepted(true);
+    if (d->doubleClickEnabled && event->button() == Qt::LeftButton) {
+        // check for double click
+        if (d->wasDoubleClick()) {
+            event->setAccepted(true);
+            Q_EMIT doubleClicked();
+        }
+        d->invalidateDoubleClickTimer();
+    }
+    if (d->pressAndHold && event->button() == Qt::LeftButton) {
+        d->startPressAndHold();
+    }
+}
+
+void DecorationButton::mouseReleaseEvent(QMouseEvent *event)
+{
+    if (!d->enabled || !d->visible || !d->isPressed(event->button())) {
+        return;
+    }
+    if (contains(event->position())) {
+        if (!d->pressAndHold || event->button() != Qt::LeftButton) {
+            Q_EMIT clicked(event->button());
+        } else {
+            d->stopPressAndHold();
+        }
+    }
+    d->setPressed(event->button(), false);
+    event->setAccepted(true);
+
+    if (d->doubleClickEnabled && event->button() == Qt::LeftButton) {
+        d->startDoubleClickTimer();
+    }
+}
+
+void DecorationButton::wheelEvent(QWheelEvent *event)
+{
+    Q_UNUSED(event)
+}
+
+}
+
+#include "moc_decorationbutton.cpp"
diff --git a/src/decorationbutton.h b/src/decorationbutton.h
new file mode 100644 (file)
index 0000000..96fd480
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "decorationdefines.h"
+#include <kdecoration2/kdecoration2_export.h>
+
+#include <QObject>
+#include <QRect>
+
+class QHoverEvent;
+class QMouseEvent;
+class QPainter;
+class QWheelEvent;
+
+namespace KDecoration2
+{
+class DecorationButtonPrivate;
+class Decoration;
+
+/**
+ * @brief A button to be used in a Decoration.
+ *
+ * The DecorationButton is a simple Button which can be used (but doesn't have to) in a Decoration.
+ * It takes care of the input handling and triggers the correct state change methods on the
+ * Decoration.
+ *
+ * This simplifies the handling of DecorationButtons. A Decoration implementation just needs to
+ * subclass DecorationButton and implement the paint method. Everything else is handled by the
+ * DecorationButton.
+ *
+ * For positioning the DecorationButtons it's recommended to use a DecorationButtonGroup.
+ *
+ * @see Decoration
+ * @see DecorationButtonGroup
+ **/
+class KDECORATIONS2_EXPORT DecorationButton : public QObject
+{
+    Q_OBJECT
+    /**
+     * Whether the DecorationButton is visible. By default this is @c true, OnAllDesktops and
+     * QuickHelp depend on the DecoratedClient's state.
+     **/
+    Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged)
+    /**
+     * Whether the DecorationButton is currently pressed.
+     **/
+    Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged)
+    /**
+     * Whether the DecorationButton is currently hovered.
+     **/
+    Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged)
+    /**
+     * Whether the DecorationButton is enabled. Only an enabled button accepts hover and mouse
+     * press events.
+     **/
+    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
+    /**
+     * Whether the DecorationButton can be checked. This is used for state aware DecorationButtons
+     * like Maximize, Shade, KeepAbove, KeepBelow and OnAllDesktops.
+     **/
+    Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged)
+    /**
+     * Whether the DecorationButton is checked. A DecorationButton can only be checked if the
+     * DecorationButton is checkable. Note: the checked state is not changed by clicking the
+     * DecorationButton. It gets changed if the DecoratedClient changes it's state, though.
+     **/
+    Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged)
+    /**
+     * The geometry of the DecorationButton in Decoration-local coordinates.
+     **/
+    Q_PROPERTY(QRectF geometry READ geometry NOTIFY geometryChanged)
+    /**
+     * The mouse buttons the DecorationButton accepts. By default the Qt::LeftButton gets accepted,
+     * for some types more buttons are accepted.
+     **/
+    Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
+public:
+    ~DecorationButton() override;
+
+    QRectF geometry() const;
+    QSizeF size() const;
+    void setGeometry(const QRectF &geometry);
+
+    bool isVisible() const;
+    bool isPressed() const;
+    bool isHovered() const;
+    bool isEnabled() const;
+    bool isChecked() const;
+    bool isCheckable() const;
+    DecorationButtonType type() const;
+
+    /**
+     * Returns @c true if @p pos is inside of the button, otherwise returns @c false.
+     **/
+    bool contains(const QPointF &pos) const;
+
+    Qt::MouseButtons acceptedButtons() const;
+    void setAcceptedButtons(Qt::MouseButtons buttons);
+
+    /**
+     * Invoked for painting this DecorationButtons. Implementing sub-classes need to implement
+     * this method. The coordinate system of the QPainter is set to Decoration coordinates.
+     *
+     * This method will be invoked from the rendering thread.
+     *
+     * @param painter The QPainter to paint this DecorationButton.
+     * @param repaintArea The area which is going to be repainted in Decoration coordinates
+     **/
+    virtual void paint(QPainter *painter, const QRect &repaintArea) = 0;
+
+    Decoration *decoration() const;
+
+    bool event(QEvent *event) override;
+
+public Q_SLOTS:
+    void setEnabled(bool enabled);
+    void setCheckable(bool checkable);
+    void setChecked(bool checked);
+    void setVisible(bool visible);
+
+    /**
+     * Schedules a repaint of the DecorationButton.
+     * Calling update will eventually result in paint being invoked.
+     *
+     * @param rect The area to repaint in Decoration local coordinates, a null QRect updates the complete geometry
+     * @see paint
+     **/
+    void update(const QRectF &rect);
+    /**
+     * Schedules a repaint of the DecorationButton.
+     *
+     * Overloaded method for convenience.
+     **/
+    void update();
+
+Q_SIGNALS:
+    void clicked(Qt::MouseButton);
+    void pressed();
+    void released();
+    void pointerEntered();
+    void pointerLeft();
+    void doubleClicked();
+
+    void pressedChanged(bool);
+    void hoveredChanged(bool);
+    void enabledChanged(bool);
+    void checkableChanged(bool);
+    void checkedChanged(bool);
+    void geometryChanged(const QRectF &);
+    void acceptedButtonsChanged(Qt::MouseButtons);
+    void visibilityChanged(bool);
+
+protected:
+    explicit DecorationButton(DecorationButtonType type, Decoration *decoration, QObject *parent = nullptr);
+
+    virtual void hoverEnterEvent(QHoverEvent *event);
+    virtual void hoverLeaveEvent(QHoverEvent *event);
+    virtual void hoverMoveEvent(QHoverEvent *event);
+    virtual void mouseMoveEvent(QMouseEvent *event);
+    virtual void mousePressEvent(QMouseEvent *event);
+    virtual void mouseReleaseEvent(QMouseEvent *event);
+    virtual void wheelEvent(QWheelEvent *event);
+
+private:
+    class Private;
+    std::unique_ptr<Private> d;
+};
+
+} // namespace
+
+#ifndef K_DOXYGEN
+size_t KDECORATIONS2_EXPORT qHash(const KDecoration2::DecorationButtonType &type, size_t seed = 0);
+#endif
+
+Q_DECLARE_METATYPE(KDecoration2::DecorationButtonType)
diff --git a/src/decorationbutton_p.h b/src/decorationbutton_p.h
new file mode 100644 (file)
index 0000000..5ceeaaf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "decorationbutton.h"
+
+#include <QPointer>
+
+class QElapsedTimer;
+class QTimer;
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+namespace KDecoration2
+{
+class Q_DECL_HIDDEN DecorationButton::Private
+{
+public:
+    explicit Private(DecorationButtonType type, const QPointer<Decoration> &decoration, DecorationButton *parent);
+    ~Private();
+
+    bool isPressed() const
+    {
+        return m_pressed != Qt::NoButton;
+    }
+    bool isPressed(Qt::MouseButton button) const
+    {
+        return m_pressed.testFlag(button);
+    }
+
+    void setHovered(bool hovered);
+    void setPressed(Qt::MouseButton, bool pressed);
+    void setAcceptedButtons(Qt::MouseButtons buttons);
+    void setEnabled(bool enabled);
+    void setChecked(bool checked);
+    void setCheckable(bool checkable);
+    void setVisible(bool visible);
+    void startDoubleClickTimer();
+    void invalidateDoubleClickTimer();
+    bool wasDoubleClick() const;
+    void setPressAndHold(bool enable);
+    void startPressAndHold();
+    void stopPressAndHold();
+
+    QString typeToString(DecorationButtonType type);
+
+    QPointer<Decoration> decoration;
+    DecorationButtonType type;
+    QRectF geometry;
+    bool hovered;
+    bool enabled;
+    bool checkable;
+    bool checked;
+    bool visible;
+    Qt::MouseButtons acceptedButtons;
+    bool doubleClickEnabled;
+    bool pressAndHold;
+
+private:
+    void init();
+    DecorationButton *q;
+    Qt::MouseButtons m_pressed;
+    std::unique_ptr<QElapsedTimer> m_doubleClickTimer;
+    std::unique_ptr<QTimer> m_pressAndHoldTimer;
+};
+
+}
diff --git a/src/decorationbuttongroup.cpp b/src/decorationbuttongroup.cpp
new file mode 100644 (file)
index 0000000..8cc8ac1
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decorationbuttongroup.h"
+#include "decoration.h"
+#include "decorationbuttongroup_p.h"
+#include "decorationsettings.h"
+
+#include <QDebug>
+#include <QGuiApplication>
+
+namespace KDecoration2
+{
+DecorationButtonGroup::Private::Private(Decoration *decoration, DecorationButtonGroup *parent)
+    : decoration(decoration)
+    , spacing(0.0)
+    , q(parent)
+{
+}
+
+DecorationButtonGroup::Private::~Private() = default;
+
+void DecorationButtonGroup::Private::setGeometry(const QRectF &geo)
+{
+    if (geometry == geo) {
+        return;
+    }
+    geometry = geo;
+    Q_EMIT q->geometryChanged(geometry);
+}
+
+namespace
+{
+static bool s_layoutRecursion = false;
+}
+
+void DecorationButtonGroup::Private::updateLayout()
+{
+    if (s_layoutRecursion) {
+        return;
+    }
+    s_layoutRecursion = true;
+    const QPointF &pos = geometry.topLeft();
+    // first calculate new size
+    qreal height = 0;
+    qreal width = 0;
+    for (auto it = buttons.constBegin(); it != buttons.constEnd(); ++it) {
+        if (!(*it)->isVisible()) {
+            continue;
+        }
+        height = qMax(height, qreal((*it)->size().height()));
+        width += (*it)->size().width();
+        if (it + 1 != buttons.constEnd()) {
+            width += spacing;
+        }
+    }
+    setGeometry(QRectF(pos, QSizeF(width, height)));
+
+    QGuiApplication* app = qobject_cast<QGuiApplication*>(QCoreApplication::instance());
+    const auto layoutDirection = app ? app->layoutDirection() : Qt::LeftToRight;
+
+    qreal leftPosition = pos.x();
+    qreal rightPosition = pos.x() + width;
+
+    if (layoutDirection == Qt::LeftToRight)
+        for (auto button : std::as_const(buttons)) {
+            if (!button->isVisible()) {
+                continue;
+            }
+            const auto size = button->size();
+            const auto buttonPos = QPointF(leftPosition, pos.y());
+            button->setGeometry(QRectF(buttonPos, size));
+            leftPosition += size.width() + spacing;
+        }
+    else if (layoutDirection == Qt::RightToLeft)
+        for (auto button : std::as_const(buttons)) {
+            if (!button->isVisible()) {
+                continue;
+            }
+            const auto size = button->size();
+            const auto buttonPos = QPointF(rightPosition - size.width(), pos.y());
+            button->setGeometry(QRectF(buttonPos, size));
+            rightPosition -= size.width() + spacing;
+        }
+    else {
+        qCritical() << "There's an unhandled layout direction! This is likely an issue of KDecoration2 not being updated to handle it\n"
+                    << "or the application having an invalid layout direction set. Either way, this is a critical bug.";
+    }
+
+    s_layoutRecursion = false;
+}
+
+DecorationButtonGroup::DecorationButtonGroup(Decoration *parent)
+    : QObject(parent)
+    , d(new Private(parent, this))
+{
+}
+
+DecorationButtonGroup::DecorationButtonGroup(DecorationButtonGroup::Position type,
+                                             Decoration *parent,
+                                             std::function<DecorationButton *(DecorationButtonType, Decoration *, QObject *)> buttonCreator)
+    : QObject(parent)
+    , d(new Private(parent, this))
+{
+    auto createButtons = [this, buttonCreator, type] {
+        const Qt::LayoutDirection layoutDirection = QGuiApplication::layoutDirection();
+        const DecorationSettings *settings = d->decoration->settings().get();
+        const auto &buttons =
+            (type == Position::Left) ?
+                (layoutDirection == Qt::LeftToRight ? settings->decorationButtonsLeft() : settings->decorationButtonsRight()) :
+                (layoutDirection == Qt::LeftToRight ? settings->decorationButtonsRight() : settings->decorationButtonsLeft());
+        for (DecorationButtonType type : buttons) {
+            if (DecorationButton *b = buttonCreator(type, d->decoration, this)) {
+                addButton(b);
+            }
+        }
+    };
+    createButtons();
+    auto changed = type == Position::Left ? &DecorationSettings::decorationButtonsLeftChanged : &DecorationSettings::decorationButtonsRightChanged;
+    connect(parent->settings().get(), changed, this, [this, createButtons] {
+        qDeleteAll(d->buttons);
+        d->buttons.clear();
+        createButtons();
+    });
+}
+
+DecorationButtonGroup::~DecorationButtonGroup() = default;
+
+Decoration *DecorationButtonGroup::decoration() const
+{
+    return d->decoration;
+}
+
+QRectF DecorationButtonGroup::geometry() const
+{
+    return d->geometry;
+}
+
+bool DecorationButtonGroup::hasButton(DecorationButtonType type) const
+{
+    // TODO: check for deletion of button
+    auto it = std::find_if(d->buttons.begin(), d->buttons.end(), [type](DecorationButton *button) {
+        return button->type() == type;
+    });
+    return it != d->buttons.end();
+}
+
+qreal DecorationButtonGroup::spacing() const
+{
+    return d->spacing;
+}
+
+QPointF DecorationButtonGroup::pos() const
+{
+    return d->geometry.topLeft();
+}
+
+void DecorationButtonGroup::setPos(const QPointF &pos)
+{
+    if (d->geometry.topLeft() == pos) {
+        return;
+    }
+    d->setGeometry(QRectF(pos, d->geometry.size()));
+    d->updateLayout();
+}
+
+void DecorationButtonGroup::setSpacing(qreal spacing)
+{
+    if (d->spacing == spacing) {
+        return;
+    }
+    d->spacing = spacing;
+    Q_EMIT spacingChanged(d->spacing);
+    d->updateLayout();
+}
+
+void DecorationButtonGroup::addButton(DecorationButton *button)
+{
+    Q_ASSERT(button);
+    connect(button, &DecorationButton::visibilityChanged, this, [this]() {
+        d->updateLayout();
+    });
+    connect(button, &DecorationButton::geometryChanged, this, [this]() {
+        d->updateLayout();
+    });
+    d->buttons.append(button);
+    d->updateLayout();
+}
+
+QList<DecorationButton *> DecorationButtonGroup::buttons() const
+{
+    return d->buttons;
+}
+
+void DecorationButtonGroup::removeButton(DecorationButtonType type)
+{
+    bool needUpdate = false;
+    auto it = d->buttons.begin();
+    while (it != d->buttons.end()) {
+        if ((*it)->type() == type) {
+            it = d->buttons.erase(it);
+            needUpdate = true;
+        } else {
+            it++;
+        }
+    }
+    if (needUpdate) {
+        d->updateLayout();
+    }
+}
+
+void DecorationButtonGroup::removeButton(DecorationButton *button)
+{
+    bool needUpdate = false;
+    auto it = d->buttons.begin();
+    while (it != d->buttons.end()) {
+        if (*it == button) {
+            it = d->buttons.erase(it);
+            needUpdate = true;
+        } else {
+            it++;
+        }
+    }
+    if (needUpdate) {
+        d->updateLayout();
+    }
+}
+
+void DecorationButtonGroup::paint(QPainter *painter, const QRect &repaintArea)
+{
+    const auto &buttons = d->buttons;
+    for (auto button : buttons) {
+        if (!button->isVisible()) {
+            continue;
+        }
+        button->paint(painter, repaintArea);
+    }
+}
+
+} // namespace
+
+#include "moc_decorationbuttongroup.cpp"
diff --git a/src/decorationbuttongroup.h b/src/decorationbuttongroup.h
new file mode 100644 (file)
index 0000000..f4317ee
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+#include "decorationbutton.h"
+#include <functional>
+#include <kdecoration2/kdecoration2_export.h>
+
+class QPainter;
+
+namespace KDecoration2
+{
+class Decoration;
+class DecorationButtonGroupPrivate;
+
+/**
+ * @brief Helper class to layout DecorationButton.
+ *
+ * A Decoration normally has two groups of DecorationButtons: one left of the caption and one
+ * right of the caption. The DecorationButtonGroup helps in positioning the DecorationButtons in
+ * these groups and to update the position of each of the DecorationButtons whenever the state
+ * changes in a way that they should be repositioned.
+ *
+ * A DecorationButtonGroup is a visual layout element not accepting input events. As a visual
+ * element it provides a paint method allowing a sub class to provide custom painting for the
+ * DecorationButtonGroup.
+ **/
+class KDECORATIONS2_EXPORT DecorationButtonGroup : public QObject
+{
+    Q_OBJECT
+    /**
+     * The spacing to use between the DecorationButtons
+     **/
+    Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+    /**
+     * The geometry of the DecorationButtonGroup in Decoration-local coordinates.
+     * The size of the DecorationButtonGroup depends on the sizes of the individual
+     * DecorationButtons and the spacing.
+     **/
+    Q_PROPERTY(QRectF geometry READ geometry NOTIFY geometryChanged)
+    // TODO: pos must consider whether it's left or right
+    /**
+     * The top left Position of the DecorationButtonGroup. This property needs to be
+     * changed to reposition the DecorationButtonGroup. An update should normally be
+     * triggered after e.g. a state change like maximization.
+     **/
+    Q_PROPERTY(QPointF pos READ pos WRITE setPos NOTIFY posChanged)
+public:
+    enum class Position {
+        Left,
+        Right,
+    };
+    explicit DecorationButtonGroup(Position type,
+                                   Decoration *parent,
+                                   std::function<DecorationButton *(DecorationButtonType, Decoration *, QObject *)> buttonCreator);
+    explicit DecorationButtonGroup(Decoration *parent);
+    ~DecorationButtonGroup() override;
+
+    /**
+     * Paints the DecorationButtonGroup. This method should normally be invoked from the
+     * Decoration's paint method. Base implementation just calls the paint method on each
+     * of the DecorationButtons. Overwriting sub classes need to either call the base
+     * implementation or ensure that the DecorationButtons are painted.
+     *
+     * @param painter The QPainter which is used to paint this DecorationButtonGroup
+     * @param repaintArea The area which is going to be repainted in Decoration coordinates
+     **/
+    virtual void paint(QPainter *painter, const QRect &repaintArea);
+
+    Decoration *decoration() const;
+
+    qreal spacing() const;
+    void setSpacing(qreal spacing);
+
+    QRectF geometry() const;
+    QPointF pos() const;
+    void setPos(const QPointF &pos);
+
+    /**
+     * Adds @p button to the DecorationButtonGroup and triggers a re-layout of all
+     * DecorationButtons.
+     **/
+    void addButton(DecorationButton *button);
+    /**
+     * Removes @p button from the DecorationButtonGroup and triggers a re-layout of all
+     * DecorationButtons.
+     **/
+    void removeButton(DecorationButton *button);
+    /**
+     * Removes all DecorationButtons with @p type from the DecorationButtonGroup and
+     * triggers a re-layout of all DecorationButtons.
+     **/
+    void removeButton(DecorationButtonType type);
+    /**
+     * @returns @c true if the DecorationButtonGroup contains a DecorationButton of @p type
+     **/
+    bool hasButton(DecorationButtonType type) const;
+    /**
+     * @returns All DecorationButtons in this DecorationButtonGroup
+     **/
+    QList<DecorationButton *> buttons() const;
+
+Q_SIGNALS:
+    void spacingChanged(qreal);
+    void geometryChanged(const QRectF &);
+    void posChanged(const QPointF &);
+
+private:
+    class Private;
+    std::unique_ptr<Private> d;
+};
+
+} // namespace
diff --git a/src/decorationbuttongroup_p.h b/src/decorationbuttongroup_p.h
new file mode 100644 (file)
index 0000000..89604ec
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+#include "decorationbuttongroup.h"
+
+#include <QList>
+#include <QRectF>
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+namespace KDecoration2
+{
+class Decoration;
+
+class Q_DECL_HIDDEN DecorationButtonGroup::Private
+{
+public:
+    explicit Private(Decoration *decoration, DecorationButtonGroup *parent);
+    ~Private();
+
+    void setGeometry(const QRectF &geometry);
+    void updateLayout();
+
+    Decoration *decoration;
+    QRectF geometry;
+    QList<DecorationButton *> buttons;
+    qreal spacing;
+
+private:
+    DecorationButtonGroup *q;
+};
+
+} // namespace
diff --git a/src/decorationdefines.h b/src/decorationdefines.h
new file mode 100644 (file)
index 0000000..523c3cc
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+namespace KDecoration2
+{
+/**
+ * The DecorationButtonType is a helper type for the DecorationButton.
+ * A Decoration should provide a DecorationButton for each of the types,
+ * if it wants to provide further buttons it should use the Custom type.
+ * The DecorationButton gets configured depending on the type. E.g. the
+ * Close button gets disabled if the DecoratedClient is not closeable.
+ **/
+enum class DecorationButtonType {
+    /**
+     * The Menu button requests showing the window menu on left or right click.
+     **/
+    Menu,
+    /**
+     * The ApplicationMenu button requests showing the application's menu on left or right click.
+     */
+    ApplicationMenu,
+    /**
+     * The OnAllDesktops button requests toggling the DecoratedClient's on all desktops state.
+     * The DecoratedButton is only visible if multiple virtual desktops are available.
+     **/
+    OnAllDesktops,
+    /**
+     * The Minimize button requests minimizing the DecoratedClient. The DecorationButton is only
+     * enabled if the DecoratedClient is minimizeable.
+     **/
+    Minimize,
+    /**
+     * The Maximize button requests maximizing the DecoratedClient. The DecorationButton is checkable
+     * and if the DecoratedClient is maximized the DecorationButton is checked. The DecorationButton
+     * supports multiple mouse buttons to change horizontal, vertical and overall maximized state.
+     *
+     * The DecorationButton is only enabled if the DecoratedClient is maximizeable.
+     **/
+    Maximize,
+    /**
+     * The Close button requests closing the DecoratedClient. The DecorationButton is only enabled
+     * if the DecoratedClient is closeable.
+     **/
+    Close,
+    /**
+     * The ContextHelp button requests entering the context help mode. The DecorationButton is only
+     * visible if the DecoratedClient provides context help.
+     **/
+    ContextHelp,
+    /**
+     * The Shade button requests toggling the DecoratedClient's shaded state. The DecoratedButton
+     * is only enabled if the DecoratedClient is shadeable.
+     **/
+    Shade,
+    /**
+     * The KeepBelow button requests toggling the DecoratedClient's keep below state.
+     **/
+    KeepBelow,
+    /**
+     * The KeepAbove button requests toggling the DecoratedClient's keep above state.
+     **/
+    KeepAbove,
+    /**
+     * The Custom type allows a Decoration to provide custom DecorationButtons.
+     **/
+    Custom,
+    /**
+     * The Spacer button provides some space between buttons.
+     */
+    Spacer,
+};
+
+/**
+ * Border sizes are a combination of visual and accessibility features.
+ * Larger borders should be used to increase the non title bar borders to
+ * make it easier to resize the decoration
+ **/
+enum class BorderSize {
+    /**
+     * Border sizes of all non title bar sides should be set to 0.
+     **/
+    None,
+    /**
+     * Border sizes of the sides should be set to 0. Title bar and
+     * the border on opposite side of the title bar should follow the
+     * Normal settings.
+     **/
+    NoSides,
+    /**
+     * Borders should be smaller than Normal, e.g. a factor of 0.5.
+     **/
+    Tiny,
+    /**
+     * The default border size with borders on each side. This should
+     * be the base for calculating other border sizes.
+     **/
+    Normal,
+    /**
+     * Increased border sizes, considered a factor of 1.5.
+     **/
+    Large,
+    /**
+     * Increased border sizes, considered a factor of 2.0.
+     **/
+    VeryLarge,
+    /**
+     * Increased border sizes, considered a factor of 2.5.
+     **/
+    Huge,
+    /**
+     * Increased border sizes, considered a factor of 3.0.
+     **/
+    VeryHuge,
+    /**
+     * Increased border sizes, considered a factor of 5.0.
+     **/
+    Oversized,
+};
+
+/**
+ * Color groups are used for DecoratedClient::color().
+ * @since 5.3
+ **/
+enum class ColorGroup {
+    /**
+     * Inactive color, used for unfocused windows.
+     **/
+    Inactive,
+    /**
+     * Active color, used for focused windows.
+     **/
+    Active,
+    /**
+     * Warning color, can only be used with ColorRole::Foreground. If used with other roles,
+     * a invalid QColor is returned. It can be used for close buttons and is typically red.
+     **/
+    Warning,
+};
+
+/**
+ * Color roles are used for DecoratedClient::color().
+ * @since 5.3
+ **/
+enum class ColorRole {
+    /**
+     * The decoration's frame background color.
+     **/
+    Frame,
+    /**
+     * The decoration's title bar background color
+     **/
+    TitleBar,
+    /**
+     * The decoration's title bar forground color
+     **/
+    Foreground,
+};
+
+}
diff --git a/src/decorationsettings.cpp b/src/decorationsettings.cpp
new file mode 100644 (file)
index 0000000..f71f25a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decorationsettings.h"
+#include "private/decorationbridge.h"
+#include "private/decorationsettingsprivate.h"
+
+#include <QFontMetrics>
+
+namespace KDecoration2
+{
+DecorationSettings::DecorationSettings(DecorationBridge *bridge, QObject *parent)
+    : QObject(parent)
+    , d(bridge->settings(this))
+{
+    auto updateUnits = [this] {
+        int gridUnit = QFontMetrics(font()).boundingRect(QLatin1Char('M')).height();
+        ;
+        if (gridUnit % 2 != 0) {
+            gridUnit++;
+        }
+        if (gridUnit != d->gridUnit()) {
+            d->setGridUnit(gridUnit);
+            Q_EMIT gridUnitChanged(gridUnit);
+        }
+        if (gridUnit != d->largeSpacing()) {
+            d->setSmallSpacing(qMax(2, (int)(gridUnit / 4))); // 1/4 of gridUnit, at least 2
+            d->setLargeSpacing(gridUnit); // msize.height
+            Q_EMIT spacingChanged();
+        }
+    };
+    updateUnits();
+    connect(this, &DecorationSettings::fontChanged, this, updateUnits);
+}
+
+DecorationSettings::~DecorationSettings() = default;
+
+bool DecorationSettings::isOnAllDesktopsAvailable() const
+{
+    return d->isOnAllDesktopsAvailable();
+}
+
+bool DecorationSettings::isAlphaChannelSupported() const
+{
+    return d->isAlphaChannelSupported();
+}
+
+bool DecorationSettings::isCloseOnDoubleClickOnMenu() const
+{
+    return d->isCloseOnDoubleClickOnMenu();
+}
+
+QList<DecorationButtonType> DecorationSettings::decorationButtonsLeft() const
+{
+    return d->decorationButtonsLeft();
+}
+
+QList<DecorationButtonType> DecorationSettings::decorationButtonsRight() const
+{
+    return d->decorationButtonsRight();
+}
+
+BorderSize DecorationSettings::borderSize() const
+{
+    return d->borderSize();
+}
+
+QFont DecorationSettings::font() const
+{
+    return d->font();
+}
+
+QFontMetricsF DecorationSettings::fontMetrics() const
+{
+    return d->fontMetrics();
+}
+
+int DecorationSettings::gridUnit() const
+{
+    return d->gridUnit();
+}
+
+int DecorationSettings::smallSpacing() const
+{
+    return d->smallSpacing();
+}
+
+int DecorationSettings::largeSpacing() const
+{
+    return d->largeSpacing();
+}
+}
+
+#include "moc_decorationsettings.cpp"
diff --git a/src/decorationsettings.h b/src/decorationsettings.h
new file mode 100644 (file)
index 0000000..bc13e31
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "decorationbutton.h"
+#include <kdecoration2/kdecoration2_export.h>
+
+#include <QFontMetricsF>
+#include <QObject>
+
+#include <memory>
+
+namespace KDecoration2
+{
+class DecorationBridge;
+class DecorationSettingsPrivate;
+
+/**
+ * @brief Common settings for the Decoration.
+ *
+ * This class gets injected into the Decoration and provides recommendations for the
+ * Decoration. The Decoration is suggested to honor the settings, but may decide that some
+ * settings don't fit the design and ignore them.
+ *
+ * @see Decoration
+ **/
+class KDECORATIONS2_EXPORT DecorationSettings : public QObject
+{
+    Q_OBJECT
+    /**
+     * Whether the feature to put a DecoratedClient on all desktops is available.
+     *
+     * If this feature is not available a Decoration might decide to not show the
+     * DecorationButtonType::OnAllDesktops.
+     **/
+    Q_PROPERTY(bool onAllDesktopsAvailable READ isOnAllDesktopsAvailable NOTIFY onAllDesktopsAvailableChanged)
+    /**
+     * Whether the Decoration will be rendered with an alpha channel.
+     *
+     * If no alpha channel is available a Decoration should not use round borders.
+     **/
+    Q_PROPERTY(bool alphaChannelSupported READ isAlphaChannelSupported NOTIFY alphaChannelSupportedChanged)
+    /**
+     * Whether the Decoration should close the DecoratedClient when double clicking on the
+     * DecorationButtonType::Menu.
+     **/
+    Q_PROPERTY(bool closeOnDoubleClickOnMenu READ isCloseOnDoubleClickOnMenu NOTIFY closeOnDoubleClickOnMenuChanged)
+    /**
+     * The suggested ordering of the decoration buttons on the left.
+     **/
+    Q_PROPERTY(QList<KDecoration2::DecorationButtonType> decorationButtonsLeft READ decorationButtonsLeft NOTIFY decorationButtonsLeftChanged)
+    /**
+     * The suggested ordering of the decoration buttons on the right.
+     **/
+    Q_PROPERTY(QList<KDecoration2::DecorationButtonType> decorationButtonsRight READ decorationButtonsRight NOTIFY decorationButtonsRightChanged)
+    /**
+     * The suggested border size.
+     **/
+    Q_PROPERTY(KDecoration2::BorderSize borderSize READ borderSize NOTIFY borderSizeChanged)
+    /**
+     * The fundamental unit of space that should be used for sizes, expressed in pixels.
+     * Given the screen has an accurate DPI settings, it corresponds to a millimeter
+     */
+    Q_PROPERTY(int gridUnit READ gridUnit NOTIFY gridUnitChanged)
+    /**
+     * The recommended font for the Decoration's caption.
+     **/
+    Q_PROPERTY(QFont font READ font NOTIFY fontChanged)
+    /**
+     * smallSpacing is the amount of spacing that should be used around smaller UI elements,
+     * for example as spacing in Columns. Internally, this size depends on the size of
+     * the default font as rendered on the screen, so it takes user-configured font size and DPI
+     * into account.
+     */
+    Q_PROPERTY(int smallSpacing READ smallSpacing NOTIFY spacingChanged)
+
+    /**
+     * largeSpacing is the amount of spacing that should be used inside bigger UI elements,
+     * for example between an icon and the corresponding text. Internally, this size depends on
+     * the size of the default font as rendered on the screen, so it takes user-configured font
+     * size and DPI into account.
+     */
+    Q_PROPERTY(int largeSpacing READ largeSpacing NOTIFY spacingChanged)
+public:
+    explicit DecorationSettings(DecorationBridge *bridge, QObject *parent = nullptr);
+    ~DecorationSettings() override;
+    bool isOnAllDesktopsAvailable() const;
+    bool isAlphaChannelSupported() const;
+    bool isCloseOnDoubleClickOnMenu() const;
+    QList<DecorationButtonType> decorationButtonsLeft() const;
+    QList<DecorationButtonType> decorationButtonsRight() const;
+    BorderSize borderSize() const;
+
+    QFont font() const;
+    /**
+     * The fontMetrics for the recommended font.
+     * @see font
+     **/
+    QFontMetricsF fontMetrics() const;
+
+    int gridUnit() const;
+    int smallSpacing() const;
+    int largeSpacing() const;
+
+Q_SIGNALS:
+    void onAllDesktopsAvailableChanged(bool);
+    void alphaChannelSupportedChanged(bool);
+    void closeOnDoubleClickOnMenuChanged(bool);
+    void decorationButtonsLeftChanged(const QList<KDecoration2::DecorationButtonType> &);
+    void decorationButtonsRightChanged(const QList<KDecoration2::DecorationButtonType> &);
+    void borderSizeChanged(KDecoration2::BorderSize size);
+    void fontChanged(const QFont &font);
+    void gridUnitChanged(int);
+    void spacingChanged();
+
+    /**
+     * This signal is emitted when the backend got reconfigured.
+     * If the plugin uses custom settings, it is recommended to re-read
+     * them after this signal got emitted.
+     **/
+    void reconfigured();
+
+private:
+    const std::unique_ptr<DecorationSettingsPrivate> d;
+};
+
+}
+
+Q_DECLARE_METATYPE(KDecoration2::BorderSize)
diff --git a/src/decorationshadow.cpp b/src/decorationshadow.cpp
new file mode 100644 (file)
index 0000000..9a3c36d
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decorationshadow.h"
+#include "decorationshadow_p.h"
+
+namespace KDecoration2
+{
+DecorationShadow::Private::Private(DecorationShadow *parent)
+    : q(parent)
+{
+}
+
+DecorationShadow::Private::~Private() = default;
+
+DecorationShadow::DecorationShadow()
+    : QObject()
+    , d(new Private(this))
+{
+}
+
+DecorationShadow::~DecorationShadow() = default;
+
+QRect DecorationShadow::topLeftGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(0, 0, d->innerShadowRect.left(), d->innerShadowRect.top());
+}
+
+QRect DecorationShadow::topGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(d->innerShadowRect.left(), 0, d->innerShadowRect.width(), d->innerShadowRect.top());
+}
+
+QRect DecorationShadow::topRightGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(d->innerShadowRect.left() + d->innerShadowRect.width(),
+                 0,
+                 d->shadow.width() - d->innerShadowRect.width() - d->innerShadowRect.left(),
+                 d->innerShadowRect.top());
+}
+
+QRect DecorationShadow::rightGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(d->innerShadowRect.left() + d->innerShadowRect.width(),
+                 d->innerShadowRect.top(),
+                 d->shadow.width() - d->innerShadowRect.width() - d->innerShadowRect.left(),
+                 d->innerShadowRect.height());
+}
+
+QRect DecorationShadow::bottomRightGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(d->innerShadowRect.left() + d->innerShadowRect.width(),
+                 d->innerShadowRect.top() + d->innerShadowRect.height(),
+                 d->shadow.width() - d->innerShadowRect.width() - d->innerShadowRect.left(),
+                 d->shadow.height() - d->innerShadowRect.top() - d->innerShadowRect.height());
+}
+
+QRect DecorationShadow::bottomGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(d->innerShadowRect.left(),
+                 d->innerShadowRect.top() + d->innerShadowRect.height(),
+                 d->innerShadowRect.width(),
+                 d->shadow.height() - d->innerShadowRect.top() - d->innerShadowRect.height());
+}
+
+QRect DecorationShadow::bottomLeftGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(0,
+                 d->innerShadowRect.top() + d->innerShadowRect.height(),
+                 d->innerShadowRect.left(),
+                 d->shadow.height() - d->innerShadowRect.top() - d->innerShadowRect.height());
+}
+
+QRect DecorationShadow::leftGeometry() const
+{
+    if (d->innerShadowRect.isNull() || d->shadow.isNull()) {
+        return QRect();
+    }
+    return QRect(0, d->innerShadowRect.top(), d->innerShadowRect.left(), d->innerShadowRect.height());
+}
+
+#ifndef K_DOXYGEN
+
+QImage DecorationShadow::shadow() const
+{
+    return d->shadow;
+}
+
+QMargins DecorationShadow::padding() const
+{
+    return d->padding;
+}
+
+QRect DecorationShadow::innerShadowRect() const
+{
+    return d->innerShadowRect;
+}
+
+int DecorationShadow::paddingTop() const
+{
+    return d->padding.top();
+}
+
+int DecorationShadow::paddingBottom() const
+{
+    return d->padding.bottom();
+}
+
+int DecorationShadow::paddingRight() const
+{
+    return d->padding.right();
+}
+
+int DecorationShadow::paddingLeft() const
+{
+    return d->padding.left();
+}
+
+void DecorationShadow::setShadow(const QImage &shadow)
+{
+    if (d->shadow == shadow) {
+        return;
+    }
+    d->shadow = shadow;
+    Q_EMIT shadowChanged(d->shadow);
+}
+
+#endif
+
+void DecorationShadow::setPadding(const QMargins &margins)
+{
+    if (d->padding == margins) {
+        return;
+    }
+    d->padding = margins;
+    Q_EMIT paddingChanged();
+}
+
+void DecorationShadow::setInnerShadowRect(const QRect &rect)
+{
+    if (d->innerShadowRect == rect) {
+        return;
+    }
+    d->innerShadowRect = rect;
+    Q_EMIT innerShadowRectChanged();
+}
+
+}
+
+#include "moc_decorationshadow.cpp"
diff --git a/src/decorationshadow.h b/src/decorationshadow.h
new file mode 100644 (file)
index 0000000..fb6a3fc
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include <kdecoration2/kdecoration2_export.h>
+
+#include <QImage>
+#include <QMargins>
+#include <QObject>
+
+namespace KDecoration2
+{
+class DecorationShadowPrivate;
+
+/**
+ * @brief A wrapper to define the shadow around the Decoration.
+ *
+ * The shadow around the Decoration should not be rendered as part of the Decoration.
+ * Instead a DecorationShadow should be used. That way a backend can optimize the
+ * rendering of the shadow in a better way. If the shadow were part of the Decoration
+ * directly it would need to be updated when the rendering changes. By using a dedicated
+ * DecorationShadow the same shadow can be shared between multiple DecoratedClients.
+ *
+ * The DecorationShadow consists of a shadow QImage which is composed of multiple parts:
+ * @li topLeft: rendered as it is
+ * @li top: stretched in x direction
+ * @li topRight: rendered as it is
+ * @li right: stretched in y direction
+ * @li bottomRight: rendered as it is
+ * @li bottom: stretched in x direction
+ * @li bottomLeft: rendered as it is
+ * @li left: stretched in y direction
+ *
+ * The sizes of these parts is denoted in the property innerShadowRect and the layout is the
+ * following:
+ * #######################################
+ * # topLeft #     top        # topRight #
+ * #######################################
+ * # left #                      # right #
+ * #######################################
+ * # bottomLeft #  bottom  # bottomRight #
+ * #######################################
+ *
+ * The innerShadowRect property is a QRect of the geometry of the areas not covered by any of the
+ * elements. This means that:
+ * @li x/y of the rect is the same as the size of the topLeft element
+ * @li width of the rect is the same as the width of the top and bottom element
+ * @li height of the rect is the same as the height of the left and the right element
+ * By that the actual sizes of all elements can be derived out of the size of the shadow image
+ * and the innerShadowRect.
+ *
+ * The position of the rendering depends on the values;
+ * @li paddingTop
+ * @li paddingRight
+ * @li paddingBottom
+ * @li paddingLeft
+ *
+ * The top left element is rendered with an offset of paddingLeft and paddingTop.
+ * The non-stretched elements are rendered in the size as specified, the area
+ * between two non-stretched elements (e.g. between topLeft and topRight) is filled
+ * by the element with one direction stretched and the other direction fixed at the
+ * corresponding padding value. E.g. the top element is stretched in x direction and
+ * fixed at paddingTop value. If stretching the side elements is not wanted one needs
+ * to provide a shadow image with those elements at a size that stretching is not
+ * required.
+ *
+ * If the padding values are smaller than the sizes of the shadow elements the shadow
+ * will overlap with the Decoration and be rendered behind the Decoration.
+ *
+ **/
+class KDECORATIONS2_EXPORT DecorationShadow : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QImage shadow READ shadow WRITE setShadow NOTIFY shadowChanged)
+    Q_PROPERTY(QRect innerShadowRect READ innerShadowRect WRITE setInnerShadowRect NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect topLeftGeometry READ topLeftGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect topGeometry READ topGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect topRightGeometry READ topRightGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect rightGeometry READ rightGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect bottomRightGeometry READ bottomRightGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect bottomGeometry READ bottomGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect bottomLeftGeometry READ bottomLeftGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(QRect leftGeometry READ leftGeometry NOTIFY innerShadowRectChanged)
+    Q_PROPERTY(int paddingTop READ paddingTop NOTIFY paddingChanged)
+    Q_PROPERTY(int paddingRight READ paddingRight NOTIFY paddingChanged)
+    Q_PROPERTY(int paddingBottom READ paddingBottom NOTIFY paddingChanged)
+    Q_PROPERTY(int paddingLeft READ paddingLeft NOTIFY paddingChanged)
+    Q_PROPERTY(QMargins padding READ padding WRITE setPadding NOTIFY paddingChanged)
+public:
+    explicit DecorationShadow();
+    ~DecorationShadow() override;
+
+    QImage shadow() const;
+    QRect innerShadowRect() const;
+    QRect topLeftGeometry() const;
+    QRect topGeometry() const;
+    QRect topRightGeometry() const;
+    QRect rightGeometry() const;
+    QRect bottomRightGeometry() const;
+    QRect bottomGeometry() const;
+    QRect bottomLeftGeometry() const;
+    QRect leftGeometry() const;
+    int paddingTop() const;
+    int paddingRight() const;
+    int paddingBottom() const;
+    int paddingLeft() const;
+    QMargins padding() const;
+
+    void setShadow(const QImage &image);
+    void setInnerShadowRect(const QRect &rect);
+    void setPadding(const QMargins &margins);
+
+Q_SIGNALS:
+    void shadowChanged(const QImage &);
+    void innerShadowRectChanged();
+    void paddingChanged();
+
+private:
+    class Private;
+    std::unique_ptr<Private> d;
+};
+
+}
+
+Q_DECLARE_METATYPE(KDecoration2::DecorationShadow *)
diff --git a/src/decorationshadow_p.h b/src/decorationshadow_p.h
new file mode 100644 (file)
index 0000000..d4b4458
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "decorationshadow.h"
+
+#include <QImage>
+
+namespace KDecoration2
+{
+class Q_DECL_HIDDEN DecorationShadow::Private
+{
+public:
+    explicit Private(DecorationShadow *parent);
+    ~Private();
+    QImage shadow;
+    QRect innerShadowRect;
+    QMargins padding;
+
+private:
+    DecorationShadow *q;
+};
+
+}
diff --git a/src/decorationthemeprovider.cpp b/src/decorationthemeprovider.cpp
new file mode 100644 (file)
index 0000000..5270020
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+
+#include "decorationthemeprovider.h"
+
+class DecorationThemeMetaDataPrivate : public QSharedData
+{
+public:
+    QString visibleName;
+    QString themeName;
+    QString configurationName;
+    QString pluginId;
+    KDecoration2::BorderSize borderSize = KDecoration2::BorderSize::Normal;
+};
+
+using namespace KDecoration2;
+
+DecorationThemeMetaData::DecorationThemeMetaData()
+    : d(new DecorationThemeMetaDataPrivate())
+{
+}
+
+DecorationThemeMetaData::~DecorationThemeMetaData() = default;
+
+QString DecorationThemeMetaData::visibleName() const
+{
+    return d->visibleName;
+}
+
+void DecorationThemeMetaData::setVisibleName(const QString &name)
+{
+    d->visibleName = name;
+}
+
+QString DecorationThemeMetaData::themeName() const
+{
+    return d->themeName;
+}
+
+void DecorationThemeMetaData::setThemeName(const QString &name)
+{
+    d->themeName = name;
+}
+
+QString DecorationThemeMetaData::configurationName() const
+{
+    return d->configurationName;
+}
+
+void DecorationThemeMetaData::setConfigurationName(const QString &name)
+{
+    d->configurationName = name;
+}
+
+void DecorationThemeMetaData::setBorderSize(KDecoration2::BorderSize size)
+{
+    d->borderSize = size;
+}
+
+KDecoration2::BorderSize DecorationThemeMetaData::borderSize() const
+{
+    return d->borderSize;
+}
+
+QString DecorationThemeMetaData::pluginId() const
+{
+    return d->pluginId;
+}
+
+void DecorationThemeMetaData::setPluginId(const QString &id)
+{
+    d->pluginId = id;
+}
+
+DecorationThemeProvider::DecorationThemeProvider(QObject *parent)
+    : QObject(parent)
+{
+}
+
+DecorationThemeMetaData::DecorationThemeMetaData(const DecorationThemeMetaData &other) = default;
+
+DecorationThemeMetaData &DecorationThemeMetaData::operator=(const DecorationThemeMetaData &other) = default;
+
+#include "moc_decorationthemeprovider.cpp"
diff --git a/src/decorationthemeprovider.h b/src/decorationthemeprovider.h
new file mode 100644 (file)
index 0000000..1f2c90d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+
+#pragma once
+
+#include "decorationdefines.h"
+#include <QObject>
+#include <QSharedDataPointer>
+#include <kdecoration2/kdecoration2_export.h>
+
+class KPluginMetaData;
+class DecorationThemeMetaDataPrivate;
+
+namespace KDecoration2
+{
+/**
+ * Class providing type-safe access to data of themes
+ *
+ * @since 5.23
+ * @author Alexander Lohnau
+ */
+class KDECORATIONS2_EXPORT DecorationThemeMetaData
+{
+public:
+    explicit DecorationThemeMetaData();
+    virtual ~DecorationThemeMetaData();
+    DecorationThemeMetaData(const DecorationThemeMetaData &other);
+    DecorationThemeMetaData &operator=(const DecorationThemeMetaData &other);
+
+    /// User-visible name of the theme
+    QString visibleName() const;
+    void setVisibleName(const QString &name);
+
+    /// Internal name of the theme
+    QString themeName() const;
+    void setThemeName(const QString &name);
+
+    /// Name of the kcm to configure the decoration theme
+    QString configurationName() const;
+    void setConfigurationName(const QString &name);
+
+    /// Border size of the decoration, this gets set based on the "recommendedBorderSize" key in the json metadata
+    /// @internal
+    KDecoration2::BorderSize borderSize() const;
+    void setBorderSize(KDecoration2::BorderSize size);
+
+    /// plugin id of theme provider
+    /// @see KPluginMetaData::pluginId
+    QString pluginId() const;
+    void setPluginId(const QString &id);
+
+private:
+    QSharedDataPointer<DecorationThemeMetaDataPrivate> d;
+};
+/**
+ * Class to give the KWin decorationmodel access to the plugin's themes.
+ *
+ * @since 5.23
+ * @author Alexander Lohnau
+ */
+class KDECORATIONS2_EXPORT DecorationThemeProvider : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit DecorationThemeProvider(QObject *parent);
+
+    /**
+     * List containing information of supported themes
+     */
+    virtual QList<DecorationThemeMetaData> themes() const = 0;
+};
+}
diff --git a/src/private/CMakeLists.txt b/src/private/CMakeLists.txt
new file mode 100644 (file)
index 0000000..47a91ef
--- /dev/null
@@ -0,0 +1,58 @@
+set(libkdecoration2Private_SRCS
+    decoratedclientprivate.cpp
+    decoratedclientprivate.h
+    decorationbridge.cpp
+    decorationbridge.h
+    decorationsettingsprivate.cpp
+    decorationsettingsprivate.h
+)
+
+add_library(kdecorations2private SHARED ${libkdecoration2Private_SRCS})
+
+generate_export_header(
+    kdecorations2private
+BASE_NAME
+    KDECORATIONS_PRIVATE
+EXPORT_FILE_NAME
+    kdecoration2/private/kdecoration2_private_export.h
+)
+
+add_library(KDecoration2::KDecorationPrivate ALIAS kdecorations2private)
+
+target_link_libraries(kdecorations2private
+    PUBLIC
+        Qt::Core
+        Qt::Gui
+)
+
+target_include_directories(kdecorations2private INTERFACE "$<INSTALL_INTERFACE:${KDECORATION2_INCLUDEDIR}>" )
+
+set_target_properties(kdecorations2private PROPERTIES VERSION   ${KDECORATION2_VERSION}
+                                                      SOVERSION 11
+                                                      EXPORT_NAME KDecoration2Private
+)
+
+ecm_generate_headers(KDecoration2Private_CamelCase_HEADERS
+  HEADER_NAMES
+    DecoratedClientPrivate
+    DecorationBridge
+    DecorationSettingsPrivate
+  PREFIX
+    KDecoration2/Private
+  REQUIRED_HEADERS KDecoration2Private_HEADERS
+)
+install(FILES ${KDecoration2Private_CamelCase_HEADERS}
+        DESTINATION ${KDECORATION2_INCLUDEDIR}/KDecoration2/Private
+        COMPONENT Devel)
+
+install(TARGETS kdecorations2private EXPORT KDecoration2Targets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
+
+install(
+    FILES
+        ${CMAKE_CURRENT_BINARY_DIR}/kdecoration2/private/kdecoration2_private_export.h
+        ${KDecoration2Private_HEADERS}
+    DESTINATION
+        ${KDECORATION2_INCLUDEDIR}/kdecoration2/private
+    COMPONENT
+        Devel
+)
diff --git a/src/private/decoratedclientprivate.cpp b/src/private/decoratedclientprivate.cpp
new file mode 100644 (file)
index 0000000..de895b2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decoratedclientprivate.h"
+
+#include <QColor>
+
+namespace KDecoration2
+{
+class Q_DECL_HIDDEN DecoratedClientPrivate::Private
+{
+public:
+    explicit Private(DecoratedClient *client, Decoration *decoration);
+    DecoratedClient *client;
+    Decoration *decoration;
+};
+
+DecoratedClientPrivate::Private::Private(DecoratedClient *client, Decoration *decoration)
+    : client(client)
+    , decoration(decoration)
+{
+}
+
+DecoratedClientPrivate::DecoratedClientPrivate(DecoratedClient *client, Decoration *decoration)
+    : d(new Private(client, decoration))
+{
+}
+
+DecoratedClientPrivate::~DecoratedClientPrivate() = default;
+
+Decoration *DecoratedClientPrivate::decoration()
+{
+    return d->decoration;
+}
+
+Decoration *DecoratedClientPrivate::decoration() const
+{
+    return d->decoration;
+}
+
+DecoratedClient *DecoratedClientPrivate::client()
+{
+    return d->client;
+}
+
+QColor DecoratedClientPrivate::color(ColorGroup group, ColorRole role) const
+{
+    Q_UNUSED(role)
+    Q_UNUSED(group)
+
+    return QColor();
+}
+
+ApplicationMenuEnabledDecoratedClientPrivate::ApplicationMenuEnabledDecoratedClientPrivate(DecoratedClient *client, Decoration *decoration)
+    : DecoratedClientPrivate(client, decoration)
+{
+}
+
+ApplicationMenuEnabledDecoratedClientPrivate::~ApplicationMenuEnabledDecoratedClientPrivate() = default;
+
+}
diff --git a/src/private/decoratedclientprivate.h b/src/private/decoratedclientprivate.h
new file mode 100644 (file)
index 0000000..7a66dd4
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../decorationdefines.h"
+#include <kdecoration2/private/kdecoration2_private_export.h>
+
+#include <QIcon>
+#include <QString>
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+namespace KDecoration2
+{
+class Decoration;
+class DecoratedClient;
+
+class KDECORATIONS_PRIVATE_EXPORT DecoratedClientPrivate
+{
+public:
+    virtual ~DecoratedClientPrivate();
+    virtual bool isActive() const = 0;
+    virtual QString caption() const = 0;
+    virtual bool isOnAllDesktops() const = 0;
+    virtual bool isShaded() const = 0;
+    virtual QIcon icon() const = 0;
+    virtual bool isMaximized() const = 0;
+    virtual bool isMaximizedHorizontally() const = 0;
+    virtual bool isMaximizedVertically() const = 0;
+    virtual bool isKeepAbove() const = 0;
+    virtual bool isKeepBelow() const = 0;
+
+    virtual bool isCloseable() const = 0;
+    virtual bool isMaximizeable() const = 0;
+    virtual bool isMinimizeable() const = 0;
+    virtual bool providesContextHelp() const = 0;
+    virtual bool isModal() const = 0;
+    virtual bool isShadeable() const = 0;
+    virtual bool isMoveable() const = 0;
+    virtual bool isResizeable() const = 0;
+
+    virtual WId windowId() const = 0;
+    virtual WId decorationId() const = 0;
+
+    virtual int width() const = 0;
+    virtual int height() const = 0;
+    virtual QSize size() const = 0;
+    virtual QPalette palette() const = 0;
+    virtual Qt::Edges adjacentScreenEdges() const = 0;
+
+    virtual void requestShowToolTip(const QString &text) = 0;
+    virtual void requestHideToolTip() = 0;
+    virtual void requestClose() = 0;
+    virtual void requestToggleMaximization(Qt::MouseButtons buttons) = 0;
+    virtual void requestMinimize() = 0;
+    virtual void requestContextHelp() = 0;
+    virtual void requestToggleOnAllDesktops() = 0;
+    virtual void requestToggleShade() = 0;
+    virtual void requestToggleKeepAbove() = 0;
+    virtual void requestToggleKeepBelow() = 0;
+    virtual void requestShowWindowMenu(const QRect &rect) = 0;
+
+    Decoration *decoration();
+    Decoration *decoration() const;
+
+    virtual QColor color(ColorGroup group, ColorRole role) const;
+    virtual QString windowClass() const = 0;
+
+protected:
+    explicit DecoratedClientPrivate(DecoratedClient *client, Decoration *decoration);
+    DecoratedClient *client();
+
+private:
+    class Private;
+    const std::unique_ptr<Private> d;
+};
+
+class KDECORATIONS_PRIVATE_EXPORT ApplicationMenuEnabledDecoratedClientPrivate : public DecoratedClientPrivate
+{
+public:
+    ~ApplicationMenuEnabledDecoratedClientPrivate() override;
+
+    virtual bool hasApplicationMenu() const = 0;
+    virtual bool isApplicationMenuActive() const = 0;
+
+    virtual void showApplicationMenu(int actionId) = 0;
+    virtual void requestShowApplicationMenu(const QRect &rect, int actionId) = 0;
+
+protected:
+    explicit ApplicationMenuEnabledDecoratedClientPrivate(DecoratedClient *client, Decoration *decoration);
+};
+
+} // namespace
diff --git a/src/private/decorationbridge.cpp b/src/private/decorationbridge.cpp
new file mode 100644 (file)
index 0000000..d95bb9d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decorationbridge.h"
+
+Q_DECLARE_METATYPE(Qt::MouseButton)
+
+namespace KDecoration2
+{
+DecorationBridge::DecorationBridge(QObject *parent)
+    : QObject(parent)
+{
+    qRegisterMetaType<Qt::MouseButton>();
+}
+
+DecorationBridge::~DecorationBridge() = default;
+
+}
+
+#include "moc_decorationbridge.cpp"
diff --git a/src/private/decorationbridge.h b/src/private/decorationbridge.h
new file mode 100644 (file)
index 0000000..1d0e919
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include <QObject>
+
+#include <memory>
+
+#include <kdecoration2/private/kdecoration2_private_export.h>
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+class QRect;
+
+namespace KDecoration2
+{
+class Decoration;
+class DecorationSettings;
+class DecorationSettingsPrivate;
+class DecoratedClient;
+class DecoratedClientPrivate;
+
+class KDECORATIONS_PRIVATE_EXPORT DecorationBridge : public QObject
+{
+    Q_OBJECT
+public:
+    ~DecorationBridge() override;
+
+    virtual std::unique_ptr<DecoratedClientPrivate> createClient(DecoratedClient *client, Decoration *decoration) = 0;
+    virtual std::unique_ptr<DecorationSettingsPrivate> settings(DecorationSettings *parent) = 0;
+
+protected:
+    explicit DecorationBridge(QObject *parent = nullptr);
+};
+
+} // namespace
+
+Q_DECLARE_METATYPE(KDecoration2::DecorationBridge *)
diff --git a/src/private/decorationsettingsprivate.cpp b/src/private/decorationsettingsprivate.cpp
new file mode 100644 (file)
index 0000000..abcda80
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#include "decorationsettingsprivate.h"
+#include <QFontDatabase>
+
+namespace KDecoration2
+{
+class Q_DECL_HIDDEN DecorationSettingsPrivate::Private
+{
+public:
+    explicit Private(DecorationSettings *settings);
+    DecorationSettings *settings;
+    int gridUnit = -1;
+    int smallSpacing = -1;
+    int largeSpacing = -1;
+};
+
+DecorationSettingsPrivate::Private::Private(DecorationSettings *settings)
+    : settings(settings)
+{
+}
+
+DecorationSettingsPrivate::DecorationSettingsPrivate(DecorationSettings *parent)
+    : d(new Private(parent))
+{
+}
+
+DecorationSettingsPrivate::~DecorationSettingsPrivate()
+{
+}
+
+DecorationSettings *DecorationSettingsPrivate::decorationSettings()
+{
+    return d->settings;
+}
+
+const DecorationSettings *DecorationSettingsPrivate::decorationSettings() const
+{
+    return d->settings;
+}
+
+QFont DecorationSettingsPrivate::font() const
+{
+    return QFontDatabase::systemFont(QFontDatabase::TitleFont);
+}
+
+QFontMetricsF DecorationSettingsPrivate::fontMetrics() const
+{
+    return QFontMetricsF(font());
+}
+
+int DecorationSettingsPrivate::gridUnit() const
+{
+    return d->gridUnit;
+}
+
+int DecorationSettingsPrivate::smallSpacing() const
+{
+    return d->smallSpacing;
+}
+
+int DecorationSettingsPrivate::largeSpacing() const
+{
+    return d->largeSpacing;
+}
+
+void DecorationSettingsPrivate::setGridUnit(int unit)
+{
+    d->gridUnit = unit;
+}
+
+void DecorationSettingsPrivate::setLargeSpacing(int spacing)
+{
+    d->largeSpacing = spacing;
+}
+
+void DecorationSettingsPrivate::setSmallSpacing(int spacing)
+{
+    d->smallSpacing = spacing;
+}
+
+}
diff --git a/src/private/decorationsettingsprivate.h b/src/private/decorationsettingsprivate.h
new file mode 100644 (file)
index 0000000..d0ef6e1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+ */
+#pragma once
+
+#include "../decorationdefines.h"
+#include <QFont>
+#include <QFontMetricsF>
+#include <QList>
+#include <kdecoration2/private/kdecoration2_private_export.h>
+#include <memory>
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the KDecoration2 API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+namespace KDecoration2
+{
+class DecorationSettings;
+
+class KDECORATIONS_PRIVATE_EXPORT DecorationSettingsPrivate
+{
+public:
+    virtual ~DecorationSettingsPrivate();
+    virtual bool isOnAllDesktopsAvailable() const = 0;
+    virtual bool isAlphaChannelSupported() const = 0;
+    virtual bool isCloseOnDoubleClickOnMenu() const = 0;
+    virtual QList<DecorationButtonType> decorationButtonsLeft() const = 0;
+    virtual QList<DecorationButtonType> decorationButtonsRight() const = 0;
+    virtual BorderSize borderSize() const = 0;
+    virtual QFont font() const;
+    virtual QFontMetricsF fontMetrics() const;
+
+    DecorationSettings *decorationSettings();
+    const DecorationSettings *decorationSettings() const;
+
+    int gridUnit() const;
+    int smallSpacing() const;
+    int largeSpacing() const;
+    void setGridUnit(int unit);
+    void setLargeSpacing(int spacing);
+    void setSmallSpacing(int spacing);
+
+protected:
+    explicit DecorationSettingsPrivate(DecorationSettings *parent);
+
+private:
+    class Private;
+    const std::unique_ptr<Private> d;
+};
+}