ukui-panel/0000775000175000017500000000000015167645111011561 5ustar fengfengukui-panel/LICENSE0000664000175000017500000010451515167645100012572 0ustar fengfeng GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ukui-panel/README.md0000664000175000017500000000237315167645100013043 0ustar fengfeng# ukui-panel ## 简介 ukui-panel是ukui桌面环境中的"任务栏"组件,它是一个在屏幕边缘的dock窗口, 提供了的功能包括应用程序启动器,系统托盘,任务管理,系统时间等。 ukui-panel基于ukui-quick-framework提供的插件机制开发。 ## 项目结构 ### **panel** #### 任务栏(经典模式) * org.ukui.panel * 屏幕边缘的dock窗口 * 可置于屏幕4个边缘 * 可拖动改变位置 #### 任务栏(三岛模式) * org.ukui.panelNext * 屏幕下边缘的dock窗口 * 不可改变位置 * 分为数据岛,应用岛,配置岛三部分 * 不会占用屏幕可用区域 * 智能隐藏 #### 顶栏 * org.ukui.panelTopBar * 屏幕上边缘的dock窗口 * 不可改变位置 * 可以将三岛任务栏上的数据岛或配置岛放到顶栏,当没有放置任何岛时,顶栏隐藏 * 会占用屏幕可用区域 ### **widgets** * org.ukui.panel.starter(开始菜单按钮插件) * org.ukui.panel.calendar(日历插件) * org.ukui.panel.search(搜索按钮插件) * org.ukui.panel.separator(分割线插件) * org.ukui.panel.showDesktop(显示桌面按钮插件) * org.ukui.panel.taskView(多任务视图插件) * org.ukui.taskManager(任务管理器插件) ukui-panel/man/0000775000175000017500000000000015167645100012332 5ustar fengfengukui-panel/man/ukui-panel.10000664000175000017500000000274715167645100014500 0ustar fengfeng.TH ukui-panel 1 "15 October 2025" "UKUI Desktop Environment Panel Module" .SH "NAME" ukui-panel - panel application for UKUI desktop environment .SH "SYNOPSIS" .B ukui-panel .SH "DESCRIPTION" ukui-panel is the main panel application for the UKUI desktop environment, providing quick access to applications, system status indicators, and other essential desktop features. .SH "OPTIONS" .TP \fB -h, --help\fR Displays help on commandline options. .TP \fB --help-all\fR Displays help including Qt specific options. .TP \fB -v, --version\fR Displays version information. .TP \fB --panelLocation\fR Show current panel location. .TP \fB --panelSizePolicy\fR Show current panel size policy. .TP \fB --panelAutoHide\fR Show current panel auto hide status. .TP \fB --panelLock\fR Show current panel lock status. .TP \fB --disabledWidgets\fR Show current panel disabled widgets. .TP \fB --trayIconsInhibited\fR Show current inhibited tray icons. .TP \fB --taskBarIconsShowedOn\fR Show where taskbar icons are displayed. .TP \fB --showPanelOnAllScreens\fR Whether the panel is shown on all screens. .TP \fB --showSystemTrayOnAllPanels\fR Whether the system tray is shown on all panels. .TP \fB --panelType\fR Show current panel type. .SH "LOG FILE" Current log file path: "~/.log/ukui-panel/" .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: https://gitee.com/openkylin/ukui-panel/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: UKUI Development Team ukui-panel/CMakeLists.txt0000664000175000017500000000044715167645100014324 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel VERSION 4.1) if (BUILD_TEST) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () add_subdirectory(panel) add_subdirectory(widgets) ukui-panel/widgets/0000775000175000017500000000000015167645100013225 5ustar fengfengukui-panel/widgets/ukui-task-manager/0000775000175000017500000000000015167645111016554 5ustar fengfengukui-panel/widgets/ukui-task-manager/dbus/0000775000175000017500000000000015167645100017507 5ustar fengfengukui-panel/widgets/ukui-task-manager/dbus/org.ukui.TaskManager.xml0000664000175000017500000000161515167645100024173 0ustar fengfeng ukui-panel/widgets/ukui-task-manager/qmldir0000664000175000017500000000053315167645100017766 0ustar fengfengmodule org.ukui.panel.taskManager plugin ukui-task-manager AppIcon 1.0 AppIcon.qml AppList 1.0 AppList.qml TaskManagerBase 1.0 TaskManagerBase.qml TaskItemData 1.0 TaskItemData.qml ThumbnailWindow 1.0 ThumbnailWindow.qml TaskManagerView 1.0 TaskManagerView.qml ThumbnailContainer 1.0 ThumbnailContainer.qml WidgetContainer 1.0 WidgetContainer.qml ukui-panel/widgets/ukui-task-manager/translations/0000775000175000017500000000000015167645100021273 5ustar fengfengukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_vi.ts0000664000175000017500000000320615167645100026356 0ustar fengfeng TaskManager::TaskManagerItem Add launcher to panel Thêm trình khởi chạy vào bảng điều khiển Remove launcher from panel Xóa trình khởi chạy khỏi bảng điều khiển Close Thoát TaskManager::UkuiTaskManager Close Thoát Restore Mở Maximize Phóng lớn Minimize Tối thiểu hóa Keep above Ghim Unset keep above Bỏ ghim ThumbnailContainer Close Thoát ThumbnailWindow Close Thoát ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_fr.ts0000664000175000017500000000316415167645100026352 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel Add launcher to panel Close TaskManager::UkuiTaskManager Close Restore Maximize Minimize Keep above Unset keep above ThumbnailContainer Close ThumbnailWindow Close ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_mn.ts0000664000175000017500000000403615167645100026354 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel ᠡᠬᠦᠷᠭᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠡᠴᠡ ᠳᠤᠭᠳᠠᠪᠤᠷᠢᠵᠢᠭᠤᠯᠤᠭᠰᠠᠨ ᠢ᠋ ᠦᠬᠡᠢᠰᠬᠡᠬᠦ Add launcher to panel ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪ ᠪᠠᠭᠠᠷ ᠲᠤ᠌ ᠳᠤᠭᠳᠠᠪᠤᠷᠢᠵᠢᠭᠤᠯᠬᠤ Close ᠬᠠᠭᠠᠬᠤ TaskManager::UkuiTaskManager Close ᠬᠠᠭᠠᠬᠤ Restore ᠰᠡᠷᠭᠦᠭᠡᠬᠦ Maximize ᠬᠠᠮᠤᠭ ᠤ᠋ᠨ ᠶᠡᠬᠡᠴᠢᠯᠡᠯ Minimize ᠬᠠᠮᠤᠭ ᠤ᠋ᠨ ᠪᠠᠭᠠᠴᠢᠯᠠᠯ Keep above ᠤᠷᠤᠢ ᠳ᠋ᠤ᠌ ᠳᠠᠯᠪᠢᠬᠤ Unset keep above ᠤᠷᠤᠢ ᠳ᠋ᠤ᠌ ᠳᠠᠯᠪᠢᠬᠤ ᠵᠢ ᠦᠬᠡᠢᠰᠬᠡᠬᠦ ThumbnailContainer Close ᠬᠠᠭᠠᠬᠤ ThumbnailWindow Close ᠬᠠᠭᠠᠬᠤ ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_es.ts0000664000175000017500000000316415167645100026352 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel Add launcher to panel Close TaskManager::UkuiTaskManager Close Restore Maximize Minimize Keep above Unset keep above ThumbnailContainer Close ThumbnailWindow Close ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_ky.ts0000664000175000017500000000336615167645100026372 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel قوزعوتقۇچتۇ باشقارمادان. چىعارۇۇ Add launcher to panel تاقتادا قوزعوتقۇچ قوشۇۇ Close جابۇۇ TaskManager::UkuiTaskManager Close جابۇۇ Restore العاچىنا كەتىرىش Maximize چوڭدۇعۇ Minimize تۅمۅنگۅ جۉكتۅۅ Keep above جوعورۇدا. ساقتوو Unset keep above Unset نى جوعۇرۇدا ساقتوو ThumbnailContainer Close جابۇۇ ThumbnailWindow Close جابۇۇ ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_de.ts0000664000175000017500000000316415167645100026333 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel Add launcher to panel Close TaskManager::UkuiTaskManager Close Restore Maximize Minimize Keep above Unset keep above ThumbnailContainer Close ThumbnailWindow Close ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_zh_HK.ts0000664000175000017500000000312515167645100026743 0ustar fengfeng TaskManager::TaskManagerItem Add launcher to panel 將啟動器添加到面板 Remove launcher from panel 從面板中刪除啟動器 Close 關閉 TaskManager::UkuiTaskManager Close 關閉 Restore 恢復 Maximize 最大化 Minimize 最小化 Keep above 保持高於 Unset keep above 取消設置 ThumbnailContainer Close 關閉 ThumbnailWindow Close 關閉 ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_bo_CN.ts0000664000175000017500000000366515167645100026731 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel ལས་ཀའི་སྡེ་ནས་གཏན་འཇོག་འདོར་བ། Add launcher to panel ལས་ཀའི་སྡེ་རུ་གཏན་བཞག་བྱེད་པ། Close ཁ་རྒྱག TaskManager::UkuiTaskManager Close ཁ་རྒྱག Restore སླར་གསོ་བྱེད་པ། Maximize ཆེ་ཤོས་སུ་སྒྱུར་བ། Minimize ཉུང་དུ་གཏོང་གང་ཐུབ་བྱ་དགོས། Keep above རྩེར་འཇོག Unset keep above གཙང་སེལ། ThumbnailContainer Close ཁ་རྒྱག ThumbnailWindow Close ཁ་རྒྱག ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_kk.ts0000664000175000017500000000337715167645100026356 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel قوزعالتۋ اسبابىن تاقتايدا شىعارىپ وتۋ Add launcher to panel تاقتاعا قوزعالتۋ اسبابى قوسۋ Close تاقاۋ TaskManager::UkuiTaskManager Close تاقاۋ Restore قالپىنا كەلتىرىلگەن Maximize ۇلكەيتۋ Minimize كىشرەيتۋ Keep above يۇقارقىنى ساقتاۋ Unset keep above Unset نى جوعارىدا ساقتاۋ ThumbnailContainer Close تاقاۋ ThumbnailWindow Close تاقاۋ ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_ug.ts0000664000175000017500000000333615167645100026357 0ustar fengfeng TaskManager::TaskManagerItem Remove launcher from panel قوزغاتقۇچنى تاختىدىن چىقىرىۋېتىش Add launcher to panel تاختىغا قوزغاتقۇچ قوشۇش Close ياپ TaskManager::UkuiTaskManager Close ياپ Restore ئەسلىگە كەلتۈرۈش Maximize چوڭايتىش Minimize كىچىكلىتىش Keep above يۇقارقىنى ساقلاش Unset keep above Unset نى يۇقىرىدا ساقلاش ThumbnailContainer Close ياپ ThumbnailWindow Close ياپ ukui-panel/widgets/ukui-task-manager/translations/libukui-task-manager_zh_CN.ts0000664000175000017500000000310115167645100026733 0ustar fengfeng TaskManager::TaskManagerItem Add launcher to panel 固定到任务栏 Remove launcher from panel 从任务栏取消固定 Close 关闭 TaskManager::UkuiTaskManager Close 关闭 Restore 还原 Maximize 最大化 Minimize 最小化 Keep above 置顶 Unset keep above 取消置顶 ThumbnailContainer Close 关闭 ThumbnailWindow Close 关闭 ukui-panel/widgets/ukui-task-manager/widget-delegate.cpp0000664000175000017500000001123415167645100022312 0ustar fengfeng/* * * * Copyright (C) 2024, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "widget-delegate.h" #include #include #include #include #include #include #include #include #include #include #include using namespace TaskManager; static std::once_flag flag; static WidgetInfo *widgetInfo = nullptr; int WidgetUpdateEvent::m_eventType = QEvent::registerEventType(); int WidgetUpdateEvent::eventType() { return m_eventType; } WidgetInfo::WidgetInfo(QObject* parent) { m_widgetLoader = new UkuiQuick::WidgetLoader(this); m_widgetLoader->addWidgetSearchPath(QStringLiteral(":/task-manager")); m_widgetLoader->setShowInFilter( UkuiQuick::WidgetMetadata::Host::TaskManager); } WidgetInfo* WidgetInfo::self() { std::call_once(flag, [ & ] { widgetInfo = new WidgetInfo(); }); return widgetInfo; } bool WidgetInfo::hasWidgetFor(const QString& appId) { QMutexLocker locker(&m_mutex); return !m_widgetLoader->widgets(appId).isEmpty(); } QString WidgetInfo::widgetFor(const QString& appId) { if (appId.isEmpty()) { return {}; } if(m_quickWidgets.contains(appId)) { return m_quickWidgets.value(appId); } QtConcurrent::run([this, appId]() { QMutexLocker locker(&m_mutex); QStringList widgets = m_widgetLoader->widgets(appId); if(!widgets.isEmpty()) { QGuiApplication::postEvent(this, new WidgetUpdateEvent(appId, widgets.first())); } }); return {}; } UkuiQuick::Widget* WidgetInfo::loadWidget(const QString& id) { QMutexLocker locker(&m_mutex); return m_widgetLoader->loadWidget(id); } void WidgetInfo::customEvent(QEvent* event) { if(event->type() == WidgetUpdateEvent::eventType()) { auto e = dynamic_cast(event); m_quickWidgets.insert(e->appId(), e->widgetId()); Q_EMIT widgetInfoUpdate(e->appId(), e->widgetId()); } QObject::customEvent(event); } WidgetDelegate::WidgetDelegate(QQuickItem* parent) : QQuickItem(parent) { loadContainer(); connect(this, &QQuickItem::childrenRectChanged, this, [this]() { Q_EMIT preferredWidthChanged(); }); } WidgetDelegate::~WidgetDelegate() { if(m_container) { Q_EMIT m_container->aboutToDeleted(); m_container->deleteLater(); m_container = nullptr; } } QString WidgetDelegate::quickWidgetId() const { return m_quickWidgetId; } void WidgetDelegate::setQuickWidgetId(const QString& id) { if(m_quickWidgetId != id) { m_quickWidgetId = id; Q_EMIT quickWidgetIdChanged(); } loadWidget(); } int WidgetDelegate::preferredWidth() { return m_preferredWidth; } void WidgetDelegate::loadContainer() { auto widget = WidgetInfo::self()->loadWidget(QStringLiteral("org.ukui.taskManagerContainer")); auto container = qobject_cast(widget); if (!container) { qWarning() << "Load taskManagerContainer failed!"; delete widget; return; } m_container = container; auto contItem = qobject_cast(UkuiQuick::WidgetQuickItem::loadWidgetItem(m_container, new QQmlContext(UkuiQuick::SharedEngineComponent::sharedEngine(), this))); if (!contItem) { qWarning() << "Load taskManagerContainerItem failed!"; return; } contItem->setParentItem(this); m_preferredWidth = contItem->childrenRect().width(); connect(contItem, &QQuickItem::childrenRectChanged, this, [&, contItem]() { m_preferredWidth = contItem->childrenRect().width(); Q_EMIT preferredWidthChanged(); }); } void WidgetDelegate::loadWidget() { if(m_widget) { m_container->removeWidget(m_widget); } m_widget = WidgetInfo::self()->loadWidget(m_quickWidgetId); m_container->addWidget(m_widget); } ukui-panel/widgets/ukui-task-manager/org.ukui.taskManagerContainer/0000775000175000017500000000000015167645100024414 5ustar fengfengukui-panel/widgets/ukui-task-manager/org.ukui.taskManagerContainer/WidgetContainer.qml0000664000175000017500000000430115167645100030213 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQml 2.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 WidgetContainerItem { id: containerItem anchors.fill: parent GridLayout { id: mainLayout z: 10 height: parent.height width: childrenRect.width rows: 1 columns: repeater.count Repeater { id: repeater model: containerItem.widgetItemModel delegate: widgetLoaderComponent } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true property Item widgetItem: model.widgetItem Layout.fillWidth: widgetItem.Layout.fillWidth Layout.fillHeight: widgetItem.Layout.fillHeight Layout.minimumHeight: widgetItem.Layout.minimumHeight; Layout.maximumHeight: mainLayout.height; Layout.minimumWidth : widgetItem.Layout.minimumWidth Layout.maximumWidth : widgetItem.Layout.maximumWidth Layout.preferredHeight: mainLayout.height Layout.preferredWidth: widgetItem.Layout.preferredWidth onWidgetItemChanged: { if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = Qt.binding(function () {return widgetParent}) } } } } } ukui-panel/widgets/ukui-task-manager/org.ukui.taskManagerContainer/metadata.json0000664000175000017500000000055715167645100027076 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.taskManagerContainer", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "TaskManager", "WidgetType": "Container", "Contents": { "Main": "WidgetContainer.qml" } } ukui-panel/widgets/ukui-task-manager/actions.h0000664000175000017500000000533115167645100020365 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_TASK_MANAGER_ACTIONS_H #define UKUI_TASK_MANAGER_ACTIONS_H #include #include #include #include namespace TaskManager { class ActionPrivate; class ActionsPrivate; class Action : public QObject { Q_OBJECT public: enum Type { Invalid, //任务栏图标action NewInstance, //启动新实例 DesktopAction, //desktop文件中的action RemoveQuickLauncher, //移除快速启动按钮 AddQuickLauncher, //增加快速启动按钮 Exit, //关闭所有窗口 //单窗口action Close, //关闭窗口 Minimize, //最小化 Maximize, //最大化 Restore, //恢复 KeepAbove, //置顶 UnsetKeepAbove //取消置顶 }; Q_ENUM(Type) explicit Action(QObject *parent = nullptr); Action(const QString &name, const QString &displayName, const QIcon &icon, Type type, const QVariant ¶m = {}, QObject *parent = nullptr); Action(const Action &other); Action &operator=(const Action &other) = delete; Action &operator=(Action &&other) = delete; bool operator==(const Action &other) const; ~Action(); QString name() const; void setName(const QString &name); QString text() const; void setText(const QString &name); QIcon icon() const; void setIcon(const QIcon &icon); Type type() const; void setType(const Type &type); QVariant param(); void setParam(const QVariant ¶m); bool enabled() const; void setEnabled(bool enabled); QAction* internalAction() const; Q_SIGNALS: void actionTriggered(const QVariant& param); private: void initConnection(); QSharedPointer d; }; typedef QVector Actions; } Q_DECLARE_METATYPE(TaskManager::Actions); #endif //UKUI_TASK_MANAGER_ACTIONS_H ukui-panel/widgets/ukui-task-manager/task-manager-filter-model.cpp0000664000175000017500000002600515167645111024216 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "task-manager-filter-model.h" #include #include #include "ukui-task-manager.h" #include #include namespace TaskManager { TaskManagerFilterModel::TaskManagerFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { setFilterRole(UkuiTaskManager::CurrentWinIdList); //读取taskmanager配置文件中的任务栏图标显示在哪个任务栏taskBarIconsShowedOn项并保存 if (!m_config) { m_config = UkuiQuick::ConfigLoader::getConfig("org.ukui.panel.taskManager"); if(m_config->data().contains("taskBarIconsShowedOn")) { m_iconsShowedonScreen = m_config->getValue("taskBarIconsShowedOn").value(); } else { m_iconsShowedonScreen = TaskBarIconsShowedOn::AllPanels; m_config->setValue(QStringLiteral("taskBarIconsShowedOn"), TaskBarIconsShowedOn::AllPanels); } //当taskBarIconsShowedOn变化时,更新筛选条件,并发送事件,更新数据 connect(m_config, &UkuiQuick::Config::configChanged, this, [&](QString key) { if(key == "taskBarIconsShowedOn") { m_iconsShowedonScreen = m_config->getValue(key).value(); invalidateFilter(); if (m_sourceModel) { m_sourceModel->requestDataChange(); } } }); } //主屏改变时,发送事件,更新数据 connect(qApp, &QGuiApplication::primaryScreenChanged, this, [&]() { if (m_sourceModel) { m_sourceModel->requestDataChange(); } }); setSourceModel(&UkuiTaskManager::self()); } void TaskManagerFilterModel::setSourceModel(QAbstractItemModel *sourceModel) { m_sourceModel = qobject_cast(sourceModel); QSortFilterProxyModel::setSourceModel(sourceModel); connect(sourceModel, &QAbstractItemModel::dataChanged, this, &TaskManagerFilterModel::onDataChanged); connect(m_sourceModel, &UkuiTaskManager::appWhiteListChanged, this, &TaskManagerFilterModel::invalidateFilter); connect(m_sourceModel, &UkuiTaskManager::appBlackListChanged, this, &TaskManagerFilterModel::invalidateFilter); } QVariant TaskManagerFilterModel::data(const QModelIndex &index, int role) const { if(role == UkuiTaskManager::CurrentWinIdList && m_screen) { return currentWinIdList(index); } else if(role == UkuiTaskManager::HasActiveWindow) { if(m_screen && mapToSource(index).data(role).toBool()) { return currentWinIdList(index).contains(UkuiQuick::WindowManager::currentActiveWindow()); } return false; } else if (role == UkuiTaskManager::Actions) { Actions actions = mapToSource(index).data(role).value(); for(auto action : actions) { if(action->type() == Action::Type::Exit) { QStringList wids = currentWinIdList(index); action->setEnabled(!wids.isEmpty()); action->setParam(wids); break; } } return QVariant::fromValue(actions); } else if (role == UkuiTaskManager::CurrentScreenWinIdList) { QStringList wins; auto windowGeometries = mapToSource(index).data(UkuiTaskManager::WindowGeometries).value>(); for (const QString&wid: mapToSource(index).data(UkuiTaskManager::CurrentDesktopWinIdList).toStringList()) { if (windowOnCurrentScreen(windowGeometries.value(wid))) { wins.append(wid); } } return wins; } return sourceModel()->data(mapToSource(index), role); } void TaskManagerFilterModel::setOrder(const QModelIndex &index, int order) { if(order >= rowCount()) { order = rowCount() - 1; } if(order < 0) { order = 0; } // 将setOrder操作放到下一次消息循环,避免wlcom上事件double free崩溃问题 QTimer::singleShot(0, this, [this, index, order] { m_sourceModel->setOrder(mapToSource(index), mapToSource(this->index(order, 0)).row()); }); } void TaskManagerFilterModel::addQuickLauncher(const QString &desktopFile, int order) { auto orderIndex = mapToSource(this->index(order, 0)); if (!orderIndex.isValid() && order > 0 && order <= m_sourceModel->rowCount(QModelIndex())) { // 添加到最后一位 m_sourceModel->setQuickLauncher(desktopFile, m_sourceModel->rowCount(QModelIndex())); } else { m_sourceModel->setQuickLauncher(desktopFile, orderIndex.row()); } } QScreen *TaskManagerFilterModel::screen() const { return m_screen; } void TaskManagerFilterModel::setScreen(QScreen *screen) { m_screen = screen; invalidateFilter(); m_sourceModel->requestDataChange(); } bool TaskManagerFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent); //黑白名单管控 if (!m_sourceModel->appWhiteList().isEmpty()) { auto whiteList = m_sourceModel->appWhiteList(); if (!std::any_of(whiteList.constBegin(), whiteList.constEnd(), [&](const QString& app) { return sourceIndex.data(UkuiTaskManager::Id).toString().endsWith(app); })) { return false; } } if (!m_sourceModel->appBlackList().isEmpty()) { auto blackList = m_sourceModel->appBlackList(); if (std::any_of(blackList.constBegin(), blackList.constEnd(), [&](const QString& app) { return sourceIndex.data(UkuiTaskManager::Id).toString().endsWith(app); })) { return false; } } if (!sourceIndex.data(UkuiTaskManager::HasLauncher).toBool()) { if (sourceIndex.data(UkuiTaskManager::CurrentDesktopWinIdList).toStringList().isEmpty()) { return false; } if (!sourceIndex.data(UkuiTaskManager::HasLauncher).toBool()) { switch (m_iconsShowedonScreen) { case AllPanels: return true; case PrimaryScreenPanelAndPanelWhereWindowIsOpen: if (m_screen == qApp->primaryScreen() || onCurrentScreen(sourceIndex)) { return true; } break; case PanelWhereWindowIsOpen: if (onCurrentScreen(sourceIndex)) { return true; } break; default: return false; } return false; } } return true; } bool TaskManagerFilterModel::openMenu(const bool &showDisabledActions, const TaskManager::Actions &actions, QQuickItem *item) { if (actions.isEmpty()) { return false; } if (m_contextMenu) { m_contextMenu->close(); } auto *menu = new QMenu; menu->setAttribute(Qt::WA_DeleteOnClose); for(const TaskManager::Action* action : actions) { if(action->enabled() || showDisabledActions) { menu->addAction(action->internalAction()); } if (action->type() == TaskManager::Action::NewInstance) { menu->insertSeparator(action->internalAction()); } } connect(menu, &QMenu::aboutToHide, this, [this] { Q_EMIT menuAboutToHide(); }); m_contextMenu = menu; m_contextMenu->winId(); if(m_contextMenu->windowHandle()) { m_contextMenu->windowHandle()->setTransientParent(item->window()); } m_contextMenu->popup(QCursor::pos()); return true; } QStringList TaskManagerFilterModel::currentWinIdList(const QModelIndex &index) const { if (m_iconsShowedonScreen == AllPanels) { return mapToSource(index).data(UkuiTaskManager::CurrentDesktopWinIdList).toStringList(); } QStringList wins; auto windowGeometries = mapToSource(index).data(UkuiTaskManager::WindowGeometries).value>(); for (const QString&wid: mapToSource(index).data(UkuiTaskManager::CurrentDesktopWinIdList).toStringList()) { switch (m_iconsShowedonScreen) { case PrimaryScreenPanelAndPanelWhereWindowIsOpen: if (windowOnCurrentScreen(windowGeometries.value(wid)) || m_screen == qApp->primaryScreen()) { wins.append(wid); } break; case PanelWhereWindowIsOpen: if (windowOnCurrentScreen(windowGeometries.value(wid))) { wins.append(wid); } break; default:; } } return wins; } void TaskManagerFilterModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); if(roles.contains(UkuiTaskManager::CurrentDesktopWinIdList) || roles.contains(UkuiTaskManager::WindowGeometries)) { Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), QVector{UkuiTaskManager::HasActiveWindow, UkuiTaskManager::CurrentScreenWinIdList}); } } bool TaskManagerFilterModel::onCurrentScreen(const QModelIndex& index) const { //item在当前desktop上的窗口中是否包含一个在当前屏幕上的窗口 auto windowGeometries = index.data(UkuiTaskManager::WindowGeometries).value>(); for(const QString &wid : index.data(UkuiTaskManager::CurrentDesktopWinIdList).toStringList()) { if(windowOnCurrentScreen(windowGeometries.value(wid))) { return true; } } return false; } bool TaskManagerFilterModel::windowOnCurrentScreen(const QRect &rect) const { if(!QGuiApplication::screens().contains(m_screen)) { return false; } auto intersectedRect = m_screen->geometry().intersected(rect); if(intersectedRect.isEmpty()) { return false; } for(const auto &screen : qGuiApp->screens()) { QRect r = screen->geometry().intersected(rect); if(r.isEmpty()) { continue; } if(r.width() * r.height() > intersectedRect.width() * intersectedRect.height() && screen != m_screen) { return false; } } return true; } void TaskManagerFilterModel::launch(const QModelIndex &index, QQuickItem *item) { m_sourceModel->launch(mapToSource(index), item); } } ukui-panel/widgets/ukui-task-manager/widget-delegate.h0000664000175000017500000000533315167645100021762 0ustar fengfeng/* * * * Copyright (C) 2024, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef WIDGET_SHELL_H #define WIDGET_SHELL_H #include #include #include namespace UkuiQuick { class WidgetContainer; class Widget; class WidgetLoader; } namespace TaskManager { class WidgetUpdateEvent : public QEvent { public: WidgetUpdateEvent(const QString &appId, const QString &widgetId) : QEvent(static_cast(eventType())), m_appId(appId), m_widgetId(widgetId) {} QString appId() const {return m_appId;}; QString widgetId() const {return m_widgetId;}; static int eventType(); private: QString m_appId; QString m_widgetId; static int m_eventType; }; class WidgetInfo : public QObject { Q_OBJECT public: static WidgetInfo *self(); bool hasWidgetFor(const QString &appId); QString widgetFor(const QString &appId); UkuiQuick::Widget *loadWidget(const QString &id); Q_SIGNALS: void widgetInfoUpdate(const QString &appid, const QString &widgetId); protected: void customEvent(QEvent* event) override; private: explicit WidgetInfo(QObject *parent = nullptr); UkuiQuick::WidgetLoader *m_widgetLoader = nullptr; QMap m_quickWidgets; QMutex m_mutex; }; class WidgetDelegate : public QQuickItem { Q_OBJECT Q_PROPERTY(QString quickWidgetId READ quickWidgetId WRITE setQuickWidgetId NOTIFY quickWidgetIdChanged) Q_PROPERTY(int preferredWidth READ preferredWidth NOTIFY preferredWidthChanged) public: explicit WidgetDelegate(QQuickItem *parent = nullptr); ~WidgetDelegate(); QString quickWidgetId() const; void setQuickWidgetId(const QString &id); int preferredWidth(); private: void loadContainer(); void loadWidget(); Q_SIGNALS: void quickWidgetIdChanged(); void preferredWidthChanged(); private: QString m_quickWidgetId; UkuiQuick::Widget *m_widget = nullptr; UkuiQuick::WidgetContainer *m_container = nullptr; int m_preferredWidth = 0; }; } #endif //WIDGET_SHELL_H ukui-panel/widgets/ukui-task-manager/CMakeLists.txt0000664000175000017500000001131415167645111021314 0ustar fengfengcmake_minimum_required(VERSION 3.16) #project(ukui-task-manager LANGUAGES CXX) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) set(VERSION_MICRO 0) set(UKUI_TASK_MANAGER_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core LinguistTools DBus Widgets Quick Qml Concurrent REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core LinguistTools DBus Widgets Quick Qml Concurrent REQUIRED) if (QT_VERSION_MAJOR EQUAL "5") set(KF_VERSION_MAJOR "5") find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED) find_package(KF5WindowSystem REQUIRED) find_package(KF5Wayland) find_package(Qt5Xdg REQUIRED) elseif (QT_VERSION_MAJOR EQUAL "6") set(KF_VERSION_MAJOR "6") find_package(KF6WindowSystem REQUIRED) find_package(KWayland) find_package(Qt6Xdg REQUIRED) endif() find_package(ukui-quick COMPONENTS core framework platform) find_package(PkgConfig REQUIRED) set(UKUI_TASK_MANAGER_PC_PKGS kysdk-waylandhelper ukui-search) foreach(external_lib IN ITEMS ${UKUI_TASK_MANAGER_PC_PKGS}) pkg_check_modules(${external_lib} REQUIRED IMPORTED_TARGET ${external_lib}) if(${${external_lib}_FOUND}) include_directories(${${external_lib}_INCLUDE_DIRS}) link_directories(${${external_lib}_LIBRARY_DIRS}) list(APPEND UKUI_TASK_MANAGER_EXTERNAL_LIBS PkgConfig::${external_lib}) endif() endforeach() file(GLOB TS_FILES translations/*.ts) set(TRANSLATION_FILE_DIR "/usr/share/ukui-task-manager/translations") add_compile_definitions(TRANSLATION_FILE_DIR="${TRANSLATION_FILE_DIR}" UKUI_TASK_MANAGER_VERSION="${UKUI_TASK_MANAGER_VERSION}") set(ukuiTaskManager_SRC ukui-task-manager.cpp ukui-task-manager.h task-manager-item.cpp task-manager-item.h utils.cpp utils.h actions.cpp actions.h task-manager-plugin.cpp task-manager-plugin.h task-manager-filter-model.cpp task-manager-filter-model.h widget-delegate.h widget-delegate.cpp ) if(COMMAND qt_add_dbus_adaptor) qt_add_dbus_adaptor(ukuiTaskManager_SRC dbus/org.ukui.TaskManager.xml ukui-task-manager.h TaskManager::UkuiTaskManager) else() qt5_add_dbus_adaptor(ukuiTaskManager_SRC dbus/org.ukui.TaskManager.xml ukui-task-manager.h TaskManager::UkuiTaskManager) endif() if(COMMAND qt_create_translation) qt_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) else() qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) endif() set(QRC_FILES container.qrc qml/qml.qrc) add_library(ukui-task-manager SHARED ${ukuiTaskManager_SRC} ${QRC_FILES} ${QM_FILES} ) target_include_directories(ukui-task-manager PUBLIC $ ) target_link_libraries(ukui-task-manager PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Concurrent ${UKUI_TASK_MANAGER_EXTERNAL_LIBS} KF${QT_VERSION_MAJOR}::WindowSystem ukui-quick::core ukui-quick::framework ukui-quick::platform ) if (QT_VERSION_MAJOR EQUAL "5") target_link_libraries(ukui-task-manager PRIVATE Qt::X11Extras Qt5Xdg KF5::WaylandClient) else() target_link_libraries(ukui-task-manager PRIVATE Qt6Xdg Plasma::KWaylandClient) endif() set_target_properties(ukui-task-manager PROPERTIES VERSION ${UKUI_TASK_MANAGER_VERSION} SOVERSION ${VERSION_MAJOR} OUTPUT_NAME ukui-task-manager ) install(FILES ${QM_FILES} DESTINATION "${TRANSLATION_FILE_DIR}") set(PLUGIN_INSTALL_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/panel/taskManager") install(DIRECTORY "plugin/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.taskManager") install(FILES "qmldir" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/AppIcon.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/AppList.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/TaskManagerBase.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/TaskItemData.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/TaskManagerView.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/ThumbnailWindow.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(FILES "qml/ThumbnailContainer.qml" DESTINATION ${PLUGIN_INSTALL_PATH}) install(TARGETS "ukui-task-manager" LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH}) ukui-panel/widgets/ukui-task-manager/qml/0000775000175000017500000000000015167645111017345 5ustar fengfengukui-panel/widgets/ukui-task-manager/qml/TaskItemData.qml0000664000175000017500000000171715167645100022377 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ import QtQml 2.15 import QtQuick 2.15 QtObject { property var windowIdList: [] property var windowIcons: {} property var windowIconsName: {} property var windowTitles: {} property Item currentTaskItem: null } ukui-panel/widgets/ukui-task-manager/qml/AppList.qml0000664000175000017500000002401515167645100021434 0ustar fengfeng/* * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * */ import QtQuick 2.12 import QtQml.Models 2.15 import QtQuick.Layouts 1.12 import org.ukui.quick.widgets 1.0 import org.ukui.quick.items 1.0 as UkuiItems import org.ukui.quick.platform 1.0 as Platform import org.ukui.panel.taskManager 1.0 as UkuiTaskManager Item { id: root property int iconIndexAboutToBeScaled: -1 property alias model: visualModel.model property bool isHorizontal: orientation === ListView.Horizontal property alias spacing: normalView.spacing property int itemSize: 48 property int itemMargin: 4 * ratio property real ratio: 1 signal toNormalFinished() signal toDraggingFinished() signal requestThumbnailView(bool show, TaskItemData data, Item item) function indexAt(x, y) { let idx = normalView.normalViewItemIdx(x, y, normalView.spacing/2, true); if (idx === -1) { idx = normalView.normalViewItemIdx(x, y, normalView.spacing/2, false); } return idx; } function updateIconGeometry() { for (var i = 0; i < visualModel.count; i++) { let item = repeater.itemAt(i); if (item) { Platform.WindowManager.setMinimizedGeometry(model[i], item); } } } DelegateModel { id: visualModel delegate: Item { width: isHorizontal ? visualDelegate.width : root.itemSize height: root.itemSize Timer { id: listDragTimer interval: 100 onTriggered: { if (listDropArea.containsDrag) { root.updateIconGeometry(); if (modelData !== "") { UkuiTaskManager.TaskManager.activateWindow(modelData) } } } } DropArea { id: listDropArea anchors.fill: parent enabled: UkuiTaskManager.TaskManager.enableDragToApp onEntered: (dragEvent) => { if (taskItemListRoot.dragEventSource(dragEvent) !== "DropToAppIcon") { dragEvent.accepted = false; return; } listDragTimer.restart(); } onExited: { listDragTimer.stop(); tooltip.hideTooltip(); } } UkuiItems.Tooltip { id: tooltip anchors.fill: parent mainText: taskItemData.Name posFollowCursor: false active: listDropArea.containsDrag // TODO: 优化 // 先有entered信号,再触发containsDragChanged信号,之后才有tooltip.active变为true // 只有当tooltip.active为true时,调用tooltip.showTooltip()才可以生效 onActiveChanged: { if (active) { tooltip.showTooltip(); } } location: { switch(Widget.container.position) { case UkuiItems.Types.Bottom: return UkuiItems.Dialog.BottomEdge; case UkuiItems.Types.Left: return UkuiItems.Dialog.LeftEdge; case UkuiItems.Types.Top: return UkuiItems.Dialog.TopEdge; case UkuiItems.Types.Right: return UkuiItems.Dialog.RightEdge; } } margin: 8 } UkuiItems.DtThemeBackground { id: visualDelegate width: viewLayout.width height: root.itemSize - itemMargin*2 anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter useStyleTransparency: false backgroundColor: listDropArea.containsDrag ? Platform.GlobalTheme.kComponentAlphaHover : normalLayout.containsPress ? Platform.GlobalTheme.kComponentAlphaClick : normalLayout.containsMouse ? Platform.GlobalTheme.kComponentAlphaHover : Platform.GlobalTheme.kContainGeneralAlphaNormal radius: Platform.GlobalTheme.kRadiusNormal RowLayout { id: viewLayout height: parent.height spacing: 0 onChildrenRectChanged: width = childrenRect.width z: 1 UkuiItems.Icon { id: themeicon Layout.margins: itemMargin Layout.preferredWidth: height Layout.maximumWidth: height Layout.fillHeight: true source: taskItemData.WindowIconsName[modelData] === "" ? taskItemData.WindowIcons[modelData] : taskItemData.WindowIconsName[modelData] addUnifiedIconBox: true scale: (iconIndexAboutToBeScaled === index) ? 0.8 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } } UkuiItems.DtThemeText { id: text Layout.preferredWidth: text.implicitWidth Layout.maximumWidth: 192 Layout.fillHeight: true Layout.rightMargin: 8 visible: isHorizontal text: (taskItemData.WindowTitles[modelData] === undefined) ? "" : taskItemData.WindowTitles[modelData] textColor: Platform.GlobalTheme.kFontPrimary verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft elide: Text.ElideRight fontSizeMode: Text.VerticalFit } } // 仅用于获取鼠标悬浮事件,requestThumbnailView MouseArea { id: normalLayout Accessible.role: Accessible.Button Accessible.description: "This is task manager button on list mode of ukui-panel" Accessible.name: taskItemData.Id + index anchors.fill: parent acceptedButtons: Qt.NoButton hoverEnabled: true TaskItemData { id: singleItemData windowIdList: [modelData] windowIcons: taskItemData.WindowIcons windowIconsName: taskItemData.WindowIconsName windowTitles: taskItemData.WindowTitles } onContainsMouseChanged: { mouseArea.aboutToShowThumbnailView(containsMouse, singleItemData, this); } } Rectangle { id: demandsAttention anchors.fill: parent color: "#FF9100" radius: 8 visible: taskItemData.DemandsAttentionWinIdList.includes(modelData) NumberAnimation on opacity { running: demandsAttention.visible loops: 4 from: 0.25 to: 0.6 duration: 450 } } } UkuiItems.DtThemeBackground { height: 4 * ratio width: 8 * ratio radius: 2 * ratio anchors.verticalCenter: visualDelegate.bottom anchors.left: visualDelegate.left anchors.leftMargin: 16 * ratio useStyleTransparency: false backgroundColor: (modelData === UkuiTaskManager.TaskManager.currentActiveWinId) ? Platform.GlobalTheme.kBrandNormal : Platform.GlobalTheme.kGrayAlpha9 } } } Grid { id: normalView width: childrenRect.width height: childrenRect.height rows: isHorizontal ? 1 : visualModel.count columns: isHorizontal ? visualModel.count : 1 Repeater { id: repeater model: visualModel } function indexAtPosition(x, y) { for (let i = 0; i < visualModel.count; ++i) { let item = repeater.itemAt(i); let point = item.mapFromItem(root, Qt.point(x, y)); if (item.contains(point)) { return i; } } return -1; } function normalViewItemIdx(x, y, offset, forward) { if (isHorizontal) { return normalView.indexAtPosition(forward ? x - offset : x + offset, y); } else { return normalView.indexAtPosition(x, forward ? y - offset : y + offset); } } } } ukui-panel/widgets/ukui-task-manager/qml/icons/0000775000175000017500000000000015167645100020456 5ustar fengfengukui-panel/widgets/ukui-task-manager/qml/icons/to.svg0000664000175000017500000000455315167645100021630 0ustar fengfengukui-panel/widgets/ukui-task-manager/qml/icons/back.svg0000664000175000017500000000461615167645100022106 0ustar fengfengukui-panel/widgets/ukui-task-manager/qml/ThumbnailContainer.qml0000664000175000017500000002214615167645100023651 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 import org.ukui.quick.items 1.0 import org.ukui.windowThumbnail 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.taskManager 1.0 as UkuiTaskManager DtThemeBackground { id: container property int spacing: 8 property var containerIcon property bool isList: false property bool containsMouse: false property bool containsPress: false property bool viewIsHorizontal: false property string containerTitle: "" signal closeButtonClicked() backgroundColor: GlobalTheme.baseActive //预览图非列表模式跟随主题透明度 alpha: 0 useStyleTransparency: !isList radius: GlobalTheme.kRadiusWindow borderColor: GlobalTheme.kLineNormal border.width: !isList ? 1 : 0 Loader { id: layoutLoader DtThemeBackground { anchors.fill: parent backgroundColor: containsPress ? GlobalTheme.kGrayAlpha3 : containsMouse ? GlobalTheme.kGrayAlpha1 : GlobalTheme.kGrayAlpha0 useStyleTransparency: false radius: isList ? 4 : GlobalTheme.kRadiusWindow } sourceComponent: isList ? listLayout : thumbnailLayout } Component { id: thumbnailLayout ColumnLayout { id: baseLayout spacing: 0 height: { if (viewIsHorizontal) { return viewLoader.preChildrenSize; } else { var preHeight = windowThumbnail.height + container.spacing * 3 + 24; return Math.max(preHeight, minimumHeight); } } width: { if (viewIsHorizontal) { var preWidth = windowThumbnail.width + container.spacing * 2; return Math.max(preWidth, minimumWidth); } else { return viewLoader.preChildrenSize; } } RowLayout { Layout.fillWidth: true Layout.preferredHeight: 24 Layout.maximumHeight: 24 Layout.margins: container.spacing Layout.bottomMargin: 0 spacing: 0 Icon { Layout.preferredHeight: 24 Layout.preferredWidth: 24 // 最小宽度下,保证图标和关闭按钮完全显示(24*2),左右margin也要对称显示 Layout.rightMargin: Math.min(baseLayout.width - 24*2 - container.spacing*2, container.spacing) source: containerIcon } DtThemeText { Layout.fillHeight: true Layout.fillWidth: true text: containerTitle textColor: GlobalTheme.kFontPrimary elide: Text.ElideRight verticalAlignment: Text.AlignVCenter Tooltip { anchors.fill: parent mainText: parent.text posFollowCursor: true visible: parent.truncated } } MouseArea { id: closeButtonArea Layout.preferredHeight: 24 Layout.preferredWidth: 24 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight hoverEnabled: true visible: container.containsMouse DtThemeBackground { backgroundColor: closeButtonArea.containsPress ? GlobalTheme.kErrorClick : GlobalTheme.kErrorNormal radius: GlobalTheme.kRadiusNormal anchors.fill: parent visible: parent.containsMouse Tooltip { anchors.fill: parent mainText: qsTr("Close") posFollowCursor: true } } Icon { anchors.centerIn: parent width: 16 height: width mode: parent.containsMouse ? Icon.Highlight : Icon.AutoHighlight source: "window-close-symbolic" } onClicked: { closeButtonClicked(); } } } WindowThumbnail { id: windowThumbnail Layout.alignment: Qt.AlignHCenter Layout.margins: container.spacing Layout.preferredWidth: viewIsHorizontal ? itemWidth : viewLoader.preChildrenSize - container.spacing * 2 Layout.preferredHeight: viewIsHorizontal ? viewLoader.preChildrenSize - 48 : itemHeight Layout.maximumHeight: maximumHeight - container.spacing * 3 - 24 Layout.maximumWidth: maximumWidth - container.spacing * 2 property real itemHeight property real itemWidth // 窗口visible改变 winId: windowVisible ? modelData : "" function updateSize() { if (winId === "") { return; } var itemGeometry = WindowManager.geometry(winId); if (viewIsHorizontal) { itemWidth = itemGeometry.width * ((viewLoader.preChildrenSize - 48 ) / itemGeometry.height); } else { itemHeight = itemGeometry.height * ((viewLoader.preChildrenSize - container.spacing * 2) / itemGeometry.width); } } onWinIdChanged: updateSize() onWidthChanged: updateSize() onHeightChanged: updateSize() } } } Component { id: listLayout Item { width: viewLoader.item.isIntervactive ? 220 : 232 height: 36 RowLayout { anchors.fill: parent anchors.margins: container.spacing Icon { Layout.preferredHeight: 16 Layout.preferredWidth: 16 source: containerIcon } DtThemeText { Layout.fillHeight: true Layout.fillWidth: true text: containerTitle textColor: GlobalTheme.kFontPrimary elide: Text.ElideRight verticalAlignment: Text.AlignVCenter Tooltip { anchors.fill: parent mainText: parent.text posFollowCursor: true visible: parent.truncated } } MouseArea { id: listCloseButtonArea Layout.preferredHeight: 16 Layout.preferredWidth: 16 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight hoverEnabled: true visible: container.containsMouse DtThemeBackground { backgroundColor: listCloseButtonArea.containsPress ? GlobalTheme.kErrorClick : GlobalTheme.kErrorNormal radius: GlobalTheme.kRadiusMin anchors.fill: parent visible: parent.containsMouse Tooltip { anchors.fill: parent mainText: qsTr("Close") posFollowCursor: true } } Icon { anchors.fill: parent mode: parent.containsMouse ? Icon.Highlight : Icon.AutoHighlight source: "window-close-symbolic" } onClicked: { closeButtonClicked(); } } } } } } ukui-panel/widgets/ukui-task-manager/qml/TaskManagerView.qml0000664000175000017500000003740615167645111023122 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * hxf * */ import QtQml 2.15 import QtQuick 2.12 import QtQml.Models 2.12 import QtQuick.Layouts 1.12 import org.ukui.quick.widgets 1.0 import org.ukui.panel.taskManager 1.0 as UkuiTaskManager import org.ukui.quick.items 1.0 as Items import org.ukui.quick.platform 1.0 as Platform // taskManager全部界面显示(包括预览图) TaskManagerBase { id: taskManager // 任务栏是否激活: 预览图是否显示、是否有高亮显示、是否有拖拽事件、是否打开右键菜单 Widget.active: taskManagerActived || thumbnailView.visible || isDragging property var widgetScreenGeo: Widget.container.screen.availableGeometry function menuAboutToHide() { viewContent.menuVisible = false; taskManagerActived = false; isTaskMenuShow = false; } function hidethumbnail() { UkuiTaskManager.TaskManager.activateWindowView([]); thumbnailView.hide(); viewContent.clearThumbnailModel(); } function showthumbnail() { if (!viewContent.currentWinIdList) { return; } if (viewContent.currentWinIdList.length !== 0) { thumbnailView.show(); } } Component.onCompleted: { taskManager.viewModel.menuAboutToHide.connect(menuAboutToHide) } Component.onDestruction: { taskManager.viewModel.menuAboutToHide.disconnect(menuAboutToHide) } state: "" states: [ State { name: "aboutToShowThumbnail" }, State { name: "aboutToHideThumbanil" } ] transitions: [ Transition { to: "aboutToShowThumbnail" SequentialAnimation { PauseAnimation { duration: 400 } ScriptAction { script: { if (!thumbnailView.visible && !isTaskMenuShow) { viewContent.updateThumbnailView(); thumbnailView.updatePosition(); thumbnailView.updateThumbnailOffset(); showthumbnail(); updateBlurRegionTimer.restart(); } } } } }, Transition { to: "aboutToHideThumbanil" SequentialAnimation { PauseAnimation { duration: 400 } ScriptAction { script: { if (thumbnailView.visible && (!taskItemData.mouse.containsMouse || isTaskMenuShow)) { hidethumbnail(); } } } } } ] Timer { id: changedThumbnailData interval: 400 onTriggered: { if (taskItemData.mouse.containsMouse) { viewContent.thumbnailData = taskItemData.dataToBeChanged; } } } onRequestThumbnailView: (show, data, mouse) => { taskItemData.mouse = mouse; if (show) { state = "aboutToShowThumbnail"; if (thumbnailView.visible) { // timer taskItemData.dataToBeChanged = data; changedThumbnailData.restart(); } else { viewContent.thumbnailData = data; } } else { if (taskItemData.mouse) { state = "aboutToHideThumbanil"; } else { hidethumbnail(); } } } QtObject { id: taskItemData // 当前预览图对应的taskItem,通过containsMouse判断是否数据更新 / 解决X下预览图尺寸变化会触发隐藏的bug property Item mouse property var dataToBeChanged } Items.Dialog { id: thumbnailView mainItem: viewContent type: Platform.Settings.platformName === "wayland" ? Platform.WindowType.Switcher : Platform.WindowType.PopupMenu flags: Qt.WindowDoesNotAcceptFocus | Qt.FramelessWindowHint /** * [注]: 以Items.Types.Bottom(任务栏在下)为例,关于horizontalCenterOffset的计算: * 由于Dialog窗口需要加上阴影大小,所以窗口大小比内部预览图要大,默认情况下,预览图是居中显示的(horizontalCenterOffset = 0) * 在满屏时,此时Dialog已经比Screen.width要大,再居中就不对了,所以需要调整horizontalCenterOffset * 在缩放情况下有时不会完美铺满屏幕,所以预览图需要在屏幕上居中显示(horizontalCenterOffset = thumbnailView.width - Screen.width)/2 * -1 * 并且设计稿标注,预览图与窗口间距为8(horizontalCenterOffset = (viewContent.cachedOffset - viewContent.screenMargin) * -1) */ onWidthChanged: updateThumbnailOffset(); onHeightChanged: updateThumbnailOffset(); function updateThumbnailOffset() { var actualHorizontalOffset = 0; var actualVerticalOffset = 0; if (viewContent.isHorizontal) { actualHorizontalOffset = (thumbnailView.width > taskManager.widgetScreenGeo.width) ? Math.max((viewContent.cachedOffset - viewContent.screenMargin) * -1, (thumbnailView.width - taskManager.widgetScreenGeo.width)/2 * -1) : 0; viewContent.anchors.horizontalCenterOffset = actualHorizontalOffset; } else { actualVerticalOffset = (thumbnailView.height > taskManager.widgetScreenGeo.height) ? Math.max((viewContent.cachedOffset - viewContent.screenMargin) * -1, (thumbnailView.height - taskManager.widgetScreenGeo.height)/2 * -1) : 0; viewContent.anchors.verticalCenterOffset = actualVerticalOffset; } } function updatePosition() { switch (Widget.container.position) { case Items.Types.Left: thumbnailView.location = Items.Types.LeftEdge; viewContent.anchors.horizontalCenterOffset = -(viewContent.offset-viewContent.viewMargin) / 2; viewContent.anchors.verticalCenterOffset = 0; break; case Items.Types.Top: thumbnailView.location = Items.Types.TopEdge; viewContent.anchors.horizontalCenterOffset = 0; viewContent.anchors.verticalCenterOffset = -(viewContent.offset-viewContent.viewMargin)/2; break; case Items.Types.Right: thumbnailView.location = Items.Types.RightEdge; viewContent.anchors.horizontalCenterOffset = (viewContent.offset-viewContent.viewMargin) / 2; viewContent.anchors.verticalCenterOffset = 0; break; case Items.Types.Bottom: thumbnailView.location = Items.Types.BottomEdge; viewContent.anchors.horizontalCenterOffset = 0; viewContent.anchors.verticalCenterOffset = (viewContent.offset-viewContent.viewMargin) / 2; break; default: break; } thumbnailView.margin = 0; } Items.WindowBlurBehind { id: blurRegions window: thumbnailView enable: true // 整个窗口的毛玻璃区域(为list模式时) Items.RectRegion { id: windowRegion x: 0 y: 0 width: viewContent.width height: viewContent.height radius: Platform.GlobalTheme.kRadiusWindow } } Item { id: viewBase height: viewContent.isHorizontal ? (viewContent.height + viewContent.offset + viewContent.viewMargin) : (viewContent.height + viewContent.offset*2) width: viewContent.isHorizontal ? (viewContent.width + viewContent.offset*2) : (viewContent.width + viewContent.offset + viewContent.viewMargin) /** * DropArea实现功能: 拖拽文件到多窗口下,预览图有悬浮显示,并600ms后激活对应窗口 * 悬浮三态 ---- (ThumbnailWindow.qml处实现)mouseAreaContainsMouse与(viewDropArea.targetThumbnailIndex === index)绑定 * 激活对应窗口 ---- 通过indexAt取到对应index并开始计时 */ DropArea { id: viewDropArea property int targetThumbnailIndex: -1 enabled: UkuiTaskManager.TaskManager.enableDragToApp anchors.fill: viewContent anchors.centerIn: viewContent onPositionChanged: (drag) => { if (taskManager.dragEventSource(drag) !== "DropToAppIcon") { return; } var targetIndex = viewContent.thumbnailLayout.indexAt(drag.x, drag.y); if (viewDropArea.targetThumbnailIndex !== targetIndex && targetIndex !== -1) { viewDropArea.targetThumbnailIndex = targetIndex; viewDragTimer.restart(); } } onExited: { viewDropArea.targetThumbnailIndex = -1; viewDragTimer.stop(); } Timer { id: viewDragTimer interval: 600 onTriggered: { if (viewDropArea.targetThumbnailIndex > -1 && viewDropArea.targetThumbnailIndex < thumbnailModel.count) { UkuiTaskManager.TaskManager.activateWindow(thumbnailModel.get(viewDropArea.targetThumbnailIndex).winId); taskManager.hidethumbnail(); viewDropArea.targetThumbnailIndex = -1; } } } } ThumbnailWindow { id: viewContent Accessible.role: Accessible.Button Accessible.description: "This is a thumbnail window of ukui-panel" Accessible.name: "ukui-panel thumbnail window" anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter property UkuiTaskManager.TaskItemData thumbnailData: null property var currentWinIdList: thumbnailData ? thumbnailData.windowIdList : [] property var windowTitles: thumbnailData ? thumbnailData.windowTitles : [] property var windowIcons: thumbnailData ? thumbnailData.windowIcons : [] property var windowIconsName: thumbnailData ? thumbnailData.windowIconsName : [] property bool isHorizontal: taskManager.view.orientation === ListView.Horizontal property bool hasFocus: viewContent.containsMouse || viewContent.menuVisible || viewDropArea.containsDrag property bool windowVisible: thumbnailView.visible property var widgetScreenGeo: taskManager.widgetScreenGeo onHasFocusChanged: { if (hasFocus) { taskManager.state = "aboutToShowThumbnail"; } else { taskManager.state = "aboutToHideThumbanil"; } } Timer { id: updateBlurRegionTimer interval: 50 onTriggered: { if (!viewContent.isList) { blurRegions.clearRectRegion(); for (var i = 0; i < thumbnailModel.count; i++) { let item = viewContent.thumbnailLayout.itemAt(i); let point = item.mapToItem(viewBase, 0, 0); item.itemRegion.x = point.x; item.itemRegion.y = point.y; if (item) { blurRegions.addRectRegion(item.itemRegion); } } } else { blurRegions.clearRectRegion(); let point = viewContent.mapToItem(viewBase, 0, 0); windowRegion.x = point.x; windowRegion.y = point.y; blurRegions.addRectRegion(windowRegion); } } } onCurrentWinIdListChanged: updateThumbnailView() // 更新预览图model数据 && 更新毛玻璃区域 function updateThumbnailView() { updateBlurRegionTimer.stop(); updateThumbnailModel(); updateBlurRegionTimer.restart(); viewContent.determineListViewSize(); // 先设置mainItem的宽高 再切换visualParent,解决预览图闪烁问题 if (viewContent.thumbnailData) { if (viewContent.thumbnailData.currentTaskItem !== null) { thumbnailView.visualParent = viewContent.thumbnailData.currentTaskItem; } } else { thumbnailView.visualParent = null; } } property var modelList: [] ListModel { id: thumbnailModel } function clearThumbnailModel() { modelList = []; thumbnailModel.clear(); } function updateThumbnailModel() { // 这里不能直接用=(js中表示引用),需要浅拷贝 if (!currentWinIdList || currentWinIdList.length == 0) { hidethumbnail(); return; } var listFromModel = modelList.slice(0); var listFromCurrent = currentWinIdList.slice(0); var indexOfRemoveList = []; for (var i = 0; i < listFromModel.length; i++) { if (listFromCurrent.includes(listFromModel[i])) { listFromCurrent.splice(listFromCurrent.indexOf(listFromModel[i]), 1); } else { indexOfRemoveList.push(i); } } for (var i = indexOfRemoveList.length - 1; i > -1; i--) { listFromModel.splice(indexOfRemoveList[i], 1); thumbnailModel.remove(indexOfRemoveList[i]); } for (var i = 0; i < listFromCurrent.length; i++) { listFromModel.push(listFromCurrent[i]); thumbnailModel.append({"winId": listFromCurrent[i]}); } modelList = listFromModel; } } } } } ukui-panel/widgets/ukui-task-manager/qml/qml.qrc0000664000175000017500000000056115167645100020645 0ustar fengfeng icons/back.svg icons/to.svg icon/ukui-start-symbolic.svg icon/ukui-start-symbolic-disable.svg icon/ukui-end-symbolic.svg icon/ukui-end-symbolic-disable.svg ukui-panel/widgets/ukui-task-manager/qml/ThumbnailWindow.qml0000664000175000017500000005532415167645111023204 0ustar fengfeng/* * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 import org.ukui.quick.items 1.0 import org.ukui.windowThumbnail 1.0 import org.ukui.quick.platform 1.0 as Platform import org.ukui.panel.taskManager 1.0 as UkuiTaskManager MouseArea { id: baseMouseArea property bool isList property var thumbnailLayout: viewLoader.item.viewRepeater hoverEnabled: true property bool menuVisible: false property int thumbnailImplicitHeight: 192 // 设置初始高度,规避初次显示时出现鼠标悬浮退出事件,影响预览图显示 width: 272 height: 192 // 判断相对于默认宽高来说,是否进行缩放(为true时,预览图在不达到最小宽高时进行等比缩放) property real thumbnailScale: 1.0 // 阴影的宽度(采用GlobalTheme.kShadowMenu) property int cachedOffset: 14 property int offset: { if (isList) { cachedOffset = Math.max(baseShadow.shadowSize, 14); return cachedOffset; } else { if (thumbnailLayout.count > 0) { cachedOffset = Math.max(thumbnailLayout.itemAt(0).shadowSize, 14); return cachedOffset; } return cachedOffset; } } // 预览图窗口布局和*默认*大小相关参数 property int viewMargin: 8 // 预览图显示内容与任务栏的间距 property int screenMargin: 8 // 预览图满屏时,与屏幕边缘的间距 property int viewSpacing: 8 // 预览图模式下窗口间距 property int layoutSpacing: 8 // 内部预览图组件与窗口的左右margin property var maximumSize : Qt.size(344, 344) property var minimumSize : Qt.size(120, 120) property var initSize: Qt.size(192, 192) function determineListViewSize() { if (!currentWinIdList) { return; } if (isHorizontal) { var listPreHeight = listViewBase.determineHeight(currentWinIdList).height; if (listPreHeight < 124) { baseMouseArea.isList = true; return; } else { viewLoader.preChildrenSize = listPreHeight; baseMouseArea.isList = false; } } else { var listPreWidth = listViewBase.determineWidth(currentWinIdList).width; if (listPreWidth < 124) { baseMouseArea.isList = true; return; } else { viewLoader.preChildrenSize = listPreWidth; baseMouseArea.isList = false; } } } DtThemeBackground { id: listViewBase backgroundColor: Platform.GlobalTheme.baseActive //预览图列表模式跟随主题透明度 alpha: 0 useStyleTransparency: isList width: viewLoader.width height: viewLoader.height borderColor: Platform.GlobalTheme.kLineNormal border.width: isList ? 1 : 0 radius: Platform.GlobalTheme.kRadiusWindow DtDropShadow { id: baseShadow anchors.fill: listViewBase shadowData: isList ? Platform.GlobalTheme.kShadowMenu : undefined shadowRadius: listViewBase.radius } // 窗口尺寸不能为0 onWidthChanged: { baseMouseArea.width = Math.max(Math.ceil(listViewBase.width), 1); baseMouseArea.height = Math.max(Math.ceil(listViewBase.height), 1); } onHeightChanged: { baseMouseArea.width = Math.max(Math.ceil(listViewBase.width), 1); baseMouseArea.height = Math.max(Math.ceil(listViewBase.height), 1); } function determineHeight(winIdList) { var totalWidth = 0; var thumbnailHeight = 144; // 这是预览图内部组件默认高度(192-24-layoutSpacing*3) if (!winIdList) { return; } for (var i = 0; i < winIdList.length; i++) { var itemGeometry = Platform.WindowManager.geometry(winIdList[i]); var thumbWidth = itemGeometry.width * (thumbnailHeight / itemGeometry.height); // 预览图在计算宽高时,也要考虑大小限制 totalWidth = totalWidth + Math.min(Math.max(thumbWidth, minimumSize.width - layoutSpacing*2), maximumSize.width - layoutSpacing*2); } var otherAreaSize; // 其余区域的大小,包括间距和预览图的margin otherAreaSize = (layoutSpacing * 2 * winIdList.length) + (viewSpacing * (winIdList.length - 1)); if ((baseMouseArea.widgetScreenGeo.width - (screenMargin * 2) - otherAreaSize) < totalWidth) { thumbnailScale = (baseMouseArea.widgetScreenGeo.width - screenMargin * 2 - otherAreaSize) / totalWidth; thumbnailHeight = thumbnailHeight * thumbnailScale; } else { thumbnailScale = 1.0; } var listPreHeight = thumbnailHeight + 48; var listPreWidth = otherAreaSize + totalWidth; return Qt.rect(0, 0, listPreWidth, listPreHeight); } function determineWidth(winIdList) { var totalHeight = 0; var thumbnailWidth = 176; // 这是预览图内部组件默认宽度(192-layoutSpacing*2) var thumbnailOtherHeight = 48; //这是单个预览图内部,除预览图外的其他高度(48) if (!winIdList) { return; } for (var i = 0; i < winIdList.length; i++) { var itemGeometry = Platform.WindowManager.geometry(winIdList[i]); var thumbHeight = (itemGeometry.height * (thumbnailWidth / itemGeometry.width)); // 预览图在计算宽高试,也要考虑大小限制 totalHeight = totalHeight + Math.min(Math.max(thumbHeight, minimumSize.height - thumbnailOtherHeight), maximumSize.height - thumbnailOtherHeight); } var otherAreaSize; // 其余区域的大小,包括间距和预览图的margin,以及纵向布局时的title高度(24) otherAreaSize = (layoutSpacing * 3 + 24) * winIdList.length + viewSpacing * (winIdList.length - 1); if ((baseMouseArea.widgetScreenGeo.height - screenMargin * 2 - otherAreaSize) < totalHeight) { thumbnailScale = (baseMouseArea.widgetScreenGeo.height - screenMargin * 2 - otherAreaSize) / totalHeight; thumbnailWidth = thumbnailWidth * thumbnailScale; } else { thumbnailScale = 1.0; } var listPreWidth = thumbnailWidth + layoutSpacing*2; var listPreHeight = totalHeight + otherAreaSize; return Qt.rect(0, 0, listPreWidth, listPreHeight); } Loader { id: viewLoader property real preChildrenSize sourceComponent: baseMouseArea.isList ? listMode : thumbnailMode } /** * 预览图显示View: 列表模式、预览图模式 */ Component { id: thumbnailMode Item { width: childrenRect.width height: childrenRect.height property var viewRepeater: repeater Column { id: columnLayout spacing: viewSpacing } Row { id: rowLayout spacing: viewSpacing } Repeater { id: repeater parent: isHorizontal ? rowLayout : columnLayout model: thumbnailModel delegate: thumbnailDelegate function indexAt(x, y) { for (let i = 0; i < thumbnailModel.count; ++i) { let item = repeater.itemAt(i); let point = item.mapFromItem(baseMouseArea, Qt.point(x, y)); if (item.contains(point)) { return i; } } return -1; } } } } } Component { id: listMode RowLayout { property bool isIntervactive: listModelView.contentItem.childrenRect.height > listModelView.height property var viewRepeater: listModelView width: 240 height: listModelView.height + listModelView.Layout.margins * 2 spacing: 0 ListView { id: listModelView Layout.fillWidth: true Layout.preferredHeight: Math.min(contentItem.childrenRect.height, 360) Layout.margins: 4 Layout.rightMargin: 0 clip: true spacing: 0 interactive: parent.isIntervactive orientation: ListView.Vertical boundsBehavior: Flickable.StopAtBounds ScrollBar.vertical: scrollBarControl model: thumbnailModel delegate: thumbnailDelegate } ScrollBar { id: scrollBarControl Layout.fillHeight: true Layout.preferredWidth: 12 Layout.margins: 4 Layout.leftMargin: 0 visible: (size < 1 && size > 0) padding: 4 contentItem: DtThemeBackground { radius: width / 2 useStyleTransparency: false backgroundColor: Platform.GlobalTheme.kGrayAlpha3 } } } } /** * 预览图delegate */ Component { id: thumbnailDelegate MouseArea { id: itemMouseArea width: thumbnailLoader.width height: thumbnailLoader.height hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton property alias itemRegion: blurRegion property alias shadowSize: itemShadow.shadowSize RectRegion { id: blurRegion x: itemMouseArea.x y: itemMouseArea.y width: itemMouseArea.width height: itemMouseArea.height radius: thumbnailLoader.item.radius } DtDropShadow { id: itemShadow anchors.fill: thumbnailLoader shadowData: isList ? undefined : Platform.GlobalTheme.kShadowMenu shadowRadius: thumbnailLoader.item.radius } Timer { id: activeTimer property var activeWinIds: [] onTriggered: { UkuiTaskManager.TaskManager.activateWindowView(activeTimer.activeWinIds) } } function activateWindowView() { var winIds = [model.winId]; if (baseMouseArea.menuVisible || containsMouse) { activeTimer.interval = 500; activeTimer.activeWinIds = winIds; activeTimer.start(); } else { activeTimer.stop(); UkuiTaskManager.TaskManager.activateWindowView([]); } } onContainsMouseChanged: activateWindowView() onClicked: { if (mouse.button === Qt.RightButton) { var actions = UkuiTaskManager.TaskManager.windowActions(model.winId); baseMouseArea.menuVisible = taskManager.viewModel.openMenu(true, actions, viewLoader); } else { // 需要先激活窗口再隐藏预览图 // 如果先隐藏预览图再激活窗口,会因为先取消highlight窗口,导致屏幕闪一下其他窗口的问题 UkuiTaskManager.TaskManager.activateWindow(model.winId); taskManager.hidethumbnail(); } } Loader { id: thumbnailLoader WindowThumbnailMprisModel { id: mprisModel winID: model.winId pid: Platform.WindowManager.pid(model.winId) } property string modelData: model.winId property var title: windowTitles ? windowTitles[model.winId] : "" property var icon: windowIcons ? windowIcons[model.winId] : "" property var iconName: windowIconsName ? windowIconsName[model.winId] : "" property var windowThumbnailMprisModel: mprisModel property bool mouseAreaContainsMouse: itemMouseArea.containsMouse || viewDropArea.targetThumbnailIndex === index property bool mouseAreaContainsPress: itemMouseArea.containsPress // 预览图限制宽高(最大最小宽高限制,要随满屏*等比例缩放* ) property real maximumHeight: isHorizontal ? maximumSize.height : maximumSize.height * baseMouseArea.thumbnailScale property real minimumHeight: isHorizontal ? minimumSize.height : minimumSize.height * baseMouseArea.thumbnailScale property real maximumWidth: isHorizontal ? maximumSize.width * baseMouseArea.thumbnailScale : maximumSize.width property real minimumWidth: isHorizontal ? minimumSize.width * baseMouseArea.thumbnailScale : minimumSize.width // mprisModel.count > 0为mpris音视频预览图 sourceComponent: { if (mprisModel.count > 0) { if (mprisModel.isCurrentMediaAudio) { return musicThumbanilComponent; } else { return videoThumbnailComponent; } } else { return thumbnailComponent; } } } } } /** * 预览图组件显示: 普通预览图(预览图界面、列表界面)、mpris音频预览图、mpris视频预览图 */ Component { id: thumbnailComponent ThumbnailContainer { width: baseMouseArea.isList ? 220 : (isHorizontal ? contentWidth : viewLoader.preChildrenSize) height: baseMouseArea.isList ? 36 : (isHorizontal ? viewLoader.preChildrenSize : contentHeight) property real contentHeight: childrenRect.height property real contentWidth: childrenRect.width isList: baseMouseArea.isList spacing: layoutSpacing containerIcon: (iconName === undefined || iconName === "") ? icon : iconName containerTitle: title === undefined ? "" : title containsMouse: mouseAreaContainsMouse containsPress: mouseAreaContainsPress viewIsHorizontal: isHorizontal onCloseButtonClicked: { UkuiTaskManager.TaskManager.activateWindowView([]); UkuiTaskManager.TaskManager.execSpecifiedAction(UkuiTaskManager.Action.Close, modelData); } } } Component { id: musicThumbanilComponent DtThemeBackground { backgroundColor: Platform.GlobalTheme.baseActive radius: Platform.GlobalTheme.kRadiusWindow useStyleTransparency: true width: childrenRect.width height: childrenRect.height borderColor: Platform.GlobalTheme.kLineNormal border.width: 1 AudioPalyerThumbnail { playerData: windowThumbnailMprisModel containsMouse: mouseAreaContainsMouse windowRadius: parent.radius onCloseButtonClicked: { UkuiTaskManager.TaskManager.activateWindowView([]); UkuiTaskManager.TaskManager.execSpecifiedAction(UkuiTaskManager.Action.Close, modelData); } } } } Component { id: videoThumbnailComponent DtThemeBackground { backgroundColor: Platform.GlobalTheme.baseActive radius: Platform.GlobalTheme.kRadiusWindow useStyleTransparency: true width: childrenRect.width height: childrenRect.height property int thumbnailMargin: 8 borderColor: Platform.GlobalTheme.kLineNormal border.width: 1 Repeater { id: view model: windowThumbnailMprisModel ColumnLayout { id: baseLayout spacing: 0 height: { if (isHorizontal) { return viewLoader.preChildrenSize; } else { var preHeight = windowThumbnail.height + layoutSpacing * 3 + 24; return Math.max(preHeight, minimumHeight); } } width: { if (isHorizontal) { var preWidth = windowThumbnail.width + layoutSpacing * 2; return Math.max(preWidth, minimumWidth); } else { return viewLoader.preChildrenSize; } } RowLayout { Layout.fillWidth: true Layout.preferredHeight: 24 Layout.maximumHeight: 24 Layout.margins: thumbnailMargin Layout.bottomMargin: 0 Icon { Layout.preferredHeight: 24 Layout.preferredWidth: 24 Layout.rightMargin: thumbnailMargin source: (iconName === undefined || iconName === "") ? icon : iconName } DtThemeText { Layout.fillHeight: true Layout.fillWidth: true text: title === undefined ? "" : title textColor: Platform.GlobalTheme.kFontPrimary elide: Text.ElideRight verticalAlignment: Text.AlignVCenter Tooltip { anchors.fill: parent mainText: parent.text posFollowCursor: true visible: parent.truncated } } MouseArea { id: closeButtonArea Layout.preferredHeight: 24 Layout.preferredWidth: 24 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight hoverEnabled: true visible: mouseAreaContainsMouse DtThemeBackground { backgroundColor: closeButtonArea.containsPress ? Platform.GlobalTheme.kErrorClick : Platform.GlobalTheme.kErrorNormal radius: Platform.GlobalTheme.kRadiusMin anchors.fill: parent visible: parent.containsMouse Tooltip { anchors.fill: parent mainText: qsTr("Close") posFollowCursor: true } } Icon { anchors.centerIn: parent width: 16 height: width mode: parent.containsMouse ? Icon.Highlight : Icon.AutoHighlight source: "window-close-symbolic" } onClicked: { UkuiTaskManager.TaskManager.activateWindowView([]); UkuiTaskManager.TaskManager.execSpecifiedAction(UkuiTaskManager.Action.Close, modelData); } } } VideoPlayerThumbnail { id: windowThumbnail Layout.alignment: Qt.AlignHCenter Layout.margins: thumbnailMargin Layout.preferredWidth: isHorizontal ? itemWidth : viewLoader.preChildrenSize - layoutSpacing*2 Layout.preferredHeight: isHorizontal ? viewLoader.preChildrenSize - 48 : itemHeight Layout.maximumHeight: maximumHeight - layoutSpacing * 3 - 24 Layout.maximumWidth: maximumWidth - layoutSpacing * 2 property real itemHeight property real itemWidth winId: windowVisible ? modelData : "" playerData: windowThumbnailMprisModel viewModel: view.model // 视频预览图需要保证按钮显示完全 clip: false onWinIdChanged: { if (winId === "") { return; } var itemGeometry = Platform.WindowManager.geometry(modelData); if (isHorizontal) { itemWidth = itemGeometry.width * ((viewLoader.preChildrenSize - 48) / itemGeometry.height); } else { itemHeight = itemGeometry.height * ((viewLoader.preChildrenSize - layoutSpacing*2) / itemGeometry.width); } } } } } } } } ukui-panel/widgets/ukui-task-manager/qml/icon/0000775000175000017500000000000015167645100020273 5ustar fengfengukui-panel/widgets/ukui-task-manager/qml/icon/ukui-start-symbolic.svg0000775000175000017500000000163415167645100024752 0ustar fengfengukui-panel/widgets/ukui-task-manager/qml/icon/ukui-end-symbolic-disable.svg0000775000175000017500000000166715167645100025772 0ustar fengfengukui-panel/widgets/ukui-task-manager/qml/icon/ukui-start-symbolic-disable.svg0000775000175000017500000000163415167645100026353 0ustar fengfengukui-panel/widgets/ukui-task-manager/qml/icon/ukui-end-symbolic.svg0000775000175000017500000000166715167645100024371 0ustar fengfengukui-panel/widgets/ukui-task-manager/qml/AppIcon.qml0000664000175000017500000002041115167645111021407 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * */ import QtQuick 2.12 import QtQuick.Layouts 1.12 import Qt5Compat.GraphicalEffects import org.ukui.quick.items 1.0 as UkuiItems import org.ukui.quick.platform 1.0 as Platform import org.ukui.panel.taskManager 1.0 as UkuiTaskManager Item { property alias appIcon: icon property alias appBackgroud: backgroud property bool isOpenGL: true property real ratio: 1 property int inset: 4 * ratio // background与控件的边距 function updateIconGeometry(winIdList) { Platform.WindowManager.setMinimizedGeometry(winIdList, backgroud); } Timer { id: iconDragTimer interval: 100 onTriggered: { if (iconDropArea.containsDrag) { updateIconGeometry(taskItemData.CurrentWinIdList); if (taskItemData.CurrentWinIdList[0] !== "") { UkuiTaskManager.TaskManager.activateWindow(taskItemData.CurrentWinIdList[0]) taskManager.hidethumbnail(); } } } } DropArea { id: iconDropArea anchors.fill: parent enabled: UkuiTaskManager.TaskManager.enableDragToApp function showTooltipIfNeeded() { if (tooltip.active && iconDropArea.containsDrag && taskItemData.CurrentWinIdList.length < 2) { tooltip.showTooltip(); } } onContainsDragChanged: showTooltipIfNeeded() //实现拖拽到未打开的固定图标上,显示tooltip onEntered: (dragEvent) => { // 表示图标内部是否接收到了拖拽事件(功能: 拖拽文件到已打开的应用图标上,有三态显示并进行激活窗口操作) if (taskItemListRoot.dragEventSource(dragEvent) !== "DropToAppIcon") { dragEvent.accepted = false; return; } if (taskItemData.CurrentWinIdList.length === 1) { iconDragTimer.restart(); } else { mouseArea.aboutToShowThumbnailView(true, thumbnailData, mouseArea) } } onPositionChanged: { // 拖拽到固定未打开的图标上,鼠标标识为禁用状态 if (taskItemData.CurrentWinIdList.length < 1) { drag.accepted = false; } } onExited: { iconDragTimer.stop(); tooltip.hideTooltip(); taskItemListRoot.requestThumbnailView(false, thumbnailData, mouseArea) } } UkuiItems.Tooltip { id: tooltip anchors.fill: parent mainText: taskItemData.Name posFollowCursor: false // 固定在任务栏的应用显示tooltip (taskItemData.CurrentWinIdList.length < 1) // 接收拖拽文件的图标显示tooltip (iconDropArea.containsDrag) active: iconDropArea.containsDrag ? true : taskItemData.CurrentWinIdList ? taskItemData.CurrentWinIdList.length < 1 : false onActiveChanged: iconDropArea.showTooltipIfNeeded() // 用于在有拖拽事件,并且只有一个打开窗口时的情况 location: { switch(Widget.container.position) { case UkuiItems.Types.Bottom: return UkuiItems.Dialog.BottomEdge; case UkuiItems.Types.Left: return UkuiItems.Dialog.LeftEdge; case UkuiItems.Types.Top: return UkuiItems.Dialog.TopEdge; case UkuiItems.Types.Right: return UkuiItems.Dialog.RightEdge; } } margin: 8 } UkuiItems.DtThemeBackground { id: backgroud Accessible.role: Accessible.Button Accessible.description: "This is task manager button of ukui-panel" Accessible.name: taskItemData.Id anchors.fill: parent anchors { leftMargin: isHorizontal? 0 : inset topMargin: isHorizontal? inset : 0 rightMargin: isHorizontal? 0 : inset bottomMargin: isHorizontal? inset : 0 } useStyleTransparency: false // id: mouseArea --> TaskManager.qml backgroundColor: iconDropArea.containsDrag ? Platform.GlobalTheme.kComponentAlphaHover : mouseArea.containsPress ? Platform.GlobalTheme.kComponentAlphaClick : mouseArea.containsMouse ? Platform.GlobalTheme.kComponentAlphaHover : Platform.GlobalTheme.kContainGeneralAlphaNormal radius: Platform.GlobalTheme.kRadiusNormal Rectangle { id: demandsAttention anchors.fill: parent color: "#FF9100" z: -1 radius: backgroud.radius visible: taskItemData.DemandsAttentionWinIdList ? (taskItemData.DemandsAttentionWinIdList.length > 0) : false NumberAnimation on opacity { running: demandsAttention.visible loops: 4 from: 0.25 to: 0.6 duration: 450 } } UkuiItems.Icon { id: icon anchors.margins: inset anchors.fill: parent Behavior on scale { NumberAnimation { duration: 100 } } } Loader { anchors.right: icon.right anchors.rightMargin: -3 anchors.top: icon.top anchors.topMargin: -3 active: taskItemData.UnreadMessagesNum > 0 sourceComponent: Rectangle { id: unreadMessagesBase height: icon.height / 2 width: height + additionalWidth radius: height / 2 property int additionalWidth: { if (taskItemData.UnreadMessagesNum < 10) { return 0; } else if (taskItemData.UnreadMessagesNum < 100){ return 6; } else { return 12; } } color: Platform.GlobalTheme.kErrorNormal.pureColor layer.enabled: isOpenCV layer.effect: DropShadow { radius: 2 samples: 5 color: Platform.GlobalTheme.kGrayAlpha10.pureColor } UkuiItems.DtThemeText { id: unreadMessagesNum anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter textColor: Platform.GlobalTheme.kFontWhite pointSizeOffset: -2 font.pixelSize: unreadMessagesBase.height * 5 / 8 //按设计稿比例设置固定字体大小 text: { if (taskItemData.UnreadMessagesNum < 100) { return taskItemData.UnreadMessagesNum; } else { return "99+" } } } } } } UkuiItems.DtThemeBackground { height: 4 * ratio width: taskItemData.CurrentWinIdList ? Math.min(taskItemData.CurrentWinIdList.length * 8 * ratio, 16 * ratio) : 16 radius: 2 * ratio anchors.verticalCenter: backgroud.bottom anchors.horizontalCenter: parent.horizontalCenter useStyleTransparency: false backgroundColor: taskItemData.HasActiveWindow? Platform.GlobalTheme.kBrandNormal : Platform.GlobalTheme.kGrayAlpha9 Behavior on width { NumberAnimation { duration: 200 } } } } ukui-panel/widgets/ukui-task-manager/qml/TaskManagerBase.qml0000664000175000017500000010563115167645111023056 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * hxf * */ import QtQml 2.15 import QtQuick 2.15 import QtQml.Models 2.15 import org.ukui.quick.widgets 1.0 import org.ukui.panel.taskManager 1.0 as UkuiTaskManager import org.ukui.quick.items 1.0 as Items import org.ukui.quick.platform 1.0 as Platform DropArea { id: taskItemListRoot property real ratio: 1 property var dragedObj: null property alias view: taskItemView property alias viewModel: taskItemProxyModel property bool taskManagerActived: false property bool isTaskMenuShow: false property bool isDragging: false property int resetItemsIndex: -1 // 请求显示预览图 signal requestThumbnailView(bool show, TaskItemData data, Item mouseArea) UkuiTaskManager.TaskManagerFilterModel { id: taskItemProxyModel screen: Widget.container.screen } Component { id: taskIconComponent Items.Icon {} } DelegateModel { id: taskItemDelegateModel property var dragedObject: null /** * 删除临时Item */ function removeTempItems() { for (let i = tempItems.count - 1; i >= 0; --i) { const obj = tempItems.get(i); obj.groups = [tempItems.name]; tempItems.remove(i); } } /** * 将对应itemsIndex的项,存在persistedItems组中,并从界面移除 * @param itemsIndex */ function removeVisualItem(itemsIndex) { if (itemsIndex < 0 || itemsIndex >= taskItemView.count) { return; } // 将被拖拽的项添加到持久化组中, 如果在items组中, 那么从可见列表移除 items.get(itemsIndex).groups = [persistedItems.name]; } /** * 将存起来的Item全部归位,并从persistedItems组中移除 */ function resetPersistedItems() { if (persistedItems.count > 0) { let i = persistedItems.count - 1; for (; i >= 0; --i) { const persistedItemObj = persistedItems.get(i); if (!persistedItemObj.inItems) { // TODO: listview中的数据往前挪可以同步缓存位置,往后挪则位置不会变,需要把临时Item最后出现的位置记下来 let tmpItemsIndex = tempItems.get(0).itemsIndex; persistedItems.addGroups(i, 1, [items.name]); items.move(persistedItemObj.itemsIndex, tmpItemsIndex, 1); } persistedItems.remove(i, 1); } } dragedObject = null; removeTempItems(); } // 临时生成的用于定位拖拽落点的Items组 groups: [ DelegateModelGroup { id: tempItems; name: "tempItems" } ] model: taskItemProxyModel delegate: Item { id: taskItemRoot property int dragStartIndex: -1 property var icon: model.Icon property bool isDragStatus: false property bool useSingleItem: taskItemView.isMergeStatus || (CurrentWinIdList ? CurrentWinIdList.length < 1 : true) //非合并状态下激活预览图时 对应的winId property var singleWinId: [] property bool iconNeedsUpdate: true // 三岛状态下,是否已切换为小插件样式 property bool quickWidgetLoaded: false property bool isItemActived: model.DemandsAttentionWinIdList ? (model.DemandsAttentionWinIdList.length !== 0) : false width: taskItemLoader.width height: taskItemLoader.height visible: !DelegateModel.inPersistedItems onIsItemActivedChanged: { taskItemView.updateActivedItem(isItemActived); } onIconChanged: { iconNeedsUpdate = true; } function generateDragImage() { let icon = taskIconComponent.createObject(this, {width: taskItemView.taskItemSize, height: taskItemView.taskItemSize}); if (icon !== null) { icon.addUnifiedIconBox = true icon.source = model.Icon icon.grabToImage(function (result) { taskItemRoot.Drag.imageSource = result.url; icon.destroy(); }); icon.visible = false } } // 拖拽设置, 手动开启拖拽 Drag.dragType: Drag.None Drag.hotSpot: Qt.point(taskItemView.taskItemSize/2, taskItemView.taskItemSize/2) // 处理拖拽完成信号 Drag.onDragFinished: function (dropAction) { taskItemListRoot.isDragging = false; // 拖拽被取消,仅处理内部拖拽 if (taskItemDelegateModel.persistedItems.count > 0) { let i = taskItemDelegateModel.persistedItems.count - 1; for (; i >= 0; --i) { const persistedItemObj = taskItemDelegateModel.persistedItems.get(i); if (!persistedItemObj.inItems) { // TODO: listview中的数据往前挪可以同步缓存位置,往后挪则位置不会变,需要把临时Item最后出现的位置记下来 persistedItemObj.groups = [taskItemDelegateModel.items.name]; } } } taskItemRoot.isDragStatus = false; } function startDrag() { // 存起来的被拖拽项目和临时生成的项目都不允许被拖动 if (!DelegateModel.inItems || DelegateModel.inPersistedItems || DelegateModel.inTempItems) { return; } const delegateModel = DelegateModel.model; const itemsIndex = DelegateModel.itemsIndex; dragStartIndex = itemsIndex; // 当前拖拽对象 delegateModel.dragedObject = delegateModel.items.get(itemsIndex); taskItemDelegateModel.removeVisualItem(itemsIndex); taskItemRoot.isDragStatus = true; const modelIndex = delegateModel.dragedObject.model.index; Drag.mimeData = { "text/plain": '{"dragStartIndex":' + dragStartIndex + ',"modelIndex":' + modelIndex + '}' }; Drag.active = true; // 不同的Action鼠标光标不同 Drag.startDrag(Qt.MoveAction); } MouseArea { id: mouseArea x: 0; y: 0 width: parent.width; height: parent.height hoverEnabled: !UkuiTaskManager.TaskManager.disableMouseHover acceptedButtons: { let button = Qt.NoButton; if (!UkuiTaskManager.TaskManager.disableMouseLeftButton) { button |= Qt.LeftButton } if (!UkuiTaskManager.TaskManager.disableMouseRightButton) { button |= Qt.RightButton } return button; } property int lastIndex: -1 property string currentWid: "" function activeWinId(winId) { if (UkuiTaskManager.TaskManager.windowIsActivated(winId)) { UkuiTaskManager.TaskManager.execSpecifiedAction(UkuiTaskManager.Action.Minimize, winId); } else { UkuiTaskManager.TaskManager.activateWindow(winId); } } function aboutToShowThumbnailView(isShow, data, item) { // 设置预览图窗口信息 // 在非合并状态下,由loader里的item触发request信号和参数 data.currentTaskItem = item; taskItemListRoot.requestThumbnailView(isShow, data, item); } // 为拖拽截图 onPressed: { if (iconNeedsUpdate) { parent.generateDragImage(); iconNeedsUpdate = false; } } drag.target: mouseArea drag.onActiveChanged: { taskItemListRoot.requestThumbnailView(false, null, mouseArea); if (drag.active) { taskItemListRoot.isDragging = true; taskItemRoot.startDrag(); } else { mouseArea.x = 0; mouseArea.y = 0; } } onClicked: (mouse) => { if (mouse.button === Qt.RightButton) { taskItemProxyModel.openMenu(false, model.Actions, taskItemView); taskManagerActived = true; isTaskMenuShow = true; } else { if (CurrentWinIdList.length === 0) { taskItemDelegateModel.model.launch(taskItemDelegateModel.model.index(model.index, 0), taskItemRoot); return; } let index = -1; if (taskItemView.isMergeStatus) { // 轮转 if (currentWid !== "") { index = CurrentWinIdList.indexOf(currentWid); if (index < (CurrentWinIdList.length - 1)) { ++index; } else { index = 0; } } } else { // 由taskList实现 index = taskItemLoader.item.indexAt(mouseX, mouseY); } if (index < 0) { index = 0; } else if (index >= CurrentWinIdList.length) { index = CurrentWinIdList.length - 1; } currentWid = CurrentWinIdList[index]; /** * 鼠标点击,更新窗口最小化和激活动画。 */ updateIconGeometry(currentWid); activeWinId(currentWid); } taskManager.hidethumbnail(); } onEntered: { if (CurrentWinIdList !== undefined && CurrentWinIdList.length > 0 && !taskItemRoot.quickWidgetLoaded) { if (taskItemView.isMergeStatus) { mouseArea.aboutToShowThumbnailView(true, thumbnailData, mouseArea); } } } onExited: { taskItemListRoot.requestThumbnailView(false, thumbnailData, mouseArea); pluginButtonLoader.active = false; } TaskItemData { id: thumbnailData windowIdList: model.CurrentWinIdList windowIcons: model.WindowIcons windowIconsName: model.WindowIconsName windowTitles: model.WindowTitles } Loader { id: taskItemLoader property var taskItemData: model property var thumbnailData: thumbnailData sourceComponent: { if (taskItemRoot.DelegateModel.inTempItems) { return tempTaskitem; } if (taskItemRoot.useSingleItem) { if (taskItemRoot.quickWidgetLoaded) { return quickWidgetItem; } else { return singleTaskItem; } } else { return listTaskItem; } } } Component { id: tempTaskitem Item { width: taskItemView.taskItemSize height: taskItemView.taskItemSize } } // 非合并状态 图标+名称 Component { id: listTaskItem AppList { height: childrenRect.height width: childrenRect.width itemSize: taskItemView.taskItemSize isHorizontal: taskItemView.orientation === ListView.Horizontal spacing: taskItemView.spacing model: taskItemData.CurrentWinIdList ratio: taskItemListRoot.ratio iconIndexAboutToBeScaled: { if (mouseArea.containsPress) { return indexAt(mouseArea.mouseX, mouseArea.mouseY); } return -1; } } } Component { id: singleTaskItem AppIcon { // 在任务栏横向的时候,单个图标的三态区域上下边距为4,左右边距为8。两方不一致,需要特殊处理。 // 并且在设计稿最新改动中(2025.9.19),各个插件的间距也为8,所以作为首项item不能留有左右的两边的间距。 // 任务栏竖向的时候,同理。 width: isHorizontal ? (taskItemView.taskItemSize - inset * 2) : taskItemView.taskItemSize height: isHorizontal ? taskItemView.taskItemSize : (taskItemView.taskItemSize - inset * 2) appIcon.source: taskItemData.IconName === "" ? taskItemData.Icon : taskItemData.IconName appIcon.addUnifiedIconBox: true appIcon.scale: mouseArea.containsPress ? 0.8 : 1.0 ratio: taskItemListRoot.ratio } } Component { id: quickWidgetItem Item { height: taskItemView.taskItemSize width: quickWidget.preferredWidth + margins * 2 property int margins: 4 * taskItemListRoot.ratio UkuiTaskManager.WidgetDelegate { id: quickWidget anchors.fill: parent anchors.margins: parent.margins quickWidgetId: taskItemData.QuickWidgetId } function updateIconGeometry(winIdList) { Platform.WindowManager.setMinimizedGeometry(winIdList, this); } } } /** * 三岛任务栏小插件切换按钮,相关属性:taskItemRoot.quickWidgetLoaded */ property bool hasQuickWidgetId: model.QuickWidgetId !== "" && model.QuickWidgetId !== undefined && root.isIslandMode onHasQuickWidgetIdChanged: { if (hasQuickWidgetId) { quickWidgetTimer.createObject(mouseArea); } } Component { id: quickWidgetTimer Timer { interval: 1000 running: mouseArea.containsMouse onTriggered: { pluginButtonLoader.active = true; } } } Loader { id: pluginButtonLoader anchors.top: mouseArea.top anchors.topMargin: 1 anchors.right: mouseArea.right anchors.rightMargin: 1 active: false sourceComponent: pluginButton } Component { id: pluginButton Items.DtThemeBackground { width: 20; height: width radius: width / 2 useStyleTransparency: false backgroundColor: mousearea.containsPress ? Platform.GlobalTheme.kGray7 : mousearea.containsMouse ? Platform.GlobalTheme.kGray6 : Platform.GlobalTheme.kContainSecondaryNormal MouseArea { id:mousearea anchors.fill: parent hoverEnabled: true onClicked: { taskItemRoot.quickWidgetLoaded = !taskItemRoot.quickWidgetLoaded; taskManager.hidethumbnail(); } } Items.Icon { anchors.fill: parent anchors.margins: 2 source: taskItemRoot.quickWidgetLoaded ? "://org.ukui.panel.taskManager/qml/icons/back.svg" : "://org.ukui.panel.taskManager/qml/icons/to.svg" } } } } /** * iconGeometry功能 */ property var currentWinIdList: model.CurrentWinIdList property var hasActiveWindow: model.HasActiveWindow property int itemIndex: DelegateModel.itemsIndex property bool invisibleOfFront: (x < taskItemView.contentX) || (y < taskItemView.contentY) property bool invisibleOfBack: (x > taskItemView.width + taskItemView.contentX) || (y > taskItemView.height + taskItemView.contentY) // 调用setMinimizedGeometry接口,默认参数为CurrentScreenWinIdList function updateIconGeometry(winIdList = CurrentScreenWinIdList) { if (taskItemLoader.item && !taskItemRoot.DelegateModel.inTempItems) { if (invisibleOfFront) { Platform.WindowManager.setMinimizedGeometry(winIdList, virtualFrontItem); } else if (invisibleOfBack) { Platform.WindowManager.setMinimizedGeometry(winIdList, virtualBackItem); } else { taskItemLoader.item.updateIconGeometry(winIdList); } } } function addIndexToGeometryList() { if (model.CurrentScreenWinIdList) { // 在 *所在屏幕* 的位置,添加最小化动画 // Note: 图标Click后,会在点击所对应的位置,进行最小化动画 if (model.CurrentScreenWinIdList.length > 0 && !taskItemView.pendingUpdatesList.includes(itemIndex)) { taskItemView.pendingUpdatesList.push(itemIndex); updateGeometryList.restart(); } } } Component.onCompleted: { //初始化、拖拽后更新model、切换任务栏方向,都会触发 addIndexToGeometryList(); } Component.onDestruction: { if (isItemActived) { taskItemView.updateActivedItem(false); } } onCurrentWinIdListChanged: { addIndexToGeometryList(); } // 激活窗口后,在窗口 *对应屏幕* 上进行最小化动画 onHasActiveWindowChanged: { if (HasActiveWindow && model.CurrentScreenWinIdList.length > 0) { updateIconGeometry(); } } Behavior on width { // 主要提供三岛小插件切换的动画 enabled: root.isIslandMode NumberAnimation { duration: 150 easing.type: Easing.OutQuad } } } } ListView { id: taskItemView // view的宽高 在main的view.width view.height中定义 property bool windowVisible: false property bool isMergeStatus: { var status = Widget.globalConfig.mergeIcons; return (status === undefined) || (status === 0) ; } property bool isHorizontal: Widget.orientation === Items.Types.Horizontal property real taskItemSize: 48 property int activedItem: 0 interactive: false // flickDeceleration: filck减速速率,默认为1500。 // 调整减速速率,达到在翻页时,以较快速度进行滑动。 // boundsMovement: Flickable.StopAtBounds 设置此属性会偶现切换方向后,contentX和ContentY出现异常导致内部不显示的问题 flickDeceleration: 10000 spacing: 0 model: taskItemDelegateModel cacheBuffer: taskItemView.isHorizontal ? Math.max(0, contentWidth) : Math.max(0, contentHeight) // 使用delayed属性,避免方向切换时,taskItemSize立即更新,导致过程中数值错误 Binding { target: taskItemView property: "taskItemSize" value: isHorizontal ? taskItemListRoot.parent.height : taskItemListRoot.parent.width delayed: true } onTaskItemSizeChanged: { if (contentX !== 0 || contentY !== 0) { positionViewAtBeginning(); } pushAllIndex(); } onIsMergeStatusChanged: { pushAllIndex(); } onWindowVisibleChanged: { if(Platform.WindowManager.isWaylandSession) { pushAllIndex(); } } onContentXChanged: { pushAllIndex(); } onContentYChanged: { pushAllIndex(); } onIsHorizontalChanged: { // 重置滚动位置 positionViewAtBeginning(); orientation = isHorizontal ? ListView.Horizontal : ListView.Vertical; } function updateActivedItem(isActived) { taskItemView.activedItem = isActived ? taskItemView.activedItem + 1 : Math.max(taskItemView.activedItem - 1, 0); taskManagerActived = taskItemView.activedItem > 0; } function updateIconState() { for (let i = 0; i < taskItemDelegateModel.count; ++i) { taskItemView.itemAtIndex(i).iconNeedsUpdate = true; } } Component.onCompleted: { orientation = isHorizontal ? ListView.Horizontal : ListView.Vertical; Platform.Theme.iconThemeChanged.connect(updateIconState); if (Widget.globalConfig.mergeIcons === undefined) { Widget.globalConfig.mergeIcons = 0; } } /** * iconGeometry */ property var pendingUpdatesList: [] Connections { target: Widget.container function onPositionChanged() { taskItemView.pushAllIndex(); } } function pushAllIndex() { pendingUpdatesList.length = 0; for (var i = 0; i < taskItemView.count; ++i) { pendingUpdatesList.push(i); } if (pendingUpdatesList.length > 0) { updateGeometryList.restart(); } } Timer { id: updateGeometryList interval: 500 onTriggered: { for (let i = 0; i < taskItemView.pendingUpdatesList.length; ++i) { let index = taskItemView.pendingUpdatesList[i]; let item = taskItemView.itemAtIndex(index); if (item) { item.updateIconGeometry(); } } taskItemView.pendingUpdatesList.length = 0; } } Item { id: virtualFrontItem x: 0; y: 0 width: 10 height: 10 } Item { id: virtualBackItem x: taskItemView.width - width; y: taskItemView.height - height width: 10 height: 10 } displaced: Transition { NumberAnimation { properties: "x,y" easing.type: Easing.OutQuad duration: 300 } } move: Transition { NumberAnimation { properties: "x,y"; duration: 300 } } add: Transition { NumberAnimation { id: addAnimation property: taskItemView.isHorizontal ? "y" : "x" from: (Widget.container.position === Items.Types.Left) || (Widget.container.position === Items.Types.Top) ? -taskItemView.taskItemSize : taskItemView.taskItemSize to: 0 easing.type: Easing.OutCubic duration: 300 } } remove: Transition { NumberAnimation { id: removeAnimation property: addAnimation.property easing.type: Easing.OutCubic from: 0; to: addAnimation.from duration: 300 } } } // 获取ListView的坐标对应的ContentItem内部坐标 // listview与dropArea的大小需要重合 function getContentPoint(localX, localY) { return Qt.point(localX + taskItemView.contentX, localY + taskItemView.contentY); } /** * 事件来源判断 * 内部事件: 任务栏内部拖拽换位--"InternalEvent" * 外部事件: 从开始菜单或桌面,固定到任务栏--"PinToTaskbar" * 从桌面、文件管理器,拖到任务栏可打开应用图标上 --"DropToAppIcon" (enableDragToApp需为true) * 无效事件: "InvalidEvent" */ property string panelDragEvent: "InvalidEvent" function dragEventSource(event) { if (taskItemDelegateModel.dragedObject !== null) { return "InternalEvent"; } let source = event.getDataAsString("source"); if (source === "ukui-menu") { let url = event.getDataAsString("url"); return url.startsWith("app://") ? "PinToTaskbar" : "InvalidEvent"; } if (UkuiTaskManager.TaskManager.enableDragToApp) { if (event.urls && event.urls.length > 0) { return "DropToAppIcon"; } } return "InvalidEvent"; } // 获取一个Item的中点坐标 function getItemMidPoint(item) { return Qt.point(item.x + item.width/2, item.y + item.height/2); } // point 是否在item的中点前 function beforeMidpoint(item, point) { let midPoint = getItemMidPoint(item); if (taskItemView.orientation === ListView.Horizontal) { return point.x < midPoint.x; } else { return point.y < midPoint.y } } // 1.拖拽进入事件 // 拖拽进入,需要生成临时Item onEntered: (dragEvent) => { // 1.处理进入拖拽区域时的边缘点情况,避免丢失拖拽事件 let enterX = dragEvent.x === width ? dragEvent.x - 1 : dragEvent.x; let enterY = dragEvent.y === height ? dragEvent.y - 1 : dragEvent.y; const contentPoint = getContentPoint(enterX, enterY); // 2.删除上次未删除的临时Item,保证只有一个临时Item if (tempItems.count > 0) { taskItemDelegateModel.removeTempItems(); } // 3.获取进入点下方的Item, 如果为null,则说明拖拽到了空白位置 let insertIndex = -1; let pointItem = taskItemView.itemAt(contentPoint.x, contentPoint.y); if (pointItem !== null) { // 4.通过进入点的对象的itemsIndex获取各种数据。 insertIndex = pointItem.DelegateModel.itemsIndex; // 判断中点位置,确定在插入在前还是后,insertIndex or insertIndex+1 const maxIdx = taskItemDelegateModel.items.count - 1; if ((insertIndex > 0) && (insertIndex < maxIdx) && beforeMidpoint(pointItem, contentPoint)) { ++insertIndex; } } else { // 5.拖拽进入点是空白区域 insertIndex = taskItemDelegateModel.items.count; } /** * 4.判断事件来源 * 区分拖拽事件的来源,一般有两个来源: * 1.内部拖拽事件,拖拽listview的Item进行位置的调整。 * 2.外部事件,将桌面图标拖拽到任务栏上。 */ const eventType = dragEventSource(dragEvent); panelDragEvent = eventType; if (eventType === "InvalidEvent") { dragEvent.accepted = false; return; } else if (eventType === "PinToTaskbar") { let id = dragEvent.getDataAsString("url").slice(6); let itemsIndex = -1; // 判断任务栏是否已经有同id图标 for (var i = 0; i < taskItemView.count; ++i) { if (taskItemDelegateModel.items.get(i).model.Id === id) { itemsIndex = taskItemDelegateModel.items.get(i).itemsIndex; resetItemsIndex = itemsIndex; } } taskItemDelegateModel.removeVisualItem(itemsIndex); } else if (eventType === "DropToAppIcon" && UkuiTaskManager.TaskManager.enableDragToApp) { dragEvent.accepted = false; return; } // 5.创建临时Item,并将他放到tempItems组中,后续可通过该组删除它 if (insertIndex < 0) { insertIndex = 0; } else if (insertIndex > taskItemDelegateModel.items.count) { insertIndex = taskItemDelegateModel.items.count; } taskItemDelegateModel.items.insert( insertIndex, { Name: "" }, [taskItemDelegateModel.items.name, "tempItems"] ); } // 2.拖拽移出事件 onExited: { taskItemDelegateModel.removeTempItems(); if (panelDragEvent === "PinToTaskbar") { // 外部拖拽退出后,任务栏已有图标返回原来位置 let i = taskItemDelegateModel.persistedItems.count - 1; for (; i >= 0; --i) { const persistedItemObj = taskItemDelegateModel.persistedItems.get(i); if (!persistedItemObj.inItems) { persistedItemObj.groups = [taskItemDelegateModel.items.name]; if (resetItemsIndex !== -1) { taskItemDelegateModel.items.move(persistedItemObj.itemsIndex, resetItemsIndex, 1); } } } resetItemsIndex = -1; } } // 3.拖拽移动事件 onPositionChanged: (dragEvent) => { if (tempItems.count === 1) { // 落点 let currentPoint = getContentPoint(dragEvent.x, dragEvent.y); let targetItem = taskItemView.itemAt(currentPoint.x, currentPoint.y); if (targetItem !== null && !targetItem.DelegateModel.inTempItems) { let sourceIndex = tempItems.get(0).itemsIndex; let targetIndex = targetItem.DelegateModel.itemsIndex; const bmp = beforeMidpoint(targetItem, currentPoint); if ((sourceIndex < targetIndex) && bmp) { --targetIndex; } else if ((sourceIndex > targetIndex) && !bmp) { ++targetIndex; } let moveCount = Math.abs(targetIndex - sourceIndex); if (moveCount === 0) { return; } if (sourceIndex < targetIndex) { taskItemDelegateModel.items.move(sourceIndex + 1, sourceIndex, moveCount); } else { taskItemDelegateModel.items.move(targetIndex, targetIndex + 1, moveCount); } } } } // 4.拖拽放下事件 onDropped: (dragEvent) => { // 1.获取丢下点的Index let droppedIndex = -1; if (tempItems.count > 0) { // 默认情况下临时Item对应的位置就是丢下的位置 let tempObj = tempItems.get(0); droppedIndex = tempObj.inItems ? tempObj.itemsIndex : taskItemDelegateModel.items.count; } else { // 修正边缘落点情况 let enterX = dragEvent.x === width ? dragEvent.x - 1 : dragEvent.x; let enterY = dragEvent.y === height ? dragEvent.y - 1 : dragEvent.y; let contentPoint = getContentPoint(enterX, enterY); let dropTargetItem = taskItemView.itemAt(contentPoint.x, contentPoint.y); droppedIndex = (dropTargetItem === null) ? taskItemDelegateModel.items.count : dropTargetItem.DelegateModel.itemsIndex; } // 2.将存起来的Item全部归位,并清空临时对象 let eventType = dragEventSource(dragEvent); taskItemDelegateModel.resetPersistedItems(); // 3.事件类型 if (eventType === "InternalEvent") { const obj = JSON.parse(dragEvent.text); if (obj !== null) { taskItemProxyModel.setOrder(taskItemDelegateModel.model.index(obj.modelIndex, 0), droppedIndex); } } else if (eventType === "PinToTaskbar") { // 外部事件,执行外部操作 let id = dragEvent.getDataAsString("url").slice(6); taskItemProxyModel.addQuickLauncher(id, droppedIndex); } taskItemListRoot.isDragging = false; panelDragEvent = "InvalidEvent"; } } ukui-panel/widgets/ukui-task-manager/utils.cpp0000664000175000017500000000346015167645100020421 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "utils.h" #include #include "window-manager.h" static UkuiSearch::ApplicationInfo *applicationInfo = nullptr; static std::once_flag flag; UkuiSearch::ApplicationInfo *Utils::getApplicationInfo() { std::call_once(flag, [ & ] { applicationInfo = new UkuiSearch::ApplicationInfo(); }); return applicationInfo; } QString Utils::desktopFileFromPid(uint pid) { QString desktopFile; getApplicationInfo()->tranPidToDesktopFp(pid, desktopFile); return desktopFile; } QString Utils::desktopFileFromWid(const QString &wid) { QString desktopFile; getApplicationInfo()->desktopFilePathFromName(UkuiQuick::WindowManager::appId(wid), desktopFile); if(desktopFile.isEmpty()) { getApplicationInfo()->tranPidToDesktopFp(UkuiQuick::WindowManager::pid(wid),desktopFile); } return desktopFile; } QString Utils::desktopFilePathFromName(const QString&name) { QString desktopFile; getApplicationInfo()->desktopFilePathFromName(name, desktopFile); return desktopFile; } ukui-panel/widgets/ukui-task-manager/plugin/0000775000175000017500000000000015167645100020050 5ustar fengfengukui-panel/widgets/ukui-task-manager/plugin/qml/0000775000175000017500000000000015167645111020643 5ustar fengfengukui-panel/widgets/ukui-task-manager/plugin/qml/main.qml0000664000175000017500000002515615167645111022313 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: qiqi49 * hxf * */ import QtQuick 2.12 import QtQuick.Layouts 1.12 import org.ukui.quick.widgets 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.taskManager 1.0 as UkuiTaskManager WidgetItem { id: root Layout.objectName: "layout" property bool isHorizontal: Widget.orientation === Types.Horizontal property int maxLength: { if (isHorizontal) { if (parent.Layout.maximumWidth > 0) { return parent.Layout.maximumWidth; } else { if (parent.width > 0) { return parent.width; } else { return height + buttonBase.width; } } } else { return parent.Layout.maximumHeight ? parent.Layout.maximumHeight : parent.height; } } property bool isIntervactive: { if (isHorizontal) { return taskManagerView.view.contentWidth > maxLength; } else { return taskManagerView.view.contentHeight > maxLength; } } property real ratio: parent.ratio ? parent.ratio : 1 property int spacing: parent ? (parent.ratio ? 8 * parent.ratio : 8) : 8 property bool isIslandMode: parent.isIslandMode ? parent.isIslandMode : false Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? childrenRect.width : width Layout.preferredHeight: isHorizontal ? height : childrenRect.height // 最小宽高:保证taskManager在滚动状态时,能够至少显示一个图标和翻页按钮 Layout.minimumWidth: isHorizontal ? Math.min((taskManagerView.view.contentWidth + taskManagerView.view.taskItemSize + spacing), (height + buttonBase.width)) : 0 onWidgetWindowChanged: { if (widgetWindow) { widgetWindow.onVisibleChanged.connect(updateWindowVisible); } } function updateWindowVisible() { taskManagerView.view.windowVisible = widgetWindow.visible; } function flickView(distance) { // 计算轻弹速度 let velocity = Math.round(Math.sqrt(2 * Math.abs(distance) * taskManagerView.view.flickDeceleration)); // 确定轻弹方向 let direction = (distance > 0) ? 1 : -1 taskManagerView.view.maximumFlickVelocity = velocity; if (isHorizontal) { taskManagerView.view.flick(velocity * direction, 0); } else { taskManagerView.view.flick(0, velocity * direction); } } // 向前滚动view,进行Overshoot时的处理 function flickViewForward(distance) { // 想要滚动的距离,采取向上取整,避免剩余0.XX时还需要再进行翻页 let preDistance = Math.ceil(distance); // 剩余的距离 let remainDistance = isHorizontal ? taskManagerView.view.contentX : taskManagerView.view.contentY; if (preDistance < remainDistance) { flickView(preDistance); } else { flickView(remainDistance + taskManagerView.viewOvershoot); } } // 向后滚动view,进行Overshoot时的处理 function flickViewBackward(distance) { // 想要滚动的距离,采取向上取整,避免剩余0.XX时还需要再进行翻页 let preDistance = Math.ceil(distance); // 剩余的距离,采取向下取整,原因同上 let remainDistance = isHorizontal ? Math.max(0, taskManagerView.view.contentItem.childrenRect.width - taskManagerView.view.contentX - taskManagerView.view.width) : Math.max(0, taskManagerView.view.contentItem.childrenRect.height - taskManagerView.view.contentY - taskManagerView.view.height); remainDistance = Math.floor(remainDistance); if (preDistance < remainDistance) { flickView(preDistance * -1); } else { flickView((remainDistance + taskManagerView.viewOvershoot) * -1); } } GridLayout { id: gridLayout width: isHorizontal ? (isIntervactive ? maxLength : taskManagerView.width) : parent.width height: isHorizontal ? parent.height : (isIntervactive ? maxLength : taskManagerView.height) columnSpacing: root.spacing rowSpacing: root.spacing columns: taskManagerView.view.isHorizontal ? 2 : 1 rows: taskManagerView.view.isHorizontal ? 1 : 2 // taskManager MouseArea { id: wheelArea Layout.preferredWidth: isHorizontal ? taskManagerView.width : parent.width Layout.preferredHeight: isHorizontal ? parent.height : taskManagerView.height enabled: isIntervactive onWheel: (wheel) => { flickView(wheel.angleDelta.y); } UkuiTaskManager.TaskManagerView { id: taskManagerView // 三岛、经典模式下,taskManager.width都留出一个item的空白宽度,并且可以接受drop事件 property int visualWidth: isIntervactive ? childrenRect.width : childrenRect.width + view.taskItemSize + spacing // 超长滚动时,内容可超过边界的距离 property int viewOvershoot: 120 width: isHorizontal ? visualWidth : parent.width height: isHorizontal ? parent.height : childrenRect.height ratio: root.ratio view.clip: isIntervactive view.spacing: root.spacing view.width: { if (isHorizontal) { if (maxLength < view.contentItem.childrenRect.width) { return maxLength - buttonBase.width - root.spacing; } else { return isIslandMode ? view.contentItem.childrenRect.width : maxLength; } } else { return parent.width } } view.height: { if (isHorizontal) { return parent.height } else { if (maxLength < view.contentItem.childrenRect.height) { return maxLength - buttonBase.height - root.spacing } else { return isIslandMode ? view.contentItem.childrenRect.height : maxLength; } } } } } // 超长滚动按钮 按钮宽高比为 0.8 StyleBackground { id: buttonBase Layout.preferredHeight: isHorizontal ? (parent.height - spacing*2) : (buttonBase.width*0.8*2 + 1) Layout.preferredWidth: isHorizontal ? (buttonBase.height*0.8*2 + 1) : (parent.width - spacing*2) Layout.alignment: isHorizontal ? Qt.AlignVCenter : Qt.AlignHCenter Layout.margins: 2 property int iconSize: isHorizontal ? (buttonBase.height / 2) : (buttonBase.width / 2) paletteRole: Theme.Text useStyleTransparency: false alpha: 0.1 radius: 12 GridLayout { anchors.fill: parent rows: isHorizontal ? 1 : children.length columns: isHorizontal ? children.length : 1 rowSpacing: 0 columnSpacing: 0 // 上一页 MouseArea { Layout.fillHeight: true Layout.fillWidth: true property string iconEnabled: "://org.ukui.panel.taskManager/qml/icon/ukui-start-symbolic.svg" property string iconDisabled: "://org.ukui.panel.taskManager/qml/icon/ukui-start-symbolic-disable.svg" property bool isAtBeginning: isHorizontal ? taskManagerView.view.atXBeginning : taskManagerView.view.atYBeginning onClicked: { if (!isAtBeginning) { flickViewForward(isHorizontal ? taskManagerView.view.width : taskManagerView.view.height); } } Icon { width: buttonBase.iconSize; height: width anchors.centerIn: parent mode: Icon.AutoHighlight rotation: isHorizontal ? 0 : 90 source: parent.isAtBeginning ? parent.iconDisabled : parent.iconEnabled } } StyleBackground { Layout.fillHeight: isHorizontal Layout.fillWidth: !isHorizontal Layout.preferredHeight: 1 Layout.preferredWidth: 1 paletteRole: Theme.Text useStyleTransparency: false alpha: 0.15 } // 下一页 MouseArea { Layout.fillHeight: true Layout.fillWidth: true property string iconEnabled: "://org.ukui.panel.taskManager/qml/icon/ukui-end-symbolic.svg" property string iconDisabled: "://org.ukui.panel.taskManager/qml/icon/ukui-end-symbolic-disable.svg" property bool isAtEnd: isHorizontal ? taskManagerView.view.atXEnd : taskManagerView.view.atYEnd onClicked: { if (!isAtEnd) { flickViewBackward(isHorizontal ? taskManagerView.view.width : taskManagerView.view.height); } } Icon { width: buttonBase.iconSize; height: width anchors.centerIn: parent mode: Icon.AutoHighlight rotation: isHorizontal ? 0 : 90 source: parent.isAtEnd ? parent.iconDisabled : parent.iconEnabled } } } } } } ukui-panel/widgets/ukui-task-manager/plugin/metadata.json0000775000175000017500000000116715167645100022533 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.panel.taskManager", "Icon": "taskManager", "Name": "taskManager", "Name[zh_CN]": "任务管理器", "Name[bo_CN]": "ལས་འགན་དོ་དམ་ཆས།", "Description": "taskManager", "Description[zh_CN]": "任务管理器", "Description[bo_CN]": "ལས་འགན་དོ་དམ་ཆས།", "Version": "1.0.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "Contents": { "Main": "qml/main.qml" } } ukui-panel/widgets/ukui-task-manager/task-manager-plugin.cpp0000664000175000017500000000452315167645100023130 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: qiqi49 * */ #include "task-manager-plugin.h" #include #include #include #include "ukui-task-manager.h" #include "actions.h" #include "task-manager-filter-model.h" #include "widget-delegate.h" void TaskManagerPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.taskManager")); qmlRegisterSingletonType(uri, 1, 0, "TaskManager", [] (QQmlEngine *, QJSEngine *) -> QObject* { return &TaskManager::UkuiTaskManager::self(); }); qmlRegisterType(uri, 1, 0, "TaskManagerFilterModel"); qmlRegisterType(uri, 1, 0, "WidgetDelegate"); qmlRegisterUncreatableType(uri, 1, 0, "Action", "Only enumeration variables are required"); qRegisterMetaType("TaskManager::Action::Type"); qRegisterMetaType("TaskManager::Actions"); } void TaskManagerPlugin::initializeEngine(QQmlEngine* engine, const char* uri) { Q_UNUSED(engine); Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.taskManager")); //workaround bug#470839 这个构造中有roundTrip,可能会触发屏幕改变信号,导致触发任务栏新增或删除,如果上面的qmlRegisterSingletonType中初始化可能会导致循环调用 //这里确保UkuiQuick::WindowManager和TaskManager::UkuiTaskManager提前初始化好并且在主线程 UkuiQuick::WindowManager::self(); TaskManager::UkuiTaskManager::self(); } ukui-panel/widgets/ukui-task-manager/actions.cpp0000664000175000017500000000553215167645100020723 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "actions.h" namespace TaskManager { class ActionPrivate { public: ActionPrivate(); ~ActionPrivate(); QString m_name; Action::Type m_type = Action::Type::Invalid; QVariant m_param; QAction *m_action = nullptr; }; ActionPrivate::ActionPrivate() { m_action = new QAction; } ActionPrivate::~ActionPrivate() { if(m_action) { delete m_action; m_action = nullptr; } } Action::Action(QObject *parent) : QObject(parent), d(new ActionPrivate()) { initConnection(); } Action::Action(const QString &name, const QString &displayName, const QIcon &icon, Type type, const QVariant ¶m, QObject *parent) : QObject(parent), d(new ActionPrivate()) { d->m_name = name; d->m_type = type; d->m_param = param; d->m_action->setText(displayName); d->m_action->setIcon(icon); initConnection(); } Action::Action(const Action &other) { d = other.d; initConnection(); } Action::~Action() = default; QString Action::name() const { return d->m_name; } Action::Type Action::type() const { return d->m_type; } void Action::setName(const QString &name) { d->m_name = name; } QString Action::text() const { return d->m_action->text(); } void Action::setText(const QString &name) { d->m_action->setText(name); } QIcon Action::icon() const { return d->m_action->icon(); } void Action::setIcon(const QIcon &icon) { d->m_action->setIcon(icon); } void Action::setType(const Action::Type &type) { d->m_type = type; } bool Action::operator==(const Action &other) const { return(d->m_name == other.name() && d->m_type == other.type()); } QVariant Action::param() { return d->m_param; } void Action::setParam(const QVariant ¶m) { d->m_param = param; } void Action::initConnection() { connect(d->m_action, &QAction::triggered, this, [&](){ Q_EMIT actionTriggered(d->m_param); }); } QAction *Action::internalAction() const { return d->m_action; } bool Action::enabled() const { return d->m_action->isEnabled(); } void Action::setEnabled(bool enabled) { d->m_action->setEnabled(enabled); } } ukui-panel/widgets/ukui-task-manager/utils.h0000664000175000017500000000232015167645100020060 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_TASK_MANAGER_UTILS_H #define UKUI_TASK_MANAGER_UTILS_H #include #include #include class Utils { public: static UkuiSearch::ApplicationInfo *getApplicationInfo(); static QString desktopFileFromPid(uint pid); static QString desktopFileFromWid(const QString &wid); static QString desktopFilePathFromName(const QString &name); }; #endif //UKUI_TASK_MANAGER_UTILS_H ukui-panel/widgets/ukui-task-manager/task-manager-plugin.h0000664000175000017500000000227115167645100022573 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: qiqi49 * */ #ifndef UKUI_PANEL_TASK_MANAGER_PLUGIN_H #define UKUI_PANEL_TASK_MANAGER_PLUGIN_H #include class TaskManagerPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; void initializeEngine(QQmlEngine *engine, const char *uri) override; }; #endif //UKUI_PANEL_TASK_MANAGER_PLUGIN_H ukui-panel/widgets/ukui-task-manager/ukui-task-manager.h0000664000175000017500000001452415167645111022260 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUITASKMANAGER_H #define UKUITASKMANAGER_H #include #include #include #include #include "actions.h" namespace TaskManager { class UkuiTaskManager : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QString currentActiveWinId READ currentActiveWinId NOTIFY currentActiveWinIdChanged) Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) Q_PROPERTY(bool disableMouseRightButton READ disableMouseRightButton NOTIFY disableMouseRightButtonChanged) Q_PROPERTY(bool disableMouseHover READ disableMouseHover NOTIFY disableMouseHoverChanged) Q_PROPERTY(bool enableDragToApp READ enableDragToApp WRITE setEnableDragToApp NOTIFY enableDragToAppChanged) public: enum AdditionalRoles { Id = Qt::UserRole + 1, //desktop文件全路径 DesktopFile, Name, //名称 GenericName, //应用GenericName IconName, //图标名称 Icon, //图标 WinIdList, //winID列表 CurrentDesktopWinIdList, //当前工作区的窗口 WindowGeometries, WindowTitles, WindowIcons, WindowIconsName, CurrentWinIdList, CurrentScreenWinIdList, //当前屏幕上的窗口列表 DemandsAttentionWinIdList, //处于demandsAttention状态的窗口列表 HasLauncher, //快速启动按钮位置(从0开始),-1表示无快速启动按钮 Actions, //可执行的action,目前只包含desktop action UnreadMessagesNum, //未读消息数量 HasActiveWindow, ApplicationMenuServiceName, ApplicationMenuObjectPath, QuickWidgetId }; Q_ENUM(AdditionalRoles) static UkuiTaskManager &self(); ~UkuiTaskManager() override; QHash roleNames() const override; QVariant data(const QModelIndex &index, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent) const override; /** * 快速启动按钮 增加/交换位置 * @param desktopFile 目标desktop文件 * @param order 增加或交换位置 */ void setQuickLauncher(const QString &desktopFile, int order); void setOrder(const QModelIndex &index, int order); QModelIndex indexOf(const QString &appId); QString currentActiveWinId() const; Q_INVOKABLE static void activateWindowView(const QStringList &winIds); /** * 激活窗口 * @param winId */ Q_INVOKABLE void activateWindow(const QString &winId); /** * 窗口标题 * @param winId * @return */ Q_INVOKABLE QString windowTitle(const QString &winId); /** * 窗口图标 * @param winId * @return */ Q_INVOKABLE QIcon windowIcon(const QString &winId); /** * 窗口action * @param winId * @return */ Q_INVOKABLE TaskManager::Actions windowActions(const QString &winId); /** * 窗口是否被激活 * @param winId * @return bool */ Q_INVOKABLE static bool windowIsActivated(const QString &winId); /** * 窗口执行指定动作 * @param Action::Type * @param winId */ Q_INVOKABLE static void execSpecifiedAction(const TaskManager::Action::Type &type, const QString &wid); void launch(const QModelIndex &index, const QQuickItem *item = nullptr); bool event(QEvent* ev) override; void requestDataChange(); bool disableMouseLeftButton() const; bool disableMouseRightButton() const; bool disableMouseHover() const; QStringList appWhiteList() const; QStringList appBlackList() const; bool enableDragToApp() const; void setEnableDragToApp(bool enable); Q_SIGNALS: void unReadMessagesNumberUpdate(const QString &desktopFile, uint num); void currentActiveWinIdChanged(); void disableMouseLeftButtonChanged(); void disableMouseRightButtonChanged(); void disableMouseHoverChanged(); void appWhiteListChanged(); void appBlackListChanged(); void enableDragToAppChanged(); public Q_SLOTS: /* * 这四个接口是对外的接口,用于添加/删除/检查/获取快速启动按钮 */ bool addQuickLauncher(const QString &desktopFile); bool checkQuickLauncher(const QString &desktopFile); bool removeQuickLauncher(const QString &desktopFile); QStringList quickLaunchers() const; static QString standardizePath(const QString &path); void closeWindow(const QVariant& wid); void minimizeWindow(const QVariant& wid); void maximizeWindow(const QVariant& wid); void restoreWindow(const QVariant& wid); void keepAbove(const QVariant& wid); void unsetKeepAbove(const QVariant& wid); private: explicit UkuiTaskManager(QObject *parent = nullptr); /** * 添加快捷按钮到指定位置(新增、交换位置) * @param desktopFile * @param order 图标在m_items对应的位置 */ void addQuickLauncher(const QString &desktopFile, int order); int quickLauncherCountBeforeRow(int row) const; void onAppUninstalled(const QStringList &desktopFiles); /** * 固定到任务栏/取消固定操作上传埋点数据 * @param applicationName 目标desktop文件 */ void addQuickLauncherEvent(const QString &applicationName, const QString &operate); void onFunctionControlChanged(const QString& name, bool exit = false); class Private; Private *d = nullptr; }; } #endif // UKUITASKMANAGER_H ukui-panel/widgets/ukui-task-manager/container.qrc0000664000175000017500000000031515167645100021242 0ustar fengfeng org.ukui.taskManagerContainer/WidgetContainer.qml org.ukui.taskManagerContainer/metadata.json ukui-panel/widgets/ukui-task-manager/ukui-task-manager.cpp0000664000175000017500000010750715167645111022617 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "ukui-task-manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "task-manager-item.h" #include "taskmanageradaptor.h" #include "utils.h" #include #include #include #include "actions.h" #include "config.h" #include "taskmanageradaptor.h" #include static const QString QUICK_LAUNCHERS_KEY("quickLaunchers"); static const QString NOTIFICATION_SERVICE = QStringLiteral("org.freedesktop.Notifications"); static const QString NOTIFICATION_PATH = QStringLiteral("/org/freedesktop/Notifications"); static const QString NOTIFICATION_INTERFACE = QStringLiteral("org.ukui.NotificationServer"); static const QStringList DEFAULT_QUICK_LAUNCHERS = {"peony", "firefox", "kylin-software-center", "kylin-screenshot", "ukui-control-center", }; /** * 1.0 QUICK_LAUNCHERS_KEY 值从desktop文件全路径改为desktop文件名列表(不包含后缀) */ static const QString CONFIG_VERSION = QStringLiteral("1.0"); namespace TaskManager { using WindowManager = UkuiQuick::WindowManager; bool compareListBySort(QStringList &list1, QStringList &list2) { if (list1.size() != list2.size()) return false; list1.sort(); list2.sort(); return list1 == list2; } QString appIdFromDesktopFile(const QString &desktopFile) { QFileInfo fileInfo(desktopFile); auto fileName = fileInfo.fileName(); if (fileName.endsWith(QStringLiteral(".desktop"))) { return fileName.left(fileName.length() - 8); } return {}; } class Q_DECL_HIDDEN UkuiTaskManager::Private { public: explicit Private(UkuiTaskManager *q = nullptr); ~Private(); void windowAdded(const QString &windowId); void windowRemoved(const QString &windowId); void skipTaskbarChanged(const QString& windowId); void activeWindowChanged(const QString& windowId); void loadSettings(); void addQuickLauncherItem(const QString &desktopFile); void save() const; void loadWindows(); void newItem(const QString &wid, const QString &desktopFile); void onNotificationServiceChanged(const QString &service, const QString &oldOwner, const QString &newOwner); void connectToNotificationServer(); QVector m_items; UkuiQuick::Config *m_config {nullptr}; QStringList m_quickLaunchersOrder; uint m_groupID = 0; //当窗口的group为空时使用 QTranslator *m_translator = nullptr; QDBusServiceWatcher *m_watcher = nullptr; bool m_connectedToNotificationServer = false; QString m_activeWindow; TaskManager::Actions m_windowActions; bool m_requestDataChange {false}; //管控配置 bool m_disableMouseLeftButton {false}; bool m_disableMouseRightButton {false}; bool m_disableMouseHover {false}; QStringList m_appWhiteList; QStringList m_appBlackList; // 控制是否允许拖拽到应用图标,激活应用窗口功能(default: true) bool m_enableDragToApp {true}; private: UkuiTaskManager *q = nullptr; }; UkuiTaskManager::Private::Private(UkuiTaskManager *q) : q(q) { } UkuiTaskManager::Private::~Private() { qDeleteAll(m_items); qDeleteAll(m_windowActions); } void UkuiTaskManager::Private::loadSettings() { if (!m_config) { m_config = UkuiQuick::ConfigLoader::getConfig("org.ukui.panel.taskManager"); } //版本升级处理 if (m_config->getValue(QStringLiteral("version")).toString() != CONFIG_VERSION) { auto oldVersion = m_config->getValue(QStringLiteral("version")).toString(); if (oldVersion.isEmpty() && m_config->contains(QUICK_LAUNCHERS_KEY)) { auto list = m_config->getValue(QUICK_LAUNCHERS_KEY).toStringList(); QStringList newList; QFileInfo info; for (const auto&desktop: list) { info.setFile(desktop); QString filName = info.fileName(); if (filName.endsWith(QStringLiteral(".desktop"))) { newList.append(filName.left(filName.length() - 8)); } } m_config->setValue(QUICK_LAUNCHERS_KEY, newList); } m_config->setValue(QStringLiteral("version"), CONFIG_VERSION); } QStringList quickLaunchers; if (m_config->contains(QUICK_LAUNCHERS_KEY)) { quickLaunchers = m_config->getValue(QUICK_LAUNCHERS_KEY).toStringList(); } else { quickLaunchers = DEFAULT_QUICK_LAUNCHERS; } for (auto id : quickLaunchers) { auto fullPath = Utils::desktopFilePathFromName(id); if (!fullPath.isEmpty()) { m_quickLaunchersOrder.append(id); addQuickLauncherItem(fullPath); } } if (quickLaunchers != m_quickLaunchersOrder) { m_config->setValue(QUICK_LAUNCHERS_KEY, m_quickLaunchersOrder); } } void UkuiTaskManager::Private::addQuickLauncherItem(const QString &desktopFile) { qDebug() << "Init quickLauncher button from desktop:" << desktopFile; auto item = new TaskManagerItem(desktopFile); connect(item, &TaskManagerItem::dataUpdated, q, [&, item](const QVector &roles){ QModelIndex changeIndex = q->index(m_items.indexOf(item), 0, QModelIndex()); q->dataChanged(changeIndex, changeIndex, roles); }); connect(q, &UkuiTaskManager::unReadMessagesNumberUpdate, item, &TaskManagerItem::updateUnreadMessagesNum); item->setHasLauncher(true); item->init(); q->beginInsertRows(QModelIndex(), m_items.size(), m_items.size()); m_items.append(item); q->endInsertRows(); } void UkuiTaskManager::Private::windowAdded(const QString &windowId) { //过滤不需要显示的窗口 if(WindowManager::skipTaskBar(windowId)) { return; } QString windowGroup = WindowManager::windowGroup(windowId); if (windowGroup.isEmpty()) { windowGroup = QString::number(++m_groupID); } QString desktopFile = Utils::desktopFileFromWid(windowId); for (auto item : m_items) { //避免重复添加 if(item->winIDs().contains(windowId)) { return; } //组已经存在,增加一个窗口(windowGroup就是appid) if (item->group() == windowGroup) { item->addWinID(windowId); return; } //desktop匹配,增加一个窗口 auto appid = appIdFromDesktopFile(desktopFile); if (!item->ID().isEmpty() && !appid.isEmpty() && item->ID() == appid) { item->addWinID(windowId); return; } } newItem(windowId, desktopFile); } void UkuiTaskManager::Private::windowRemoved(const QString &windowId) { for (int index = 0; index < m_items.size(); ++index) { auto item = m_items.at(index); if (item->winIDs().contains(windowId)) { item->removeWinID(windowId); if (item->winIDs().isEmpty() && !item->hasLauncher()) { q->beginRemoveRows(QModelIndex(), index, index); delete m_items.takeAt(index); q->endRemoveRows(); } break; } } } void UkuiTaskManager::Private::skipTaskbarChanged(const QString &windowId) { bool skipTaskBar = WindowManager::skipTaskBar(windowId); QString windowGroup = WindowManager::windowGroup(windowId); bool handled = false; for (int index = 0; index < m_items.size(); ++index) { auto item = m_items.at(index); if (item->winIDs().contains(windowId)) { if(skipTaskBar) { item->removeWinID(windowId); if (item->winIDs().isEmpty() && !item->hasLauncher()) { q->beginRemoveRows(QModelIndex(), index, index); delete m_items.takeAt(index); q->endRemoveRows(); } } handled = true; break; } else if(item->group() == windowGroup && !windowGroup.isEmpty() && !skipTaskBar) { item->addWinID(windowId); handled = true; break; } } if(!handled) { if(!skipTaskBar) { newItem(windowId, Utils::desktopFileFromWid(windowId)); } } } void UkuiTaskManager::Private::activeWindowChanged(const QString &windowId) { if(windowId == m_activeWindow) { return; } for(auto item : m_items) { if(item->currentDesktopWinIDs().contains(m_activeWindow)) { item->setHasActiveWindow(false); } if(item->currentDesktopWinIDs().contains(windowId)) { item->setHasActiveWindow(true); } } m_activeWindow = windowId; Q_EMIT q->currentActiveWinIdChanged(); } void UkuiTaskManager::Private::loadWindows() { for (const QString &winID: WindowManager::windows()) { windowAdded(winID); } } void UkuiTaskManager::Private::newItem(const QString &wid, const QString &desktopFile) { auto appid = appIdFromDesktopFile(desktopFile); //查看是否存在快速启动按钮 if (m_quickLaunchersOrder.contains(appid)) { m_items.at(q->indexOf(appid).row())->addWinID(wid); return; } //新增一个item auto newItem = new TaskManagerItem(QStringList{wid}); newItem->setID(appid); newItem->setDesktopFile(desktopFile); newItem->init(); connect(q, &UkuiTaskManager::unReadMessagesNumberUpdate, newItem, &TaskManagerItem::updateUnreadMessagesNum); QObject::connect(newItem, &TaskManagerItem::dataUpdated, q, [&, newItem](const QVector &roles){ QModelIndex changeIndex = q->index(m_items.indexOf(newItem), 0, QModelIndex()); q->dataChanged(changeIndex, changeIndex, roles); }); q->beginInsertRows(QModelIndex(), m_items.size(), m_items.size()); m_items.append(newItem); q->endInsertRows(); } void UkuiTaskManager::Private::save() const { m_config->setValue(QUICK_LAUNCHERS_KEY, m_quickLaunchersOrder); m_config->forceSync(); } void UkuiTaskManager::Private::onNotificationServiceChanged(const QString &service, const QString &oldOwner, const QString &newOwner) { if(!oldOwner.isEmpty()) { QDBusConnection::sessionBus().disconnect(NOTIFICATION_SERVICE, NOTIFICATION_PATH, NOTIFICATION_INTERFACE, QStringLiteral("UnreadMessagesNumberUpdated"), q, SLOT(unReadMessagesNumberUpdate)); m_connectedToNotificationServer = false; if(!newOwner.isEmpty()) { connectToNotificationServer(); } } else if(!newOwner.isEmpty()) { if(!m_connectedToNotificationServer) { return; } connectToNotificationServer(); } } void UkuiTaskManager::Private::connectToNotificationServer() { m_connectedToNotificationServer = QDBusConnection::sessionBus().connect(NOTIFICATION_SERVICE, NOTIFICATION_PATH, NOTIFICATION_INTERFACE, QStringLiteral("UnreadMessagesNumberUpdated"), q, SLOT(unReadMessagesNumberUpdate(const QString &, uint))); } QModelIndex UkuiTaskManager::indexOf(const QString &appId) { for(int row = 0; row < d->m_items.size(); ++row) { if(d->m_items.at(row)->ID() == appId) { return index(row, 0, {}); } } return {}; } QString UkuiTaskManager::currentActiveWinId() const { return d->m_activeWindow; } UkuiTaskManager::UkuiTaskManager(QObject *parent) : QAbstractListModel(parent), d(new Private(this)) { d->m_translator = new QTranslator(this); if (!d->m_translator->load(QString(TRANSLATION_FILE_DIR) + "/libukui-task-manager_" + QLocale::system().name() + ".qm")) { qWarning() << "Load translations file" << QLocale::system().name() << "failed!";; } qApp->installTranslator(d->m_translator); //加载配置文件,初始化快速启动按钮 d->loadSettings(); //加载当前打开的窗口 d->loadWindows(); connect(Utils::getApplicationInfo(), &UkuiSearch::ApplicationInfo::appDBItems2BDelete, this, &UkuiTaskManager::onAppUninstalled); connect(WindowManager::self(), &WindowManager::windowAdded, this, [&](const QString &winId) { d->windowAdded(winId); }); connect(WindowManager::self(), &WindowManager::windowRemoved, this, [&](const QString &winId) { d->windowRemoved(winId); }); connect(WindowManager::self(), &WindowManager::skipTaskbarChanged, this, [&](const QString &winId) { d->skipTaskbarChanged(winId); }); connect(WindowManager::self(), &WindowManager::activeWindowChanged, this, [&](const QString &winId){ d->activeWindowChanged(winId); }); //为了避免UI阻塞 bug#464235 QTimer::singleShot(0, [this](){ d->m_activeWindow = WindowManager::currentActiveWindow(); Q_EMIT currentActiveWinIdChanged(); }); auto conn = QDBusConnection::sessionBus(); d->m_watcher = new QDBusServiceWatcher(QStringLiteral("org.freedesktop.Notifications"), conn, QDBusServiceWatcher::WatchForOwnerChange, this); connect(d->m_watcher, &QDBusServiceWatcher::serviceOwnerChanged,this,[&](const QString &service, const QString &oldOwner, const QString &newOwner){ d->onNotificationServiceChanged(service, oldOwner, newOwner); }); d->connectToNotificationServer(); new TaskManagerAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/taskManager"), this); dbus.registerService(QStringLiteral("org.ukui.taskManager")); UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-taskManager-v11")); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [&](const QString &name) { onFunctionControlChanged(name); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [&]() { onFunctionControlChanged(QStringLiteral("ukui-panel-taskManager-v11"), true); }); onFunctionControlChanged(QStringLiteral("ukui-panel-taskManager-v11")); } UkuiTaskManager::~UkuiTaskManager() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-taskManager-v11")); if (d) { delete d; d = nullptr; } } QHash UkuiTaskManager::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles")); for (int i = 0; i < e.keyCount(); ++i) { roles.insert(e.value(i), e.key(i)); } return roles; } QVariant UkuiTaskManager::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= d->m_items.count()) { return {}; } TaskManagerItem *item = d->m_items.at(index.row()); if (!item) { return {}; } switch (role) { case Qt::DisplayRole: return item->name(); case Icon: { if (item->icon().isNull()) { return "application-x-desktop"; } return item->icon(); } case IconName: return item->iconName(); case Id: return item->ID(); case DesktopFile: return item->desktopFile(); case Name: return item->name(); case GenericName: return item->genericName(); case WinIdList: return item->winIDs(); case CurrentDesktopWinIdList: return item->currentDesktopWinIDs(); case WindowGeometries: return QVariant::fromValue(item->WindowGeometries()); case WindowTitles: return QVariant::fromValue(item->windowTitles()); case WindowIcons: return QVariant::fromValue(item->windowIcons()); case WindowIconsName: return QVariant::fromValue(item->windowIconsName()); case DemandsAttentionWinIdList: return item->demandsAttentionWinIDs(); case ApplicationMenuServiceName: case ApplicationMenuObjectPath: return QString(); case HasLauncher: return item->hasLauncher(); case Actions: { auto actions = item->actions(); for(auto action : actions) { if(action->type() == Action::Type::AddQuickLauncher) { action->setParam(index.row()); break; } } return QVariant::fromValue(actions); } case UnreadMessagesNum: return item->unReadMessagesNum(); case HasActiveWindow: return item->hasActiveWindow(); case QuickWidgetId: return item->quickWidget(); default: return {}; } Q_UNREACHABLE(); } QModelIndex UkuiTaskManager::index(int row, int column, const QModelIndex &parent) const { if (row < 0 || column != 0) { return {}; } return createIndex(row, column, nullptr); } int UkuiTaskManager::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : d->m_items.count(); } bool UkuiTaskManager::addQuickLauncher(const QString &desktopFile) { //支持传入全路径,appId后带desktop后缀的appId QString fullpath = standardizePath(desktopFile); if (fullpath.isEmpty()) { return false; } const auto appId = appIdFromDesktopFile(fullpath); if (appId.isEmpty() || d->m_quickLaunchersOrder.contains(appId)) { return false; } QModelIndex index = indexOf(fullpath); if (index.isValid()) { addQuickLauncher(fullpath, index.row()); } else { addQuickLauncher(fullpath, d->m_items.size()); } return true; } bool UkuiTaskManager::checkQuickLauncher(const QString &desktopFile) { if (std::any_of(d->m_quickLaunchersOrder.begin(), d->m_quickLaunchersOrder.end(), [&](const QString& id) { if (desktopFile.endsWith("/" + id + ".desktop")) { return true; } return false; })) { return true; } return false; } bool UkuiTaskManager::removeQuickLauncher(const QString &desktopFile) { QString appId; if (desktopFile.endsWith(QStringLiteral("desktop"))) { appId = appIdFromDesktopFile(desktopFile); } else { appId = desktopFile; } if (appId.isEmpty()) { return false; } if (d->m_quickLaunchersOrder.contains(appId)) { int modelIndex = indexOf(appId).row(); auto targetItem = d->m_items.at(modelIndex); int oldOrder = d->m_quickLaunchersOrder.indexOf(appId); //取消固定 targetItem->setHasLauncher(false); //上传埋点数据 addQuickLauncherEvent(appId, "unpin from taskbar"); if (targetItem->winIDs().isEmpty()) { beginRemoveRows(QModelIndex(), modelIndex, modelIndex); delete d->m_items.takeAt(modelIndex); endRemoveRows(); } d->m_quickLaunchersOrder.removeAt(oldOrder); d->save(); } else { return false; } return true; } QStringList UkuiTaskManager::quickLaunchers() const { return d->m_quickLaunchersOrder; } QString UkuiTaskManager::standardizePath(const QString &path) { QString fullpath = path; if (!QFile::exists(path)) { if (path.endsWith(QStringLiteral("desktop"))) { fullpath = Utils::desktopFilePathFromName(path.left(path.length() - 8)); } else { fullpath = Utils::desktopFilePathFromName(path); } if (!QFile::exists(fullpath)) { return {}; } } else if (!path.endsWith(QStringLiteral("desktop"))) { return {}; } return fullpath; } void UkuiTaskManager::addQuickLauncher(const QString &desktopFile, int order) { if(order < 0 || !QFile::exists(desktopFile)) { return; } auto appId = appIdFromDesktopFile(desktopFile); // 1. 任务栏已存在图标 // 1.1 改变HasLauncher属性,并同步配置文件 for (int i = 0; i < d->m_items.size(); ++i) { if (d->m_items.at(i)->ID() == appId) { if (!d->m_items.at(i)->hasLauncher()) { d->m_items.at(i)->setHasLauncher(true); auto launcherOrder = qMin(quickLauncherCountBeforeRow(i), d->m_quickLaunchersOrder.size()); d->m_quickLaunchersOrder.insert(launcherOrder, appId); d->save(); } // 1.2 移动到指定位置 setOrder(indexOf(appId), order); addQuickLauncherEvent(appId, "pin to taskbar"); return; } } // 2. 任务栏不存在图标 // 2.1. 新增图标 auto item = new TaskManagerItem(desktopFile); item->setHasLauncher(true); connect(this, &UkuiTaskManager::unReadMessagesNumberUpdate, item, &TaskManagerItem::updateUnreadMessagesNum); QObject::connect(item, &TaskManagerItem::dataUpdated, this, [&, item](const QVector&roles) { QModelIndex changeIndex = index(d->m_items.indexOf(item), 0, QModelIndex()); Q_EMIT dataChanged(changeIndex, changeIndex, roles); }); item->init(); order = qMin(order, d->m_items.size()); beginInsertRows(QModelIndex(), order, order); d->m_items.insert(order, item); endInsertRows(); // 2.2 记录快捷启动按钮顺序,并同步配置文件 auto launcherOrder = quickLauncherCountBeforeRow(order); launcherOrder = qMin(launcherOrder, d->m_quickLaunchersOrder.size()); d->m_quickLaunchersOrder.insert(launcherOrder, appId); d->save(); // 2.3 上传埋点数据 addQuickLauncherEvent(appId, "pin to taskbar"); } void UkuiTaskManager::setOrder(const QModelIndex &index, int order) { int oldOrder = index.row(); order = qMin(order, d->m_items.size() -1); if(order == oldOrder || !index.isValid() || oldOrder >= d->m_items.size()) { return; } auto item = d->m_items.at(oldOrder); if(item->hasLauncher()) { int launcherOrder = d->m_quickLaunchersOrder.indexOf(item->ID()); if(oldOrder < order) { for(int row = oldOrder + 1; row <= order; ++row) { if(d->m_items.at(row)->hasLauncher()) { ++launcherOrder; } } } else { for(int row = oldOrder - 1; row >= order; --row) { if(d->m_items.at(row)->hasLauncher()) { --launcherOrder; } } if (launcherOrder < 0) { launcherOrder = 0; } } launcherOrder = qMin(d->m_quickLaunchersOrder.size() - 1, launcherOrder); d->m_quickLaunchersOrder.move(d->m_quickLaunchersOrder.indexOf(item->ID()), launcherOrder); d->save(); } if (oldOrder < order) { beginMoveRows(index.parent(), oldOrder, oldOrder, index.parent(), order + 1); } else { beginMoveRows(index.parent(), oldOrder, oldOrder, index.parent(), order); } d->m_items.insert(order, d->m_items.takeAt(oldOrder)); endMoveRows(); } void UkuiTaskManager::activateWindowView(const QStringList &winIds) { WindowManager::self()->activateWindowView(winIds); } void UkuiTaskManager::activateWindow(const QString &winId) { WindowManager::activateWindow(winId); } QString UkuiTaskManager::windowTitle(const QString &winId) { return WindowManager::windowTitle(winId); } QIcon UkuiTaskManager::windowIcon(const QString &winId) { return WindowManager::windowIcon(winId); } UkuiTaskManager &UkuiTaskManager::self() { static UkuiTaskManager s_self; return s_self; } TaskManager::Actions UkuiTaskManager::windowActions(const QString &winId) { if(d->m_windowActions.isEmpty()) { //关闭 auto action = new Action("Close", tr("Close"), QIcon::fromTheme("window-close-symbolic"), Action::Type::Close, winId); connect(action, &Action::actionTriggered, this, &UkuiTaskManager::closeWindow); d->m_windowActions.append(action); //还原 action = new Action("Restore", tr("Restore"), QIcon::fromTheme("window-restore-symbolic"), Action::Type::Restore, winId); connect(action, &Action::actionTriggered, this, &UkuiTaskManager::restoreWindow); d->m_windowActions.append(action); //最大化 action = new Action("Maximize", tr("Maximize"), QIcon::fromTheme("window-maximize-symbolic"), Action::Type::Maximize, winId); connect(action, &Action::actionTriggered, this, &UkuiTaskManager::maximizeWindow); d->m_windowActions.append(action); //最小化 action = new Action("Minimize", tr("Minimize"), QIcon::fromTheme("window-minimize-symbolic"), Action::Type::Minimize, winId); connect(action, &Action::actionTriggered, this, &UkuiTaskManager::minimizeWindow); d->m_windowActions.append(action); //置顶 action = new Action("Keep above", tr("Keep above"), QIcon::fromTheme("ukui-fixed-symbolic"), Action::Type::KeepAbove, winId); connect(action, &Action::actionTriggered, this, &UkuiTaskManager::keepAbove); d->m_windowActions.append(action); //取消置顶 action = new Action("Unset keep above", tr("Unset keep above"), QIcon::fromTheme("ukui-unfixed-symbolic"), Action::Type::UnsetKeepAbove, winId); connect(action, &Action::actionTriggered, this, &UkuiTaskManager::unsetKeepAbove); d->m_windowActions.append(action); } for (auto action : d->m_windowActions) { if (action->param() != winId) { action->setParam(winId); } switch (action->type()) { case Action::Close: break; case Action::Minimize: action->setEnabled(WindowManager::isMinimizable(winId) && !WindowManager::isMinimized(winId)); break; case Action::Maximize: action->setEnabled(WindowManager::isMaximizable(winId) && (!WindowManager::isMaximized(winId) || WindowManager::isMinimized(winId))); break; case Action::Restore: action->setEnabled(WindowManager::isMaximized(winId) || WindowManager::isMinimized(winId)); break; case Action::KeepAbove: action->setEnabled(!WindowManager::isKeepAbove(winId)); break; case Action::UnsetKeepAbove: action->setEnabled(WindowManager::isKeepAbove(winId)); break; default: break; } } return d->m_windowActions; } bool UkuiTaskManager::windowIsActivated(const QString &winId) { return winId == WindowManager::currentActiveWindow(); } void UkuiTaskManager::execSpecifiedAction(const TaskManager::Action::Type &type, const QString &wid) { switch (type) { case Action::Close: WindowManager::closeWindow(wid); break; case Action::Minimize: WindowManager::minimizeWindow(wid); break; case Action::Maximize: WindowManager::maximizeWindow(wid); break; case Action::Restore: WindowManager::restoreWindow(wid); break; case Action::KeepAbove: case Action::UnsetKeepAbove: WindowManager::keepAboveWindow(wid); break; default: break; } } void UkuiTaskManager::launch(const QModelIndex& index, const QQuickItem* item) { if (!index.isValid() || index.row() >= d->m_items.count()) { return; } d->m_items.at(index.row())->launch(item); } void UkuiTaskManager::closeWindow(const QVariant &wid) { WindowManager::closeWindow(wid.toString()); } void UkuiTaskManager::minimizeWindow(const QVariant &wid) { WindowManager::minimizeWindow(wid.toString()); } void UkuiTaskManager::maximizeWindow(const QVariant &wid) { if (!WindowManager::isMaximized(wid.toString())) { WindowManager::maximizeWindow(wid.toString()); } WindowManager::activateWindow(wid.toString()); } void UkuiTaskManager::restoreWindow(const QVariant &wid) { WindowManager::restoreWindow(wid.toString()); WindowManager::activateWindow(wid.toString()); } void UkuiTaskManager::keepAbove(const QVariant &wid) { WindowManager::keepAboveWindow(wid.toString()); } void UkuiTaskManager::unsetKeepAbove(const QVariant &wid) { WindowManager::keepAboveWindow(wid.toString()); } int UkuiTaskManager::quickLauncherCountBeforeRow(int row) const { int launcherCount = 0; row = qMin(row, d->m_items.size()); for(int i = 0; i < row; ++i) { if(d->m_items.at(i)->hasLauncher()) { launcherCount++; } } return launcherCount; } void UkuiTaskManager::setQuickLauncher(const QString &desktopFile, int order) { if(order >= d->m_items.size()) { order = d->m_items.size(); } addQuickLauncher(desktopFile, order); } void UkuiTaskManager::onAppUninstalled(const QStringList &desktopFiles) { for(const QString &desktopFile : desktopFiles) { removeQuickLauncher(desktopFile); } } void UkuiTaskManager::addQuickLauncherEvent(const QString &applicationName, const QString &operate ) { KCustomProperty *property = new KCustomProperty[2]; property[0].key = strdup(QStringLiteral("AppliciationName").toLocal8Bit().data()); property[0].value = strdup(applicationName.toLocal8Bit().data()); property[1].key = strdup(QStringLiteral("EventType").toLocal8Bit().data()); property[1].value = strdup(operate.toLocal8Bit().data()); KTrackData *node = kdk_dia_data_init(KEVENTSOURCE_DESKTOP, KEVENT_CLICK); kdk_dia_append_custom_property(node, property, 2); kdk_dia_upload_default(node, strdup(QStringLiteral("pin_to_taskbar_event").toLocal8Bit().data()),strdup(QStringLiteral("ukui-panel").toLocal8Bit().data())); kdk_dia_data_free(node); free(property[0].key); free(property[0].value); free(property[1].key); free(property[1].value); delete []property; } void UkuiTaskManager::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-taskManager-v11")) { return; } //管控中有值时,设置为管控值,否则设置为配置文件中的值 auto config = exit? QJsonObject() : UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "TaskManager" << "function control config:" << config; //应用白名单 if (config.contains(QStringLiteral("appWhiteList"))) { QStringList appWhiteList; for (QVariant &app : config.value(QStringLiteral("appWhiteList")).toArray().toVariantList()) { auto id = app.toString(); if (id.endsWith(".desktop")) { id = id.left(id.size() - 8); } appWhiteList.append(id); } if (!compareListBySort(d->m_appWhiteList, appWhiteList)) { d->m_appWhiteList = appWhiteList; Q_EMIT appWhiteListChanged(); } } else if (!d->m_appWhiteList.isEmpty()) { d->m_appWhiteList.clear(); Q_EMIT appWhiteListChanged(); } //应用黑名单 if (config.contains(QStringLiteral("appBlackList"))) { QStringList appBlackList; for (QVariant &app : config.value(QStringLiteral("appBlackList")).toArray().toVariantList()) { auto id = app.toString(); if (id.endsWith(".desktop")) { id = id.left(id.size() - 8); } appBlackList.append(id); } if (!compareListBySort(d->m_appBlackList, appBlackList)) { d->m_appBlackList= appBlackList; Q_EMIT appBlackListChanged(); } } else if (!d->m_appBlackList.isEmpty()) { d->m_appBlackList.clear(); Q_EMIT appBlackListChanged(); } //是否禁用左键点击(任务栏整体禁用) if (config.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = config.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != d->m_disableMouseLeftButton) { d->m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { d->m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } //是否禁用右键点击(任务栏整体禁用) if (config.contains(QStringLiteral("disableMouseRightButton"))) { bool disable = config.value(QStringLiteral("disableMouseRightButton")).toBool(); if (disable != d->m_disableMouseRightButton) { d->m_disableMouseRightButton = disable; Q_EMIT disableMouseRightButtonChanged(); } } else { d->m_disableMouseRightButton = false; Q_EMIT disableMouseRightButtonChanged(); } //是否禁用任务栏鼠标悬浮效果(任务栏整体) if (config.contains(QStringLiteral("disableMouseHover"))) { bool disable = config.value(QStringLiteral("disableMouseHover")).toBool(); if (disable != d->m_disableMouseHover) { d->m_disableMouseHover = disable; Q_EMIT disableMouseHoverChanged(); } } else { d->m_disableMouseHover = false; Q_EMIT disableMouseHoverChanged(); } } bool UkuiTaskManager::event(QEvent *event) { if (event->type() == QEvent::UpdateRequest) { for(auto item : d->m_items) { item->updateIconStatus(); } d->m_requestDataChange = false; } return QObject::event(event); } void UkuiTaskManager::requestDataChange() { if (!d->m_requestDataChange) { d->m_requestDataChange = true; auto ev = new QEvent(QEvent::UpdateRequest); QCoreApplication::postEvent(this, ev); } } bool UkuiTaskManager::disableMouseLeftButton() const { return d->m_disableMouseLeftButton; } bool UkuiTaskManager::disableMouseRightButton() const { return d->m_disableMouseRightButton; } bool UkuiTaskManager::disableMouseHover() const { return d->m_disableMouseHover; } QStringList UkuiTaskManager::appWhiteList() const { return d->m_appWhiteList; } QStringList UkuiTaskManager::appBlackList() const { return d->m_appBlackList; } bool UkuiTaskManager::enableDragToApp() const { return d->m_enableDragToApp; } void UkuiTaskManager::setEnableDragToApp(bool enable) { if (enable != d->m_enableDragToApp) { d->m_enableDragToApp = enable; Q_EMIT enableDragToAppChanged(); } } } #include "moc_ukui-task-manager.cpp" ukui-panel/widgets/ukui-task-manager/task-manager-item.h0000664000175000017500000000667515167645100022247 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_TASK_MANAGER_TASK_MANAGER_ITEM_H #define UKUI_TASK_MANAGER_TASK_MANAGER_ITEM_H #include #include #include #include "actions.h" class QQuickItem; namespace TaskManager { class TaskManagerItemPrivate; class TaskManagerItem : public QObject { Q_OBJECT public: explicit TaskManagerItem(QObject *parent = nullptr); explicit TaskManagerItem(const QString &desktoFile, QObject *parent = nullptr); explicit TaskManagerItem(const QStringList &winIDs, QObject *parent = nullptr); ~TaskManagerItem(); const QString &ID() const; void setID(const QString &appID); const QString &desktopFile() const; void setDesktopFile(const QString &desktopFile); const QString &name() const; const QString &genericName() const; const QString &iconName() const; const QIcon &icon() const; const QStringList &winIDs() const; const QStringList ¤tDesktopWinIDs(); const QMap &WindowGeometries() const; const QMap &windowTitles() const; const QMap &windowIcons() const; const QMap &windowIconsName() const; void addWinID(const QString &winId); void removeWinID(const QString &winID); void iconChanged(const QString& windowId); void titleChanged(const QString& windowId); void desktopChanged(const QString& windowId); void demandsAttentionChanged(const QString& windowId); void geometryChanged(const QString& windowId); void setHasActiveWindow(bool has); bool hasActiveWindow(); const QString &group() const; void setGroup(const QString &group); bool hasLauncher() const; void setHasLauncher(bool hasLauncher); Actions actions() const; QStringList demandsAttentionWinIDs() const; const QString &display() const; QString quickWidget() const; uint unReadMessagesNum(); void init(); void updateIconStatus(); public Q_SLOTS: void updateUnreadMessagesNum(const QString &desktopFile, uint num); void newInstanceActionActive(const QVariant& param); void launch(const QQuickItem *item = nullptr); private Q_SLOTS: void refreshWinIdsOnCurrentDesktop(); void refreshWinIdsOnScreens(); void refreshWindowTitlesAndIcons(); void desktopActionActive(const QString &name); void removeQuickLauncherActionActive(); void addQuickLauncherActionActive(int index); void exitActionActive(const QStringList &winIds); void onWidgetInfoUpdate(const QString &appid, const QString &widgetId); Q_SIGNALS: void dataUpdated(QVector roles); private: TaskManagerItemPrivate *d = nullptr; }; } #endif //UKUI_TASK_MANAGER_TASK_MANAGER_ITEM_H ukui-panel/widgets/ukui-task-manager/task-manager-filter-model.h0000664000175000017500000000620115167645111023657 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_TASK_MANAGER_FILTER_MODEL_H #define UKUI_PANEL_TASK_MANAGER_FILTER_MODEL_H #include #include #include #include #include #include "actions.h" #include "ukui-task-manager.h" #include "config-loader.h" namespace TaskManager { class TaskManagerFilterModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(QScreen *screen READ screen WRITE setScreen) public: explicit TaskManagerFilterModel(QObject *parent = nullptr); Q_INVOKABLE void setSourceModel(QAbstractItemModel *sourceModel) override; QVariant data(const QModelIndex &index, int role) const override; Q_INVOKABLE void setOrder(const QModelIndex &index, int order); /** * 右键菜单 * @param showDisabledActions * @param actions */ Q_INVOKABLE bool openMenu(const bool &showDisabledActions, const TaskManager::Actions &actions, QQuickItem *item); /** * 添加快捷按钮到指定位置(先添加快捷按钮,再换位) * @param desktopFile * @param order */ Q_INVOKABLE void addQuickLauncher(const QString &desktopFile, int order); Q_INVOKABLE void launch(const QModelIndex &index, QQuickItem *item = nullptr); QScreen *screen() const; void setScreen(QScreen *screen); /** * 多屏时,任务栏图标显示在哪个任务栏 枚举值 * 0-所有屏幕,1-主屏和打开了窗口的任务栏 2-只显示在打开了窗口的任务栏 */ enum TaskBarIconsShowedOn { AllPanels = 0, PrimaryScreenPanelAndPanelWhereWindowIsOpen, PanelWhereWindowIsOpen }; Q_ENUM(TaskBarIconsShowedOn) protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: QStringList currentWinIdList(const QModelIndex &index) const; void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); bool onCurrentScreen(const QModelIndex &index) const; bool windowOnCurrentScreen(const QRect &rect) const; UkuiTaskManager *m_sourceModel = nullptr; QScreen *m_screen = nullptr; QPointer m_contextMenu; //任务栏图标显示在哪个任务栏 TaskBarIconsShowedOn m_iconsShowedonScreen; UkuiQuick::Config *m_config {nullptr}; Q_SIGNALS: void menuAboutToHide(); }; } #endif //UKUI_PANEL_TASK_MANAGER_FILTER_MODEL_H ukui-panel/widgets/ukui-task-manager/task-manager-item.cpp0000664000175000017500000004724615167645100022601 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "task-manager-item.h" #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #include #else #include #include #endif #include #include #include #include #include #include #include #include #include "window-manager.h" #include "ukui-task-manager.h" #include "utils.h" #include "widget-delegate.h" using namespace TaskManager; using namespace UkuiQuick; class TaskManager::TaskManagerItemPrivate { public: ~TaskManagerItemPrivate(); QString m_ID; QString m_desktopFile; QString m_name; QString m_genericName; QString m_iconName; QIcon m_icon; QStringList m_winIDs; QStringList m_winIDsOnCurrentDesktop; QString m_groupLeader; QString m_group; bool m_hasLauncher = false; QString m_display; Actions m_actions; XdgDesktopFile m_xdf; uint m_unreadMessagesNum = 0; QStringList m_demandsAttentionWinIDs; QMap m_widToGeometry; QMap m_widToTitle; QMap m_widToIcon; QMap m_widToIconName; bool m_hasActiveWindow = false; QString m_quickWidget; }; TaskManagerItemPrivate::~TaskManagerItemPrivate() { qDeleteAll(m_actions); } TaskManagerItem::TaskManagerItem(QObject *parent) : QObject(parent), d(new TaskManagerItemPrivate) { } TaskManagerItem::TaskManagerItem(const QString &desktoFile, QObject *parent): QObject(parent), d(new TaskManagerItemPrivate) { d->m_desktopFile = desktoFile; QFileInfo info(d->m_desktopFile); auto fileName = info.fileName(); if (fileName.endsWith(QStringLiteral(".desktop"))) { d->m_ID = fileName.left(fileName.size() - 8); } d->m_xdf.load(d->m_desktopFile); } TaskManagerItem::TaskManagerItem(const QStringList &winIDs, QObject *parent) : QObject(parent), d(new TaskManagerItemPrivate) { d->m_winIDs = winIDs; } TaskManagerItem::~TaskManagerItem() { if(d) { delete d; d = nullptr; } } const QString &TaskManagerItem::ID() const { return d->m_ID; } void TaskManagerItem::setID(const QString &appID) { d->m_ID = appID; } const QString& TaskManagerItem::desktopFile() const { return d->m_desktopFile; } void TaskManagerItem::setDesktopFile(const QString&desktopFile) { d->m_desktopFile = desktopFile; d->m_xdf.load(desktopFile); } bool TaskManagerItem::hasLauncher() const { return d->m_hasLauncher; } void TaskManagerItem::setHasLauncher(bool hasLauncher) { if(d->m_hasLauncher && hasLauncher) { return; } if(!hasLauncher && d->m_hasLauncher) { for(Action *action : d->m_actions) { if(action->type() == Action::Type::RemoveQuickLauncher) { action->setEnabled(false); } if(action->type() == Action::Type::AddQuickLauncher) { action->setEnabled(true); } } } else if(hasLauncher && !d->m_hasLauncher) { for(Action *action : d->m_actions) { if(action->type() == Action::Type::RemoveQuickLauncher) { action->setEnabled(true); } if(action->type() == Action::Type::AddQuickLauncher) { action->setEnabled(false); } } } d->m_hasLauncher = hasLauncher; Q_EMIT dataUpdated(QVector{UkuiTaskManager::HasLauncher, UkuiTaskManager::Actions}); } const QString &TaskManagerItem::display() const { return d->m_display; } QString TaskManagerItem::quickWidget() const { return d->m_quickWidget; } const QString &TaskManagerItem::name() const { return d->m_name; } const QIcon &TaskManagerItem::icon() const { return d->m_icon; } const QString &TaskManagerItem::genericName() const { return d->m_genericName; } const QString &TaskManagerItem::iconName() const { return d->m_iconName; } const QStringList &TaskManagerItem::winIDs() const { return d->m_winIDs; } void TaskManagerItem::addWinID(const QString &winId) { if(d->m_winIDs.contains(winId)) { return; } d->m_winIDs.append(winId); Q_EMIT dataUpdated(QVector{UkuiTaskManager::WinIdList}); if(WindowManager::isOnCurrentDesktop(winId) || WindowManager::isOnAllDesktops(winId)) { d->m_winIDsOnCurrentDesktop.append(winId); Q_EMIT dataUpdated(QVector{UkuiTaskManager::CurrentDesktopWinIdList, UkuiTaskManager::CurrentWinIdList}); } geometryChanged(winId); QString title = WindowManager::windowTitle(winId); if(title.isEmpty()) { title = d->m_name; } d->m_widToTitle.insert(winId, title); QIcon icon = WindowManager::windowIcon(winId); if(icon.isNull()) { icon = d->m_icon; } d->m_widToIcon.insert(winId, icon.isNull() ? QVariant("application-x-desktop") : icon); d->m_widToIconName.insert(winId, icon.name()); Q_EMIT dataUpdated(QVector{UkuiTaskManager::WindowTitles, UkuiTaskManager::WindowIcons, UkuiTaskManager::WindowIconsName}); } void TaskManagerItem::removeWinID(const QString &winID) { bool updateIconName = d->m_winIDs.isEmpty()? false : d->m_winIDs.first() == winID; if(!d->m_winIDs.isEmpty()) { d->m_winIDs.removeAll(winID); d->m_widToTitle.remove(winID); d->m_widToIcon.remove(winID); d->m_widToIconName.remove(winID); Q_EMIT dataUpdated(QVector{UkuiTaskManager::WinIdList, UkuiTaskManager::WindowTitles, UkuiTaskManager::WindowIcons, UkuiTaskManager::WindowIconsName}); if(!hasLauncher() && d->m_xdf.name().isEmpty() && !d->m_winIDs.isEmpty() && updateIconName) { d->m_name = WindowManager::windowTitle(d->m_winIDs.first()); d->m_icon = WindowManager::windowIcon(d->m_winIDs.first()); Q_EMIT dataUpdated(QVector{UkuiTaskManager::Name, UkuiTaskManager::Icon}); } } if(d->m_winIDsOnCurrentDesktop.removeAll(winID)) { Q_EMIT dataUpdated(QVector{UkuiTaskManager::CurrentDesktopWinIdList, UkuiTaskManager::CurrentWinIdList}); } if(d->m_widToGeometry.remove(winID)) { Q_EMIT dataUpdated(QVector{UkuiTaskManager::WindowGeometries, UkuiTaskManager::CurrentWinIdList}); } if(d->m_demandsAttentionWinIDs.removeAll(winID)) { Q_EMIT dataUpdated(QVector{UkuiTaskManager::DemandsAttentionWinIdList}); } } void TaskManagerItem::setHasActiveWindow(bool has) { if(d->m_hasActiveWindow != has) { d->m_hasActiveWindow = has; Q_EMIT dataUpdated(QVector{UkuiTaskManager::HasActiveWindow}); } } bool TaskManagerItem::hasActiveWindow() { return d->m_hasActiveWindow; } const QString &TaskManagerItem::group() const { return d->m_group; } void TaskManagerItem::setGroup(const QString &group) { d->m_group = group; } void TaskManagerItem::init() { connect(WindowManager::self(), &WindowManager::currentDesktopChanged, this, &TaskManagerItem::refreshWinIdsOnCurrentDesktop); connect(WindowManager::self(), &WindowManager::onAllDesktopsChanged, this, &TaskManagerItem::desktopChanged); connect(WindowManager::self(), &WindowManager::windowDesktopChanged, this, &TaskManagerItem::desktopChanged); connect(WindowManager::self(), &WindowManager::titleChanged, this, &TaskManagerItem::titleChanged); connect(WindowManager::self(), &WindowManager::iconChanged, this, &TaskManagerItem::iconChanged); connect(WindowManager::self(), &WindowManager::demandsAttentionChanged, this, &TaskManagerItem::demandsAttentionChanged); connect(WindowManager::self(), &WindowManager::geometryChanged, this, &TaskManagerItem::geometryChanged); connect(WidgetInfo::self(), &WidgetInfo::widgetInfoUpdate, this, &TaskManagerItem::onWidgetInfoUpdate); d->m_quickWidget = WidgetInfo::self()->widgetFor(d->m_ID); d->m_name = d->m_xdf.localizedValue("Name").toString(); d->m_iconName = d->m_xdf.iconName(); if(d->m_iconName.startsWith("/")) { if(QFile::exists(d->m_iconName)) { d->m_icon = QIcon(d->m_iconName); } } else { d->m_icon = QIcon::fromTheme(d->m_iconName); if (d->m_icon.isNull()) { d->m_icon = XdgIcon::fromTheme(d->m_iconName); } } if(!winIDs().isEmpty()) { //TODO: 获取groupLeader窗口的图标? if (winIDs().contains(WindowManager::currentActiveWindow())) { this->setHasActiveWindow(true); } if(d->m_icon.isNull()) { d->m_icon = WindowManager::windowIcon(winIDs().at(0)); } if(d->m_name.isEmpty()) { d->m_name = WindowManager::windowTitle(winIDs().at(0)); } d->m_group = WindowManager::windowGroup(winIDs().at(0)); refreshWinIdsOnCurrentDesktop(); refreshWinIdsOnScreens(); refreshWindowTitlesAndIcons(); } //添加Action //desktop中的action for(const QString &action : d->m_xdf.actions()) { auto a = new Action(action, d->m_xdf.actionName(action), d->m_xdf.actionIcon(action), Action::Type::DesktopAction, action); connect(a, &Action::actionTriggered, this, [&](const QVariant& param){ desktopActionActive(param.toString()); }); d->m_actions.append(a); } //打开应用 if(d->m_xdf.isValid()) { d->m_actions.append(new Action(d->m_xdf.name(), d->m_xdf.name(), d->m_icon, Action::Type::NewInstance)); connect(d->m_actions.last(), &Action::actionTriggered, this, &TaskManagerItem::newInstanceActionActive); } //添加到任务栏和从任务栏移除 auto removeLauncher = new Action("Remove launcher", tr("Remove launcher from panel"), QIcon::fromTheme("ukui-unfixed-symbolic"), Action::Type::RemoveQuickLauncher); connect(removeLauncher, &Action::actionTriggered, this, &TaskManagerItem::removeQuickLauncherActionActive); removeLauncher->setEnabled(hasLauncher()); d->m_actions.append(removeLauncher); //NoDisplay为true时无添加到任务栏选项 if (!d->m_xdf.value("NoDisplay").toBool()) { auto addLauncher = new Action("Add launcher", tr("Add launcher to panel"), QIcon::fromTheme("ukui-fixed-symbolic"), Action::Type::AddQuickLauncher); connect(addLauncher, &Action::actionTriggered, this, [&](const QVariant ¶m) { addQuickLauncherActionActive(param.toInt()); }); addLauncher->setEnabled(!hasLauncher() && !d->m_ID.isEmpty()); d->m_actions.append(addLauncher); } //关闭 auto exit = new Action("Close", tr("Close"), QIcon::fromTheme("application-exit-symbolic"), Action::Type::Exit); connect(exit, &Action::actionTriggered, this, [&](const QVariant& param){ exitActionActive(param.toStringList()); }); d->m_actions.append(exit); Q_EMIT dataUpdated(QVector{UkuiTaskManager::Actions, UkuiTaskManager::Id, UkuiTaskManager::Icon, UkuiTaskManager::Name}); } Actions TaskManagerItem::actions() const { return d->m_actions; } QStringList TaskManagerItem::demandsAttentionWinIDs() const { return d->m_demandsAttentionWinIDs; } void TaskManagerItem::iconChanged(const QString &windowId) { if(d->m_winIDs.contains(windowId)) { QIcon icon = WindowManager::windowIcon(windowId); if(icon.isNull()) { return; } d->m_widToIcon.insert(windowId, icon); d->m_widToIconName.insert(windowId, icon.name()); Q_EMIT dataUpdated(QVector{UkuiTaskManager::WindowIcons, UkuiTaskManager::WindowIconsName}); if(d->m_icon.isNull() && windowId == winIDs().first()) { d->m_icon = WindowManager::windowIcon(winIDs().at(0)); Q_EMIT dataUpdated(QVector{UkuiTaskManager::Icon}); } } } void TaskManagerItem::titleChanged(const QString &windowId) { if(d->m_winIDs.contains(windowId)) { d->m_widToTitle.insert(windowId, WindowManager::windowTitle(windowId)); Q_EMIT dataUpdated(QVector{UkuiTaskManager::WindowTitles}); if (d->m_name.isEmpty() && windowId == winIDs().first()) { d->m_name = WindowManager::windowTitle(winIDs().at(0)); Q_EMIT dataUpdated(QVector{UkuiTaskManager::Name}); } } } void TaskManagerItem::desktopChanged(const QString &windowId) { if(currentDesktopWinIDs().contains(windowId)) { if(!WindowManager::isOnAllDesktops(windowId) && !WindowManager::isOnCurrentDesktop(windowId)) { d->m_winIDsOnCurrentDesktop.removeAll(windowId); Q_EMIT dataUpdated(QVector{UkuiTaskManager::CurrentDesktopWinIdList, UkuiTaskManager::CurrentWinIdList}); } } else if (d->m_winIDs.contains(windowId)){ if(WindowManager::isOnAllDesktops(windowId) || WindowManager::isOnCurrentDesktop(windowId)) { d->m_winIDsOnCurrentDesktop.append(windowId); Q_EMIT dataUpdated(QVector{UkuiTaskManager::CurrentDesktopWinIdList, UkuiTaskManager::CurrentWinIdList}); } } } void TaskManagerItem::demandsAttentionChanged(const QString &windowId) { if(d->m_winIDs.contains(windowId)) { if(WindowManager::isDemandsAttention(windowId)) { if(!d->m_demandsAttentionWinIDs.contains(windowId)) { d->m_demandsAttentionWinIDs.append(windowId); Q_EMIT dataUpdated(QVector{UkuiTaskManager::DemandsAttentionWinIdList}); } } else { if(d->m_demandsAttentionWinIDs.contains(windowId)) { d->m_demandsAttentionWinIDs.removeAll(windowId); Q_EMIT dataUpdated(QVector{UkuiTaskManager::DemandsAttentionWinIdList}); } } } } void TaskManagerItem::geometryChanged(const QString &windowId) { if(!d->m_winIDs.contains(windowId)) { return; } d->m_widToGeometry.insert(windowId, WindowManager::geometry(windowId)); Q_EMIT dataUpdated(QVector{UkuiTaskManager::WindowGeometries, UkuiTaskManager::CurrentWinIdList}); } void TaskManagerItem::refreshWinIdsOnCurrentDesktop() { d->m_winIDsOnCurrentDesktop.clear(); for(const QString &wid : d->m_winIDs) { if(WindowManager::isOnCurrentDesktop(wid) || WindowManager::isOnAllDesktops(wid)) { d->m_winIDsOnCurrentDesktop.append(wid); } } Q_EMIT dataUpdated(QVector{UkuiTaskManager::CurrentDesktopWinIdList, UkuiTaskManager::CurrentWinIdList}); } void TaskManagerItem::refreshWinIdsOnScreens() { d->m_widToGeometry.clear(); for (const QString &wid: d->m_winIDs) { d->m_widToGeometry.insert(wid, WindowManager::geometry(wid)); } Q_EMIT dataUpdated(QVector{UkuiTaskManager::WindowGeometries, UkuiTaskManager::CurrentWinIdList}); } void TaskManagerItem::refreshWindowTitlesAndIcons() { d->m_widToTitle.clear(); for(const QString &wid : d->m_winIDs) { QString title = WindowManager::windowTitle(wid); if(title.isEmpty()) { title = d->m_name; } d->m_widToTitle.insert(wid, title); QIcon icon = WindowManager::windowIcon(wid); if(icon.isNull()) { icon = d->m_icon; } d->m_widToIcon.insert(wid, icon.isNull() ? QVariant("application-x-desktop") : icon); d->m_widToIconName.insert(wid, icon.name()); } } const QStringList &TaskManagerItem::currentDesktopWinIDs() { return d->m_winIDsOnCurrentDesktop; } void TaskManagerItem::updateUnreadMessagesNum(const QString &desktopFile, uint num) { QFileInfo fileInfo(desktopFile); QString desktopName; if (fileInfo.fileName().endsWith(QStringLiteral(".desktop"))) { desktopName = fileInfo.completeBaseName(); } else { desktopName = fileInfo.fileName(); } if(desktopName == d->m_ID) { qDebug() << "Update unread messagesNum" << desktopFile << num; d->m_unreadMessagesNum = num; Q_EMIT dataUpdated(QVector{UkuiTaskManager::UnreadMessagesNum}); } } uint TaskManagerItem::unReadMessagesNum() { return d->m_unreadMessagesNum; } void TaskManagerItem::newInstanceActionActive(const QVariant& param) { launch(param.value()); } void TaskManagerItem::launch(const QQuickItem* item) { if(d->m_desktopFile.isEmpty()) { return; } QString method = QStringLiteral("LaunchApp"); if(item) { method = QStringLiteral("LaunchAppWithGeometry"); } QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("com.kylin.ProcessManager"), QStringLiteral("/com/kylin/ProcessManager/AppLauncher"), QStringLiteral("com.kylin.ProcessManager.AppLauncher"), method); message << d->m_desktopFile; if(item) { auto point = item->mapToGlobal(QPoint(0, 0)); message << static_cast(point.x()) << static_cast(point.y()) << static_cast(item->width()) << static_cast(item->height()); } qDebug() << "Taskmanager Calling:" << method << message; auto watcher = new QDBusPendingCallWatcher(QDBusPendingCall(QDBusConnection::sessionBus().asyncCall(message))); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [&] (QDBusPendingCallWatcher *self) { qDebug() << "Taskmanager Calling finished:" << self->isError(); if (self->isError()) { qDebug() << "launch" << d->m_desktopFile << self->error(); d->m_xdf.startDetached(); } self->deleteLater(); }); } void TaskManagerItem::desktopActionActive(const QString &name) { d->m_xdf.actionActivate(name, {}); } void TaskManagerItem::removeQuickLauncherActionActive() { UkuiTaskManager::self().removeQuickLauncher(d->m_desktopFile); } void TaskManagerItem::addQuickLauncherActionActive(int index) { UkuiTaskManager::self().setQuickLauncher(d->m_desktopFile, index); } void TaskManagerItem::exitActionActive(const QStringList &winIds) { for(const QString &wid : winIds) { WindowManager::closeWindow(wid); } } void TaskManagerItem::onWidgetInfoUpdate(const QString& appid, const QString& widgetId) { if(d->m_ID == appid) { d->m_quickWidget = widgetId; Q_EMIT dataUpdated(QVector{UkuiTaskManager::QuickWidgetId}); } } const QMap &TaskManagerItem::WindowGeometries() const { return d->m_widToGeometry; } const QMap &TaskManagerItem::windowTitles() const { return d->m_widToTitle; } const QMap &TaskManagerItem::windowIcons() const { return d->m_widToIcon; } const QMap &TaskManagerItem::windowIconsName() const { return d->m_widToIconName; } void TaskManagerItem::updateIconStatus() { Q_EMIT dataUpdated(QVector{UkuiTaskManager::HasActiveWindow, UkuiTaskManager::WindowGeometries, UkuiTaskManager::CurrentWinIdList}); } ukui-panel/widgets/ukui-panel-widget-test/0000775000175000017500000000000015167645100017535 5ustar fengfengukui-panel/widgets/ukui-panel-widget-test/widget/0000775000175000017500000000000015167645100021020 5ustar fengfengukui-panel/widgets/ukui-panel-widget-test/widget/ui/0000775000175000017500000000000015167645100021435 5ustar fengfengukui-panel/widgets/ukui-panel-widget-test/widget/ui/BlurImageTest.qml0000664000175000017500000000242015167645100024655 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import org.ukui.quick.items 1.0 Rectangle { color: "transparent" Image { id: image width: 1600 height: 900 source: "file:///usr/share/backgrounds/2-openkylin.jpg" } BlurItem { x: 100 y: 100 width: 500 height: 500 radius: 40 samples: 81 source: image Drag.active: dragArea.drag.active MouseArea { id: dragArea anchors.fill: parent drag.target: parent } } } ukui-panel/widgets/ukui-panel-widget-test/widget/ui/main.qml0000664000175000017500000000323415167645100023076 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.menu.starter 1.0 import org.ukui.quick.items 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal Layout.preferredWidth: isHorizontal ? 200 : 50 Layout.preferredHeight: !isHorizontal ? 200 : 50 // BlurImageTest { // anchors.fill: parent // } ToolTip.text: Widget.tooltip MouseArea { anchors.fill: parent hoverEnabled: true onEntered: { root.ToolTip.show(root.mapToGlobal(root.x, root.y)); } onExited: { root.ToolTip.hide(); } } Rectangle { anchors.fill: parent color: "#407D52BF" DropArea { anchors.fill: parent onDropped: (drop) => { console.log("drop:", drop.urls, drop.text); } } } } ukui-panel/widgets/ukui-panel-widget-test/widget/metadata.json0000664000175000017500000000103615167645100023473 0ustar fengfeng{ "Authors": [ { "Name": "zpf", "Email": "zpf@kylinos.cn" } ], "Id": "org.ukui.panel.widget.test", "Icon": "ukui-panel", "Name": "Widget test tool", "Name[zh_CN]": "组件测试工具", "Tooltip": "Widget test tool", "Tooltip[zh_CN]": "组件测试工具", "Description": "Widget test tool", "Description[zh_CN]": "组件测试工具", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "Contents": { "Main": "ui/main.qml" } } ukui-panel/widgets/ukui-panel-widget-test/CMakeLists.txt0000664000175000017500000000020415167645100022271 0ustar fengfengcmake_minimum_required(VERSION 3.16) install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.widget.test") ukui-panel/widgets/CMakeLists.txt0000664000175000017500000000067115167645100015771 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(widgets VERSION 4.1) add_subdirectory(ukui-task-manager) add_subdirectory(ukui-menu-starter) add_subdirectory(ukui-panel-showDesktop) add_subdirectory(ukui-panel-widget-test) add_subdirectory(ukui-panel-calendar) add_subdirectory(ukui-panel-separator) add_subdirectory(ukui-panel-search) add_subdirectory(ukui-panel-taskView) add_subdirectory(ukui-panel-idm) add_subdirectory(ukui-ai-assistant) ukui-panel/widgets/ukui-panel-showDesktop/0000775000175000017500000000000015167645111017611 5ustar fengfengukui-panel/widgets/ukui-panel-showDesktop/widget/0000775000175000017500000000000015167645100021072 5ustar fengfengukui-panel/widgets/ukui-panel-showDesktop/widget/ui/0000775000175000017500000000000015167645100021507 5ustar fengfengukui-panel/widgets/ukui-panel-showDesktop/widget/ui/main.qml0000664000175000017500000000646015167645100023154 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ import QtQuick 2.12 import QtQuick.Layouts 1.12 import org.ukui.quick.widgets 1.0 import org.ukui.panel.showDesktop 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal property real ratio: parent.ratio ? parent.ratio : 1 property real inset: 2 * ratio Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredHeight: isHorizontal ? height : (15 * ratio + inset) Layout.preferredWidth: isHorizontal ? (15 * ratio + inset) : width //使其右键不显示父窗口的菜单 MouseArea { anchors.fill: root acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { return; } } } MouseArea { Accessible.role: Accessible.Button Accessible.description: "This is a showDesktop button of ukui-panel" Accessible.name: "show desktop" anchors.fill: parent anchors.leftMargin: isHorizontal ? inset : 0 anchors.topMargin: isHorizontal ? 0 : inset hoverEnabled: true DtThemeBackground { anchors.fill: parent useStyleTransparency: false backgroundColor: parent.containsPress ? GlobalTheme.kComponentAlphaClick : parent.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kComponentAlphaNormal } ShowDesktop { id: showDesktop } onClicked: { //使其右键不显示父窗口的菜单 if (mouse.button === Qt.RightButton) { return; } else if (mouse.button === Qt.LeftButton && !showDesktop.disableMouseLeftButton) { showDesktop.showDesktop(); } } Tooltip { id: tooltip anchors.fill: parent mainText: Widget.tooltip posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: 8 } } } ukui-panel/widgets/ukui-panel-showDesktop/widget/metadata.json0000775000175000017500000000334515167645100023555 0ustar fengfeng{ "Authors": [ { "Name": "hxf", "Email": "hewenfei@kylinos.cn" } ], "Id": "org.ukui.panel.showDesktop", "Icon": "ukui-panel", "Name": "show desktop", "Name[zh_CN]": "显示桌面", "Name[zh_HK]": "顯示桌面", "Name[bo_CN]": "ཅོག་ངོས་འཆར་བ།", "Name[ug_CN]": "ئۈستەل يۈزىنى  كۆرسىتىش", "Name[kk_KZ]": "ۇستەل بەتىن  كورسەتۋ", "Name[ky_KG]": "شىرە  بەتىن  كۅرسۅتۉۉ", "Name[mn_MN]": "ᠰᠢᠷᠡᠭᠡᠨ ᠭᠠᠳᠠᠷᠭᠤ ᠶᠢ ᠢᠯᠡᠷᠡᠭᠦᠯᠦᠨ᠎ᠡ", "Tooltip": "Show desktop", "Tooltip[zh_CN]": "显示桌面", "Tooltip[zh_HK]": "顯示桌面", "Tooltip[bo_CN]": "ཅོག་ངོས་འཆར་བ།", "Tooltip[ug_CN]": "ئۈستەل يۈزىنى  كۆرسىتىش", "Tooltip[kk_KZ]": "ۇستەل بەتىن  كورسەتۋ", "Tooltip[ky_KG]": "شىرە  بەتىن  كۅرسۅتۉۉ", "Tooltip[mn_MN]": "ᠰᠢᠷᠡᠭᠡᠨ ᠭᠠᠳᠠᠷᠭᠤ ᠶᠢ ᠢᠯᠡᠷᠡᠭᠦᠯᠦᠨ᠎ᠡ", "Description": "Show desktop", "Description[zh_CN]": "显示桌面", "Description[zh_HK]": "顯示桌面", "Description[bo_CN]": "ཅོག་ངོས་འཆར་བ།", "Description[ug_CN]": "ئۈستەل يۈزىنى  كۆرسىتىش", "Description[kk_KZ]": "ۇستەل بەتىن  كورسەتۋ", "Description[ky_KG]": "شىرە  بەتىن  كۅرسۅتۉۉ", "Description[mn_MN]": "ᠰᠢᠷᠡᠭᠡᠨ ᠭᠠᠳᠠᠷᠭᠤ ᠶᠢ ᠢᠯᠡᠷᠡᠭᠦᠯᠦᠨ᠎ᠡ", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "Contents": { "Main": "ui/main.qml" } } ukui-panel/widgets/ukui-panel-showDesktop/CMakeLists.txt0000664000175000017500000000256515167645111022361 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel-showDesktop VERSION 4.1) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick REQUIRED) find_package(ukui-quick REQUIRED platform) set(PROJECT_SOURCES plugin/show-desktop-plugin.h plugin/show-desktop-plugin.cpp plugin/show-desktop.h plugin/show-desktop.cpp ) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES}) else() add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES}) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG> ) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick ukui-quick::platform ) set(PLUGIN_INSTALL_ROOT_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/panel/showDesktop") install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.showDesktop") install(FILES "plugin/qmldir" DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) ukui-panel/widgets/ukui-panel-showDesktop/plugin/0000775000175000017500000000000015167645100021105 5ustar fengfengukui-panel/widgets/ukui-panel-showDesktop/plugin/qmldir0000664000175000017500000000010015167645100022307 0ustar fengfengmodule org.ukui.panel.showDesktop plugin ukui-panel-showDesktop ukui-panel/widgets/ukui-panel-showDesktop/plugin/show-desktop.h0000664000175000017500000000270015167645100023704 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_SHOW_DESKTOP_H #define UKUI_PANEL_SHOW_DESKTOP_H #include namespace UkuiPanel { class ShowDesktop : public QObject { Q_OBJECT Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) public: explicit ShowDesktop(QObject *parent = nullptr); ~ShowDesktop() override; Q_INVOKABLE void showDesktop(); bool disableMouseLeftButton() const; Q_SIGNALS: void disableMouseLeftButtonChanged(); public Q_SLOTS: void onFunctionControlChanged(const QString& name, bool exit = false); private: void initFunctionControl(); bool m_disableMouseLeftButton = false; }; } // UkuiPanel #endif //UKUI_PANEL_SHOW_DESKTOP_H ukui-panel/widgets/ukui-panel-showDesktop/plugin/show-desktop-plugin.h0000664000175000017500000000207615167645100025206 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_SHOW_DESKTOP_PLUGIN_H #define UKUI_PANEL_SHOW_DESKTOP_PLUGIN_H #include class ShowDesktopPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif //UKUI_PANEL_SHOW_DESKTOP_PLUGIN_H ukui-panel/widgets/ukui-panel-showDesktop/plugin/show-desktop.cpp0000664000175000017500000000544215167645100024245 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "show-desktop.h" #include #include #include namespace UkuiPanel { ShowDesktop::ShowDesktop(QObject *parent) : QObject(parent) { initFunctionControl(); } ShowDesktop::~ShowDesktop() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-showDesktop-v11")); } void ShowDesktop::showDesktop() { UkuiQuick::WindowManager::setShowingDesktop(!UkuiQuick::WindowManager::showingDesktop()); } bool ShowDesktop::disableMouseLeftButton() const { return m_disableMouseLeftButton; } void ShowDesktop::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-showDesktop-v11")) { return; } auto controlConfig = exit ? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "ShowDesktop function control config:" << controlConfig; //是否禁用左键点击 if (controlConfig.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } } void ShowDesktop::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-showDesktop-v11")); onFunctionControlChanged(QStringLiteral("ukui-panel-showDesktop-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-showDesktop-v11"), true); }); } } // UkuiPanel ukui-panel/widgets/ukui-panel-showDesktop/plugin/show-desktop-plugin.cpp0000664000175000017500000000201315167645100025530 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "show-desktop-plugin.h" #include "show-desktop.h" #include void ShowDesktopPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.showDesktop")); qmlRegisterType(uri, 1, 0, "ShowDesktop"); } ukui-panel/widgets/ukui-panel-search/0000775000175000017500000000000015167645111016544 5ustar fengfengukui-panel/widgets/ukui-panel-search/translations/0000775000175000017500000000000015167645100021263 5ustar fengfengukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_ky.ts0000664000175000017500000000056315167645100026447 0ustar fengfeng main Search ٴتىنتۋ Search settings ٴتىنتۋ سالۋ ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_zh_CN.ts0000664000175000017500000000055215167645100027023 0ustar fengfeng main Search 搜索 Search settings 设置搜索项 ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_es.ts0000664000175000017500000000056615167645100026436 0ustar fengfeng main Search Search settings ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_fr.ts0000664000175000017500000000056615167645100026436 0ustar fengfeng main Search Search settings ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_ug.ts0000664000175000017500000000057515167645100026442 0ustar fengfeng main Search ئىزدە Search settings ئىزدەش تەڭشەكلىرى ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_mn.ts0000664000175000017500000000063015167645100026431 0ustar fengfeng main Search ᠡᠷᠢᠬᠦ Search settings ᠡᠷᠢᠵᠦ ᠪᠠᠶᠢᠷᠢᠯᠠᠭᠤᠯᠬᠤ ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_kk.ts0000664000175000017500000000056315167645100026431 0ustar fengfeng main Search ٴتىنتۋ Search settings ٴتىنتۋ سالۋ ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_zh_HK.ts0000664000175000017500000000055215167645100027025 0ustar fengfeng main Search 搜索 Search settings 設置搜索項 ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_bo_CN.ts0000664000175000017500000000074215167645100027003 0ustar fengfeng main Search འཚོལ་ཞིབ་བྱེད་པ། Search settings འཚོལ་ཞིབ་ཀྱི་རྣམ་གྲངས་བཟོ་དགོས། ukui-panel/widgets/ukui-panel-search/translations/org.ukui.panel.search_de.ts0000664000175000017500000000056615167645100026417 0ustar fengfeng main Search Search settings ukui-panel/widgets/ukui-panel-search/widget/0000775000175000017500000000000015167645100020025 5ustar fengfengukui-panel/widgets/ukui-panel-search/widget/ui/0000775000175000017500000000000015167645100020442 5ustar fengfengukui-panel/widgets/ukui-panel-search/widget/ui/main.qml0000664000175000017500000000762415167645100022112 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.panel.search 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal property real ratio: parent.ratio ? parent.ratio : 1 Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? height - mouseArea.anchors.topMargin - mouseArea.anchors.bottomMargin : width Layout.preferredHeight: isHorizontal ? height : width - mouseArea.anchors.leftMargin - mouseArea.anchors.rightMargin MouseArea { id: mouseArea Accessible.role: Accessible.Button Accessible.description: "This is a global search button of ukui-panel" Accessible.name: "ukui-panel-search" anchors.fill: parent hoverEnabled: true anchors { leftMargin: root.isHorizontal? 0 : 4 * root.ratio topMargin: root.isHorizontal? 4 * root.ratio : 0 rightMargin: root.isHorizontal? 0 : 4 * root.ratio bottomMargin: root.isHorizontal? 4 * root.ratio : 0 } DtThemeBackground { anchors.fill: parent radius: GlobalTheme.kRadiusNormal useStyleTransparency: false backgroundColor: mouseArea.containsPress ? GlobalTheme.kComponentAlphaClick : mouseArea.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kContainGeneralAlphaNormal Icon { anchors.fill: parent anchors.margins: 4 * root.ratio source: "kylin-search" scale: mouseArea.containsPress ? 0.8 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } } } SearchButton { id: searchButton } acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: (mouse) => { if (mouse.button === Qt.LeftButton && !searchButton.disableMouseLeftButton) { let globalPos = mapToGlobal(Qt.point(mouseArea.x, mouseArea.y)) searchButton.openUkuiSearch(globalPos.x, globalPos.y, mouseArea.width, mouseArea.height); } if (mouse.button === Qt.RightButton && !searchButton.disableMouseRightButton) { searchButton.openContextMenu(root); } } Tooltip { id: tooltip anchors.fill: parent mainText: Widget.tooltip posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: root.isHorizontal ? 8 + mouseArea.anchors.topMargin : 8 + mouseArea.anchors.leftMargin } } } ukui-panel/widgets/ukui-panel-search/widget/metadata.json0000775000175000017500000000323315167645100022504 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.panel.search", "Icon": "kylin-search", "Name": "ukui-panel-search", "Name[zh_CN]": "搜索", "Name[zh_HK]": "搜索", "Name[bo_CN]": "བཤེར་འཚོལ།", "Name[ug_CN]": "ھەممە يەردىن ئىزدەش", "Name[kk_KZ]": "بارلٸق جەردەن ٸزدەۋ", "Name[ky_KG]": "باردىق جەردەن ىزدۅۅ", "Name[mn_MN]": "ᠬᠠᠢᠯᠳᠠ", "Tooltip": "Global Search", "Tooltip[zh_CN]": "搜索", "Tooltip[zh_HK]": "搜索", "Tooltip[bo_CN]": "བཤེར་འཚོལ་འགོ་སློང་།", "Tooltip[ug_CN]": "ھەممە يەرنى ئىزدەشنى قوزغىتىش", "Tooltip[kk_KZ]": "بارلٸق جەردى ىزدەۋدى قوزعالتۋ", "Tooltip[ky_KG]": "باردىق جەردى ىزدەشتى  قوزعوتۇۇ", "Tooltip[mn_MN]": "ᠬᠠᠢᠯᠳᠠ", "Description": "Global Search", "Description[zh_CN]": "启动搜索", "Description[zh_HK]": "啟動搜索", "Description[bo_CN]": "བཤེར་འཚོལ་འགོ་སློང་།", "Description[ug_CN]": "ھەممە يەرنى ئىزدەشنى قوزغىتىش", "Description[kk_KZ]": "بارلٸق جەردى ىزدەۋدى قوزعالتۋ", "Description[ky_KG]": "باردىق جەردى ىزدەشتى  قوزعوتۇۇ", "Description[mn_MN]": "ᠬᠠᠢᠯᠳᠠ", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "All", "Contents": { "Main": "ui/main.qml", "I18n": "translations/org.ukui.panel.search" } } ukui-panel/widgets/ukui-panel-search/CMakeLists.txt0000664000175000017500000000405415167645111021307 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel-search VERSION 4.1) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick Widgets DBus LinguistTools REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick Widgets DBus LinguistTools REQUIRED) find_package(ukui-quick COMPONENTS platform) set(PROJECT_SOURCES plugin/search-button.h plugin/search-plugin.h plugin/search-plugin.cpp plugin/search-button.cpp ) file(GLOB TS_FILES translations/*.ts) set(SEARCH_WIDGET_DIR "/usr/share/ukui/widgets/org.ukui.panel.search") set(TRANSLATION_FILE_DIR "${SEARCH_WIDGET_DIR}/translations") add_compile_definitions(TRANSLATION_FILE_DIR="${TRANSLATION_FILE_DIR}" UKUI_TASK_MANAGER_VERSION="${UKUI_TASK_MANAGER_VERSION}") if(COMMAND qt_create_translation) qt_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES}) else() qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES}) endif() if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) else() add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG> ) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Widgets ukui-quick::platform ) set(PLUGIN_INSTALL_ROOT_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/panel/search") install(DIRECTORY "widget/" DESTINATION ${SEARCH_WIDGET_DIR}) install(FILES ${QM_FILES} DESTINATION "${TRANSLATION_FILE_DIR}") install(FILES "plugin/qmldir" DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) ukui-panel/widgets/ukui-panel-search/plugin/0000775000175000017500000000000015167645100020040 5ustar fengfengukui-panel/widgets/ukui-panel-search/plugin/search-plugin.cpp0000664000175000017500000000177315167645100023315 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "search-plugin.h" #include "search-button.h" #include "qqml.h" void StartMenuPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.search")); qmlRegisterType(uri, 1, 0, "SearchButton"); } ukui-panel/widgets/ukui-panel-search/plugin/qmldir0000664000175000017500000000006615167645100021255 0ustar fengfengmodule org.ukui.panel.search plugin ukui-panel-search ukui-panel/widgets/ukui-panel-search/plugin/search-button.h0000664000175000017500000000347515167645100023000 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_START_MENU_BUTTON_H #define UKUI_PANEL_START_MENU_BUTTON_H #include #include class SearchButton : public QObject { Q_OBJECT Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) Q_PROPERTY(bool disableMouseRightButton READ disableMouseRightButton NOTIFY disableMouseRightButtonChanged) public: explicit SearchButton(QObject *parent=nullptr); ~SearchButton() override; Q_INVOKABLE void openUkuiSearch(int x, int y, int width, int height); Q_INVOKABLE void openSearchSetting(); Q_INVOKABLE void openContextMenu(QQuickItem *item); bool disableMouseLeftButton() const; bool disableMouseRightButton() const; Q_SIGNALS: void disableMouseLeftButtonChanged(); void disableMouseRightButtonChanged(); public Q_SLOTS: void onFunctionControlChanged(const QString& name, bool exit = false); private: void initFunctionControl(); bool m_disableMouseLeftButton = false; bool m_disableMouseRightButton = false; }; #endif //UKUI_PANEL_START_MENU_BUTTON_H ukui-panel/widgets/ukui-panel-search/plugin/search-button.cpp0000664000175000017500000001277015167645100023331 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "search-button.h" #include #include #include #include #include #include #include #include #include #include #include SearchButton::SearchButton(QObject *parent) : QObject(parent) { initFunctionControl(); } SearchButton::~SearchButton() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-search-v11")); } void SearchButton::openUkuiSearch(int x, int y, int width, int height) { uint searchPid = QDBusConnection::sessionBus().interface()->servicePid(QStringLiteral("com.ukui.search.service")); UkuiQuick::StartupManagement::self()->setStartupGeometry(searchPid, x, y, width, height); QDBusInterface interface(QStringLiteral("com.ukui.search.service"), QStringLiteral("/"), QStringLiteral("org.ukui.search.service"), QDBusConnection::sessionBus()); interface.asyncCall(QStringLiteral("mainWindowSwitch")); } void SearchButton::openSearchSetting() { bool res(false); QDBusInterface appLaunchInterface(QStringLiteral("com.kylin.ProcessManager"), QStringLiteral("/com/kylin/ProcessManager/AppLauncher"), QStringLiteral("com.kylin.ProcessManager.AppLauncher"), QDBusConnection::sessionBus()); if(!appLaunchInterface.isValid()) { qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message()); res = false; } else { appLaunchInterface.setTimeout(10000); QDBusReply reply = appLaunchInterface.call("LaunchAppWithArguments", "/usr/share/applications/ukui-control-center.desktop", QStringList{"-m", "search"}); if(reply.isValid()) { res = true; } else { qWarning() << "ProcessManager dbus called failed!" << reply.error(); res = false; } } if (!res) { //打开控制面板对应页面 QProcess::startDetached("ukui-control-center", {"-m", "search"}); } } void SearchButton::openContextMenu(QQuickItem *item) { QMenu *menu = new QMenu; menu->setAttribute(Qt::WA_DeleteOnClose); QAction *searchSettings = new QAction(QIcon::fromTheme("system-settings-symbolic"), tr("Search settings"), menu); connect(searchSettings, &QAction::triggered, this, &SearchButton::openSearchSetting); menu->addAction(searchSettings); //设置父窗口 menu->winId(); if(menu->windowHandle()) { menu->windowHandle()->setTransientParent(item->window()); } menu->popup(QCursor::pos()); } bool SearchButton::disableMouseLeftButton() const { return m_disableMouseLeftButton; } bool SearchButton::disableMouseRightButton() const { return m_disableMouseRightButton; } void SearchButton::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-search-v11")); onFunctionControlChanged(QStringLiteral("ukui-panel-search-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-search-v11"), true); }); } void SearchButton::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-search-v11")) { return; } auto controlConfig = exit ? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "SearchButton function control config:" << controlConfig; //是否禁用左键点击 if (controlConfig.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } //是否禁用右键点击 if (controlConfig.contains(QStringLiteral("disableMouseRightButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseRightButton")).toBool(); if (disable != m_disableMouseRightButton) { m_disableMouseRightButton = disable; Q_EMIT disableMouseRightButtonChanged(); } } else { m_disableMouseRightButton = false; Q_EMIT disableMouseRightButtonChanged(); } } ukui-panel/widgets/ukui-panel-search/plugin/search-plugin.h0000664000175000017500000000207415167645100022755 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_START_MENU_PLUGIN_H #define UKUI_PANEL_START_MENU_PLUGIN_H #include class StartMenuPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif //UKUI_PANEL_START_MENU_PLUGIN_H ukui-panel/widgets/ukui-ai-assistant/0000775000175000017500000000000015167645111016602 5ustar fengfengukui-panel/widgets/ukui-ai-assistant/i18n/0000775000175000017500000000000015167645100017357 5ustar fengfengukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_ky.ts0000664000175000017500000000013415167645100024573 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_ug.ts0000664000175000017500000000013415167645100024563 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_bo_CN.ts0000664000175000017500000000013715167645100025133 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_mn.ts0000664000175000017500000000013415167645100024562 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_kk.ts0000664000175000017500000000013415167645100024555 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_es.ts0000664000175000017500000000013415167645100024557 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_zh_CN.ts0000664000175000017500000000013715167645100025154 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_zh_HK.ts0000664000175000017500000000013715167645100025156 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_de.ts0000664000175000017500000000013415167645100024540 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_fr.ts0000664000175000017500000000013415167645100024557 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/i18n/org.ukui.ai.assistant_tr.ts0000664000175000017500000000013415167645100024575 0ustar fengfeng ukui-panel/widgets/ukui-ai-assistant/widget/0000775000175000017500000000000015167645100020063 5ustar fengfengukui-panel/widgets/ukui-ai-assistant/widget/ui/0000775000175000017500000000000015167645100020500 5ustar fengfengukui-panel/widgets/ukui-ai-assistant/widget/ui/main.qml0000664000175000017500000001041515167645100022140 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.ai.assistant 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal property real ratio: parent.ratio ? parent.ratio : 1 visible: assistantButton.available Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: assistantButton.available ? (isHorizontal ? height - mouseArea.anchors.topMargin - mouseArea.anchors.bottomMargin : width) : 0 Layout.preferredHeight: assistantButton.available ? (isHorizontal ? height : width - mouseArea.anchors.leftMargin - mouseArea.anchors.rightMargin) : 0 property bool isMiniLayout: isHorizontal && (height <= 36) // 更新tooltip Widget.tooltip: Widget.tooltip //使其右键不显示父窗口的菜单 MouseArea { anchors.fill: root acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { return; } } } MouseArea { id: mouseArea Accessible.role: Accessible.Button Accessible.description: "This is an ai-assistant button of ukui-panel" Accessible.name: "kylin-ai-assistant" anchors.fill: parent hoverEnabled: true anchors { leftMargin: root.isHorizontal? 0 : 4 * root.ratio topMargin: isMiniLayout ? 2 * root.ratio : root.isHorizontal? 4 * root.ratio : 0 rightMargin: root.isHorizontal? 0 : 4 * root.ratio bottomMargin: isMiniLayout ? 2 * root.ratio : root.isHorizontal? 4 * root.ratio : 0 } DtThemeBackground { anchors.fill: parent radius: GlobalTheme.kRadiusNormal useStyleTransparency: false backgroundColor: mouseArea.containsPress ? GlobalTheme.kComponentAlphaClick : mouseArea.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kContainGeneralAlphaNormal Tooltip { id: tooltip anchors.fill: parent mainText: Widget.tooltip posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: root.isHorizontal ? 8 + mouseArea.anchors.topMargin : 8 + mouseArea.anchors.leftMargin } } Icon { anchors.fill: parent anchors.margins: isMiniLayout ? 2 * root.ratio : 4 * root.ratio source: assistantButton.icon scale: parent.containsPress ? 0.8 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } } onClicked: (mouse) => { if (mouse.button === Qt.LeftButton && !assistantButton.disableMouseLeftButton) { assistantButton.pressed(); } } } AiAssistantButton { id: assistantButton } } ukui-panel/widgets/ukui-ai-assistant/widget/metadata.json0000775000175000017500000000211315167645100022536 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.ai.assistant", "Icon": "kylin-ai-assistant", "Name": "kylin-ai-assistant", "Name[zh_CN]": "AI 助手", "Name[zh_HK]": "AI 助手", "Name[mn_MN]": "AI ᠬᠠᠪᠰᠤᠷᠤᠭᠴᠢ ", "Name[bo_CN]": "ཨའི་ཨར་རྩིས་རྩོམ་པ", "Tooltip": "AI Assistant", "Tooltip[zh_CN]": "AI 助手", "Tooltip[zh_HK]": "AI 助手", "Tooltip[mn_MN]": "AI ᠬᠠᠪᠰᠤᠷᠤᠭᠴᠢ ", "Tooltip[bo_CN]": "ཨའི་ཨར་རྩིས་རྩོམ་པ", "Description": "Kylin AI Assistant", "Description[zh_CN]": "AI 助手", "Description[zh_HK]": "AI 助手", "Description[mn_MN]": "AI ᠬᠠᠪᠰᠤᠷᠤᠭᠴᠢ ", "Description[bo_CN]": "ཨའི་ཨར་རྩིས་རྩོམ་པ", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "All", "Contents": { "Main": "ui/main.qml", "I18n": "i18n/org.ukui.ai.assistant" } } ukui-panel/widgets/ukui-ai-assistant/CMakeLists.txt0000664000175000017500000000364215167645111021347 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-ai-assistant VERSION 4.20) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) # TODO: 将依赖倒入的操作放到顶级CMakeList文件中 find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick LinguistTools REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick LinguistTools REQUIRED) find_package(ukui-quick COMPONENTS platform REQUIRED) find_package(ukui-search) set(PROJECT_SOURCES plugin/ai-assistant-button.cpp plugin/ai-assistant-button.h plugin/ai-assistant-plugin.cpp plugin/ai-assistant-plugin.h ) file(GLOB TS_FILES i18n/*.ts) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) qt_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) else() qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG> ) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus ukui-quick::platform ukui-search ) set(PLUGIN_INSTALL_ROOT_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/ai/assistant") install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.ai.assistant") install(FILES ${QM_FILES} DESTINATION "/usr/share/ukui/widgets/org.ukui.ai.assistant/i18n") install(FILES "plugin/qmldir" DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) ukui-panel/widgets/ukui-ai-assistant/plugin/0000775000175000017500000000000015167645100020076 5ustar fengfengukui-panel/widgets/ukui-ai-assistant/plugin/qmldir0000664000175000017500000000006615167645100021313 0ustar fengfengmodule org.ukui.ai.assistant plugin ukui-ai-assistant ukui-panel/widgets/ukui-ai-assistant/plugin/ai-assistant-plugin.h0000664000175000017500000000207615167645100024150 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_START_MENU_PLUGIN_H #define UKUI_PANEL_START_MENU_PLUGIN_H #include class AIAssistantPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif //UKUI_PANEL_START_MENU_PLUGIN_H ukui-panel/widgets/ukui-ai-assistant/plugin/ai-assistant-button.h0000664000175000017500000000352315167645100024163 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_START_MENU_BUTTON_H #define UKUI_PANEL_START_MENU_BUTTON_H #include namespace UkuiSearch { class ApplicationInfo; } class AiAssistantButton : public QObject { Q_OBJECT Q_PROPERTY(bool available READ available NOTIFY availableChanged) Q_PROPERTY(QString icon READ icon NOTIFY iconChanged) Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) public: explicit AiAssistantButton(QObject *parent=nullptr); ~AiAssistantButton() override; Q_INVOKABLE void pressed(); bool available() const; QString icon() const; bool disableMouseLeftButton() const; Q_SIGNALS: void availableChanged(); void iconChanged(); void disableMouseLeftButtonChanged(); public Q_SLOTS: void onFunctionControlChanged(const QString& name, bool exit = false); private: void fetchIcon(); void initFunctionControl(); bool m_disableMouseLeftButton = false; UkuiSearch::ApplicationInfo *m_appInfo = nullptr; QString m_desktopFile; QString m_icon; }; #endif //UKUI_PANEL_START_MENU_BUTTON_H ukui-panel/widgets/ukui-ai-assistant/plugin/ai-assistant-plugin.cpp0000664000175000017500000000202215167645100024472 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "ai-assistant-plugin.h" #include "ai-assistant-button.h" #include "qqml.h" void AIAssistantPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.ai.assistant")); qmlRegisterType(uri, 1, 0, "AiAssistantButton"); } ukui-panel/widgets/ukui-ai-assistant/plugin/ai-assistant-button.cpp0000664000175000017500000001400415167645100024512 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "ai-assistant-button.h" #include #include #include #include #include #include #include #include AiAssistantButton::AiAssistantButton(QObject *parent) : QObject(parent) { m_appInfo = new UkuiSearch::ApplicationInfo(this); m_appInfo->desktopFilePathFromName(QStringLiteral("kylin-aiassistant"), m_desktopFile); if (m_desktopFile.isEmpty()) { qWarning() << "AiAssistantButton: kylin-aiassistant desktop file not found"; } else { fetchIcon(); } connect(m_appInfo, &UkuiSearch::ApplicationInfo::appDBItems2BAdd, this, [this](const QStringList &desktopFiles) { for (const QString &desktopFile : desktopFiles) { if (desktopFile.endsWith(QStringLiteral("kylin-aiassistant.desktop"))) { m_appInfo->desktopFilePathFromName(QStringLiteral("kylin-aiassistant"), m_desktopFile); fetchIcon(); Q_EMIT availableChanged(); } } }); connect(m_appInfo, &UkuiSearch::ApplicationInfo::appDBItems2BDelete, this, [this](const QStringList &desktopFiles) { for (const QString &desktopFile: desktopFiles) { if (desktopFile.endsWith(QStringLiteral("kylin-aiassistant.desktop"))) { m_desktopFile.clear(); m_appInfo->desktopFilePathFromName(QStringLiteral("kylin-aiassistant"), m_desktopFile); if (!m_desktopFile.isEmpty()) { fetchIcon(); } Q_EMIT availableChanged(); } } }); connect(m_appInfo, &UkuiSearch::ApplicationInfo::appDBItems2BUpdate, this, [this](UkuiSearch::ApplicationInfoMap infoMap) { for (const QString &desktopFile : infoMap.keys()) { if (desktopFile == m_desktopFile) { auto props = infoMap[desktopFile]; if (props.contains(UkuiSearch::ApplicationProperty::Property::Icon)) { auto newicon = props[UkuiSearch::ApplicationProperty::Property::Icon].toString(); if (newicon != m_icon) { m_icon = newicon; Q_EMIT iconChanged(); } } break; } } }); initFunctionControl(); } AiAssistantButton::~AiAssistantButton() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-ai-assistant-v11")); } void AiAssistantButton::pressed() { qDebug() << "AiAssistantButton::pressed"; QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.ukui.kylin_aiassistant"), QStringLiteral("/org/ukui/kylin_aiassistant"), QStringLiteral("org.ukui.kylin_aiassistant"), QStringLiteral("showOrHideView")); auto watcher = new QDBusPendingCallWatcher(QDBusPendingCall(QDBusConnection::sessionBus().asyncCall(msg))); connect(watcher, &QDBusPendingCallWatcher::finished, this, [&] (QDBusPendingCallWatcher *self) { if (self->isError()) { qWarning() << "AiAssistantButton::pressed: failed to call showOrHideView" << self->error(); } self->deleteLater(); }); } bool AiAssistantButton::available() const { return !m_desktopFile.isEmpty(); } QString AiAssistantButton::icon() const { return m_icon; } bool AiAssistantButton::disableMouseLeftButton() const { return m_disableMouseLeftButton; } void AiAssistantButton::fetchIcon() { auto icon = m_appInfo->getInfo(m_desktopFile, UkuiSearch::ApplicationProperty::Property::Icon).toString(); if (icon != m_icon) { m_icon = icon; Q_EMIT iconChanged(); } } void AiAssistantButton::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-ai-assistant-v11")); onFunctionControlChanged(QStringLiteral("ukui-ai-assistant-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-ai-assistant-v11"), true); }); } void AiAssistantButton::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-ai-assistant-v11")) { return; } auto controlConfig = exit ? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "AiAssistantButton function control config:" << controlConfig; //是否禁用左键点击 if (controlConfig.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } } ukui-panel/widgets/ukui-menu-starter/0000775000175000017500000000000015167645111016630 5ustar fengfengukui-panel/widgets/ukui-menu-starter/i18n/0000775000175000017500000000000015167645111017407 5ustar fengfengukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_bo_CN.ts0000664000175000017500000001027115167645100025207 0ustar fengfeng StartMenuButton Lock Screen བརྙན་ཡོལ་དམིགས་འཛིན Switch User གློག་སྒོ་འབྱེད་པའི་སྤྱོད་མཁན Log Out དོར་བ Suspend ལས་མཚམས་བཞག་པ། Hibernate མངལ་གནས་སུ་སྦས་པ། Restart ཡང་བསྐྱར་འགོ་འཛུགས་ Time Shutdown དུས་གཏན་གནམ་གྲུ་སྒོ་རྒྱག་དགོས། Shut Down ལས་མཚམས་འཇོག Upgrade and Restart གསར་སྒྱུར་གལ་ཆེ་མཉམ་དུ་འཛིན་པ། Upgrade and Shut Down གསར་སྒྱུར་བྱས་པར་མ་ཟད་།ཁ་བརྒྱབ་། Estimated %1 hour %2 minutes སྔོན་དཔགས་བྱས་ན། ཆུ་ཚོད %1 དང་སྐར་མ %2 Estimated %1 minutes སྔོན་དཔགས་བྱས་ན། སྐར་མ %1 main Power Manager གློག་ཁུངས་དོ་དམ་ཆས་ About This Computer འཕྲུལ་ཆས་འདིའི་སྐོར། Network Settings དྲ་རྒྱའི་སྒྲིག་འགོད། System Monitor རྒྱུད་ཁོངས་སོ་ལྟ་ཆས། Control Center རྒྱུད་རིམ་ལྡན་པའི་སྒོ་ནས་སྒྲིག་ File Manager ཡིག་ཆའི་དོ་དམ་ཆས། Search སྤྱིའི་་བཤེར་འཚོལ། Open Terminal 打开终端 Switch User or Log Out ཐོ་ཁོངས་བརྗེ་བའམ་ཡང་ན་ཐོ་ཁོངས་ནས་བསུབ་དགོས། Power གློག་ཁུངས་བཅས་ཀྱི་རྣམ་གྲངས་འདེམས་དགོས། Show Desktop ཅོག་ཙེའི་ངོས་སུ་མངོན All Applications ཉེར་སྤྱོད་ཆ་ཚང་། ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_fr.ts0000664000175000017500000000505515167645100024642 0ustar fengfeng StartMenuButton Lock Screen Switch User Log Out Suspend Hibernate Restart Time Shutdown Shut Down main Power Manager About This Computer Network Settings System Monitor Control Center File Manager Search Open Terminal Switch User or Log Out Power Show Desktop All Applications ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_ky.ts0000664000175000017500000000630015167645100024650 0ustar fengfeng StartMenuButton Log Out بەكەر قىلىۋەتمەك Hibernate ۇيقۇ Suspend توقتوتۇۇ Restart قايرا قوزعوتۇۇ Shut Down جااپ جىبەرۉۉ Time Shutdown Lock Screen ەكىران قۇلۇپتوو Switch User ىشتەتۉۉچۉنۉ الماشتىرۇۇ Upgrade and Restart Upgrade and Shut Down Estimated %1 hour %2 minutes Estimated %1 minutes main Search ىزدۅۅ File Manager ۅجۅت ادمئنىستراتور Control Center Power System Monitor ساامالىق كۉزۅتكۉچ Show Desktop شىرە بەتىن كۅرسۅتۉۉ All Applications باردىق پراگراممالار Power Manager تۅك باشقارعىچ About This Computer Network Settings تور تەڭشەكتەرى Open Terminal Switch User or Log Out ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_tr.ts0000664000175000017500000000477615167645100024671 0ustar fengfeng StartMenuButton Log Out Log Out Hibernate DerinUyku Suspend Askıya Al Restart Yeniden Başlat Shut Down Bilgisayarı Kapat Lock Screen Switch User Time Shutdown main Search Ara File Manager Dosya Yöneticisi Control Center Power System Monitor Power Manager About This Computer Network Settings Open Terminal Switch User or Log Out Show Desktop All Applications ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_kk.ts0000664000175000017500000000636015167645100024640 0ustar fengfeng StartMenuButton Log Out بوس قىلىۋەتمەك Hibernate ۇيقى Suspend توقتاتۋ Restart قاتە قوزعالتۋ Shut Down وشىرۋ Time Shutdown ۋاقىتتى تاقاۋ Lock Screen ەكٸران قۇلپىلاۋ Switch User تۇتٸنۋشٸنٸ سايكەستىرۋ Upgrade and Restart Upgrade and Shut Down Estimated %1 hour %2 minutes Estimated %1 minutes main Search ٸزدەۋ File Manager حۇجات اكىمشى Control Center Power ۇقىق تالدانبالارٸ System Monitor سەستيما كۇزەتۋشى Show Desktop ۇستەل بەتىن كورسەتۋ All Applications بارلٸق پٸروگٸراممالار Power Manager توك باسقارۋشى About This Computer نۇ كومپيۋتەر جايىندا Network Settings تور تەڭشەۋلەرى Open Terminal ٸشٸۋ اقىرى Switch User or Log Out تۇتٸنۋشٸنٸ سايكەستىرۋ ياكي شەگىنۋ ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_mn.ts0000664000175000017500000001033715167645100024644 0ustar fengfeng StartMenuButton Lock Screen ᠳᠡᠯᠭᠡᠴᠡ ᠣᠨᠢᠰᠤᠯᠠᠬᠤ Switch User ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ᠎ᠶᠢ ᠰᠤᠯᠢᠬᠤ Log Out ᠬᠦᠴᠦᠨ ᠦᠭᠡᠶ ᠪᠣᠯᠭᠠᠬᠤ Suspend ᠵᠤᠭ᠍ᠰᠤᠭᠠᠬᠤ Hibernate ᠢᠴᠡᠬᠡᠯᠡᠬᠦ᠌ Restart ᠳᠠᠬᠢᠨ ᠡᠬᠢᠯᠡᠬᠦᠯᠬᠦ Time Shutdown ᠳᠤᠭᠳᠠᠭᠰᠠᠨ ᠴᠠᠭ ᠲᠤ᠌ ᠬᠠᠭᠠᠬᠤ Shut Down ᠮᠠᠰᠢᠨ ᠤᠨᠳᠠᠷᠠᠭᠠᠬᠤ Upgrade and Restart ᠰᠢᠨᠡᠳᠬᠡᠬᠦ ᠶᠢ ᠵᠡᠷᠭᠡᠪᠡᠷ ᠳᠠᠬᠢᠨ ᠡᠭᠢᠯᠡᠭᠦᠯᠦᠨ᠎ᠡ ᠃ Upgrade and Shut Down ᠰᠢᠨᠡᠳᠬᠡᠬᠦ ᠶᠢᠨ ᠬᠠᠮᠲᠤ ᠪᠠᠶᠢᠭᠤᠯᠤᠯᠭ᠎ᠠ ᠶᠢ ᠰᠢᠨᠡᠳᠬᠡᠨ᠎ᠡ ᠃ Estimated %1 hour %2 minutes ᠵᠢᠱᠢᠯᠲᠡ ᠪᠡᠷ ᠨᠢᠭᠡ ᠴᠠᠭ ᠢᠶᠠᠷ 2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ Estimated %1 minutes ᠵᠢᠱᠢᠯᠲᠡ ᠪᠡᠷ ᠨᠢᠭᠡ ᠮᠢᠨᠦᠢᠲ᠋ ᠃ main Power Manager ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠵᠢᠨ ᠬᠠᠮᠢᠶᠠᠷᠤᠯᠲᠠ ᠵᠢᠨ ᠪᠠᠭᠠᠵᠢ About This Computer ᠲᠤᠰ ᠮᠠᠰᠢᠨ ᠤ᠋ ᠲᠤᠬᠠᠢ Network Settings ᠰᠦᠯᠵᠢᠶᠡᠨ ᠤ᠋ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠭ᠎ᠠ System Monitor ᠰᠢᠰᠲ᠋ᠧᠮ᠎ᠦ᠋ᠨ ᠬᠢᠨᠠᠭᠤᠷ Control Center ᠡᠵᠡᠮᠳᠡᠯ ᠦᠨ ᠲᠥᠪ File Manager ᠹᠠᠢᠯ ᠤ᠋ᠨ ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠤᠷ Search ᠪᠦᠬᠦ ᠳᠠᠯ᠎ᠠ ᠪᠡᠷ ᠬᠠᠢᠬᠤ Open Terminal ᠦᠵᠦᠬᠦᠷᠯᠢᠭ ᠢ᠋ ᠨᠡᠬᠡᠬᠡᠬᠦ Switch User or Log Out ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ ᠵᠢ ᠰᠣᠯᠢᠬᠤ ᠪᠤᠶᠤ ᠳᠠᠩᠰᠠᠨ ᠡᠴᠡ ᠬᠠᠰᠤᠬᠤ Power ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠬᠦᠰᠬᠡᠭᠴᠢ ᠵᠢᠨ ᠰᠤᠩᠭᠤᠭᠳᠠᠬᠤᠨ Show Desktop ᠱᠢᠷᠡᠭᠡᠨ ᠨᠢᠭᠤᠷ ᠎ᠢ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ᠌ All Applications ᠪᠦᠬᠦ ᠬᠡᠷᠡᠭᠯᠡᠭᠡ ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_de.ts0000664000175000017500000000505515167645100024623 0ustar fengfeng StartMenuButton Lock Screen Switch User Log Out Suspend Hibernate Restart Time Shutdown Shut Down main Power Manager About This Computer Network Settings System Monitor Control Center File Manager Search Open Terminal Switch User or Log Out Power Show Desktop All Applications ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_es.ts0000664000175000017500000000505515167645100024642 0ustar fengfeng StartMenuButton Lock Screen Switch User Log Out Suspend Hibernate Restart Time Shutdown Shut Down main Power Manager About This Computer Network Settings System Monitor Control Center File Manager Search Open Terminal Switch User or Log Out Power Show Desktop All Applications ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_ug.ts0000664000175000017500000000627015167645100024646 0ustar fengfeng StartMenuButton Log Out بىكار قىلىۋەتمەك Hibernate ئۇيقۇدا Suspend ئېسىش Restart قايتا قوزغىتىش Shut Down تاقىۋېتىش Time Shutdown Lock Screen ئېكران قۇلۇپلاش Switch User ئىشلەتكۈچىنى ئالماشتۇرۇش Upgrade and Restart Upgrade and Shut Down Estimated %1 hour %2 minutes Estimated %1 minutes main Search ئىزدەش File Manager ھۆججەت باشقۇرغۇ Control Center Power System Monitor سىستېما كۆزەتكۈچ Show Desktop ئۈستەل يۈزىنى كۆرسىتىش All Applications بارلىق پروگراممىلار Power Manager توك باشقۇرغۇچ About This Computer Network Settings تور تەڭشەكلىرى Open Terminal Switch User or Log Out ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_zh_HK.ts0000664000175000017500000000566515167645100025245 0ustar fengfeng StartMenuButton Lock Screen 鎖定荧幕 Switch User 切換使用者 Log Out 註銷 Suspend 睡眠 Hibernate 休眠 Restart 重新啟動 Time Shutdown 定時關機 Shut Down 關閉電源 Upgrade and Restart 更新並重啟 Upgrade and Shut Down 更新並關機 Estimated %1 hour %2 minutes 預計 %1 小時 %2 分鐘 Estimated %1 minutes 預計 %1 分鐘 main Power Manager 電源管理 About This Computer 關於本機 Network Settings 網絡設置 System Monitor 系統監視器 Control Center 控制面板 File Manager 檔管理員 Search 搜索 Open Terminal 打開終端 Switch User or Log Out 切換用戶或註銷 Power 電源 Show Desktop 顯示桌面 All Applications 所有應用 ukui-panel/widgets/ukui-menu-starter/i18n/org.ukui.menu.starter_zh_CN.ts0000664000175000017500000000565115167645111025240 0ustar fengfeng StartMenuButton Log Out 注销 Hibernate 休眠 Suspend 睡眠 Restart 重启 Shut Down 关机 Time Shutdown 定时关机 Lock Screen 锁定屏幕 Switch User 切换用户 Upgrade and Restart 更新并重启 Upgrade and Shut Down 更新并关机 Estimated %1 hour %2 minutes 预计 %1 小时 %2 分钟 Estimated %1 minutes 预计 %1 分钟 main Search 搜索 File Manager 文件管理器 Control Center 系统设置 Power 电源 System Monitor 系统监视器 Show Desktop 显示桌面 All Applications 全部应用 Power Manager 电源管理 About This Computer 关于本机 Network Settings 网络设置 Open Terminal 打开终端 Switch User or Log Out 切换用户或注销 ukui-panel/widgets/ukui-menu-starter/widget/0000775000175000017500000000000015167645100020111 5ustar fengfengukui-panel/widgets/ukui-menu-starter/widget/ui/0000775000175000017500000000000015167645100020526 5ustar fengfengukui-panel/widgets/ukui-menu-starter/widget/ui/main.qml0000664000175000017500000001024615167645100022170 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.menu.starter 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal property real ratio: parent.ratio ? parent.ratio : 1 Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? height - mouseArea.anchors.topMargin - mouseArea.anchors.bottomMargin : width Layout.preferredHeight: isHorizontal ? height : width - mouseArea.anchors.leftMargin - mouseArea.anchors.rightMargin property bool isMiniLayout: isHorizontal && (height <= 36) Widget.active: StartMenuButton.currentScreen === Widget.container.screen ? StartMenuButton.menuWindowVisible : false // 更新tooltip Widget.tooltip: Widget.tooltip MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true Accessible.role: Accessible.Button Accessible.description: "This is a start menu button of ukui-panel" Accessible.name: "ukui-menu-starter" anchors { leftMargin: root.isHorizontal? 0 : 4 * root.ratio topMargin: isMiniLayout ? 2 * root.ratio : root.isHorizontal? 4 * root.ratio : 0 rightMargin: root.isHorizontal? 0 : 4 * root.ratio bottomMargin: isMiniLayout ? 2 * root.ratio : root.isHorizontal? 4 * root.ratio : 0 } DtThemeBackground { anchors.fill: parent radius: GlobalTheme.kRadiusNormal useStyleTransparency: false backgroundColor: mouseArea.containsPress ? GlobalTheme.kComponentAlphaClick : mouseArea.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kContainGeneralAlphaNormal Tooltip { id: tooltip anchors.fill: parent mainText: Widget.tooltip posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: root.isHorizontal ? 8 + mouseArea.anchors.topMargin : 8 + mouseArea.anchors.leftMargin } } Icon { anchors.fill: parent anchors.margins: isMiniLayout ? 2 * root.ratio : 4 * root.ratio source: "kylin-startmenu" scale: parent.containsPress ? 0.8 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } } acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: (mouse) => { if (mouse.button === Qt.LeftButton && !StartMenuButton.disableMouseLeftButton) { StartMenuButton.openStartMenu() } if (mouse.button === Qt.RightButton && !StartMenuButton.disableMouseRightButton) { StartMenuButton.openContextMenu(root) } } } } ukui-panel/widgets/ukui-menu-starter/widget/metadata.json0000775000175000017500000000374315167645100022576 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.menu.starter", "Icon": "ukui-menu", "Name": "ukui-menu-starter", "Name[zh_CN]": "开始菜单启动器", "Name[zh_HK]": "開始菜單啟動器", "Name[bo_CN]": "འགོ་འཛུགས་འདེམས་བྱང་འགོ་སློང་ཆས།", "Name[ug_CN]": "باشلاش تىزىملىكى قوزغاتقۇچى", "Name[kk_KZ]": "بباستاۋ تٸزٸمدٸگٸ قوزعالتۋ اسپابى", "Name[ky_KG]": "باشتوو تىزىمدىگى   قوزعوتۇۇچۇ", "Name[mn_MN]": "ᠡᠬᠢᠯᠡᠯᠲᠡ ᠶᠢᠨ ᠲᠣᠪᠶᠣᠭ ᠤᠨ ᠬᠥᠳᠡᠯᠭᠡᠭᠦᠷ", "Tooltip": "UKUI Menu", "Tooltip[zh_CN]": "开始菜单", "Tooltip[zh_HK]": "開始菜單", "Tooltip[bo_CN]": "འགོ་འཛུགས་འདེམས་བྱང་།", "Tooltip[ug_CN]": "باشلاش تىزىملىكىنى قوزغىتىش", "Tooltip[kk_KZ]": "باستاۋ تٸزٸمدٸكدٸ قوزعالتۋ", "Tooltip[ky_KG]": "باشتوو تىزىمدىگىن  قوزعوتۇۇ", "Tooltip[mn_MN]": "ᠡᠬᠢᠯᠡᠯᠲᠡ ᠶᠢᠨ ᠲᠣᠪᠶᠣᠭ", "Description": "Start ukui-menu", "Description[zh_CN]": "启动开始菜单", "Description[zh_HK]": "啟動開始菜單", "Description[bo_CN]": "འགོ་འཛུགས་འདེམས་བྱང་འགོ་སློང་།", "Description[ug_CN]": "باشلاش تىزىملىكىنى قوزغىتىش", "Description[kk_KZ]": "باستاۋ تٸزٸمدٸكدٸ قوزعالتۋ", "Description[ky_KG]": "باشتوو تىزىمدىگىن  قوزعوتۇۇ", "Description[mn_MN]": "ᠡᠬᠢᠯᠡᠯᠲᠡ ᠶᠢᠨ ᠲᠣᠪᠶᠣᠭ", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "All", "Contents": { "Main": "ui/main.qml", "I18n": "i18n/org.ukui.menu.starter" } } ukui-panel/widgets/ukui-menu-starter/CMakeLists.txt0000664000175000017500000000503315167645111021371 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-menu-starter VERSION 4.1) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # TODO: 将依赖倒入的操作放到顶级CMakeList文件中 find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick Widgets DBus LinguistTools REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick Widgets DBus LinguistTools REQUIRED) find_package(PkgConfig REQUIRED) find_package(ukui-quick COMPONENTS platform REQUIRED) find_package(ukui-search) set(EXTERNAL_LIBS "") if (QT_VERSION_MAJOR EQUAL "5") set(PC_PKGS gsettings-qt kysdk-systime) elseif (QT_VERSION_MAJOR EQUAL "6") set(PC_PKGS gsettings-qt6 kysdk-systime) endif() foreach(external_lib IN ITEMS ${PC_PKGS}) pkg_check_modules(${external_lib} REQUIRED IMPORTED_TARGET ${external_lib}) if(${${external_lib}_FOUND}) include_directories(${${external_lib}_INCLUDE_DIRS}) link_directories(${${external_lib}_LIBRARY_DIRS}) list(APPEND EXTERNAL_LIBS PkgConfig::${external_lib}) endif() endforeach() set(PROJECT_SOURCES plugin/start-menu-plugin.h plugin/start-menu-plugin.cpp plugin/start-menu-button.h plugin/start-menu-button.cpp ) file(GLOB TS_FILES i18n/*.ts) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) qt_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) else() qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG> ) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus ukui-quick::platform ukui-search ) set(PLUGIN_INSTALL_ROOT_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/menu/starter") install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.menu.starter") install(FILES ${QM_FILES} DESTINATION "/usr/share/ukui/widgets/org.ukui.menu.starter/i18n") install(FILES "plugin/qmldir" DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) ukui-panel/widgets/ukui-menu-starter/plugin/0000775000175000017500000000000015167645111020126 5ustar fengfengukui-panel/widgets/ukui-menu-starter/plugin/qmldir0000664000175000017500000000006615167645100021341 0ustar fengfengmodule org.ukui.menu.starter plugin ukui-menu-starter ukui-panel/widgets/ukui-menu-starter/plugin/start-menu-button.cpp0000664000175000017500000005522515167645111024253 0ustar fengfeng /* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "start-menu-button.h" #include #include #include #include #include #include #include #include #include #include #include #include #include StartMenuButton &StartMenuButton::self() { static StartMenuButton s_self; return s_self; } StartMenuButton::StartMenuButton(QObject *parent) : QObject(parent) { qRegisterMetaType>(); loadUserAction(); loadPowerAction(); connectGlobalInterface(); connectMenuInterface(); initFunctionControl(); m_applicationInfo = new UkuiSearch::ApplicationInfo(this); initAppLocalNames(); } StartMenuButton::~StartMenuButton() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-menu-starter-v11")); } void StartMenuButton::openStartMenu() { QDBusInterface interface("org.ukui.menu", "/org/ukui/menu", "org.ukui.menu", QDBusConnection::sessionBus()); interface.asyncCall(QStringLiteral("WinKeyResponse")); } void StartMenuButton::showDesktop() { UkuiQuick::WindowManager::setShowingDesktop(!UkuiQuick::WindowManager::showingDesktop()); } void StartMenuButton::execSessionAction(const QString &action) { QDBusInterface sessionManager("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", QDBusConnection::sessionBus()); sessionManager.asyncCall(action); } void StartMenuButton::onUserCountChange() { bool hasMultipleUsers {false}, canSwitch {false}; QDBusInterface displaynManager("org.freedesktop.DisplayManager", "/org/freedesktop/DisplayManager/Seat0", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply reply = displaynManager.call("Get", "org.freedesktop.DisplayManager.Seat", "CanSwitch"); canSwitch = (reply.isValid() && reply.value().toBool()); QDBusInterface interface("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", QDBusConnection::systemBus()); QDBusReply> getReply = interface.call(QStringLiteral("ListCachedUsers")); hasMultipleUsers = getReply.isValid() && getReply.value().toVector().size() > 1; if(hasMultipleUsers && canSwitch){ m_switchUserAction->setVisible(true); } else { m_switchUserAction->setVisible(false); } } void StartMenuButton::loadUserAction() { // sessionManager QDBusInterface sessionManager("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", QDBusConnection::sessionBus()); QDBusReply reply = sessionManager.call(QStringLiteral("canLockscreen")); if (reply.isValid() && reply.value()) { m_userActions << new QAction(QIcon::fromTheme("system-lock-screen-symbolic"), tr("Lock Screen"), this); connect(m_userActions.last(), &QAction::triggered, this, [this] { UkuiQuick::AppLauncher::instance()->runCommand("ukui-screensaver-command -l"); }); } if(!m_switchUserAction){ m_switchUserAction = new QAction(QIcon::fromTheme("system-users-symbolic"), tr("Switch User"), this); connect(m_switchUserAction, &QAction::triggered, this, [this] { execSessionAction(QStringLiteral("switchUser")); }); } m_userActions << m_switchUserAction; reply = sessionManager.call(QStringLiteral("canLogout")); if (reply.isValid() && reply.value()) { m_userActions << new QAction(QIcon::fromTheme("system-log-out-symbolic"), tr("Log Out"), this); connect(m_userActions.last(), &QAction::triggered, this, [this] { execSessionAction(QStringLiteral("logout")); }); } onUserCountChange(); QDBusConnection::systemBus().connect(ACCOUNTS_SERVICE_NAME, ACCOUNTS_SERVICE_PATH, ACCOUNTS_SERVICE_INTERFACE, "UserAdded",this,SLOT(onUserCountChange())); QDBusConnection::systemBus().connect(ACCOUNTS_SERVICE_NAME, ACCOUNTS_SERVICE_PATH, ACCOUNTS_SERVICE_INTERFACE, "UserDeleted",this,SLOT(onUserCountChange())); } void StartMenuButton::loadPowerAction() { QDBusInterface sessionManager("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", QDBusConnection::sessionBus()); QDBusReply reply = sessionManager.call(QStringLiteral("canSuspend")); if (reply.isValid() && reply.value()) { m_powerActions << new QAction(QIcon::fromTheme("ukui-sleep-symbolic"), tr("Suspend"), this); connect(m_powerActions.last(), &QAction::triggered, this, [this] { execSessionAction(QStringLiteral("suspend")); }); } reply = sessionManager.call(QStringLiteral("canHibernate")); if (reply.isValid() && reply.value()) { m_powerActions << new QAction(QIcon::fromTheme("ukui-hibernate-symbolic"), tr("Hibernate"), this); connect(m_powerActions.last(), &QAction::triggered, this, [this] { execSessionAction(QStringLiteral("hibernate")); }); } const QByteArray id("org.ukui.time-shutdown.settings"); if (QGSettings::isSchemaInstalled(id)) { m_powerActions << new QAction(QIcon::fromTheme("timer-symbolic"), tr("Time Shutdown"), this); connect(m_powerActions.last(), &QAction::triggered, this, [this] { UkuiQuick::AppLauncher::instance()->runCommand("time-shutdown"); }); } //更新并关机 bool isUpgradable = canUpgrade(); //存在更新时是否隐藏关机和重启 bool isNeedToHide = checkHideUpdate(); if (!m_upgradeShutdownAct) { m_upgradeShutdownAct = new QAction(QIcon::fromTheme("system-upd-shutdown-symbolic"), tr("Upgrade and Shut Down"), this); m_upgradeShutdownAct->setVisible(isUpgradable); m_upgradeShutdownAct->setToolTip(minutesToHour(m_estimatedLeftMinutes)); m_powerActions.append(m_upgradeShutdownAct); connect(m_upgradeShutdownAct, &QAction::triggered, this, [this] { execUpgradeAction("shutdown"); }); } //关机 reply = sessionManager.call(QStringLiteral("canPowerOff")); if (reply.isValid() && reply.value() && !m_shutdownAct) { m_shutdownAct = new QAction(QIcon::fromTheme("system-shutdown-symbolic"), tr("Shut Down"), this); m_shutdownAct->setVisible(!(isUpgradable && isNeedToHide)); m_powerActions.append(m_shutdownAct); connect(m_shutdownAct, &QAction::triggered, this, [this] { execSessionAction(QStringLiteral("powerOff")); }); } //更新并重启 if (!m_upgradeRebootAct) { m_upgradeRebootAct = new QAction(QIcon::fromTheme("system-upd-reboot-symbolic"), tr("Upgrade and Restart"), this); m_upgradeRebootAct->setVisible(isUpgradable); m_upgradeRebootAct->setToolTip(minutesToHour(m_estimatedLeftMinutes)); m_powerActions.append(m_upgradeRebootAct); connect(m_upgradeRebootAct, &QAction::triggered, this, [this] { execUpgradeAction("reboot"); }); } //重启 reply = sessionManager.call(QStringLiteral("canReboot")); if (reply.isValid() && reply.value() && !m_rebootAct) { m_rebootAct = new QAction(QIcon::fromTheme("system-reboot-symbolic"), tr("Restart"), this); m_rebootAct->setVisible(!(isUpgradable && isNeedToHide)); m_powerActions.append(m_rebootAct); connect(m_rebootAct, &QAction::triggered, this, [this] { execSessionAction(QStringLiteral("reboot")); }); } QDBusConnection::systemBus().connect(SYSTEMUPGRADE_SERVICE, SYSTEMUPGRADE_PATH, SYSTEMUPGRADE_INTERFACE, "UpdateDownloadFinished",this,SLOT(onUpdateDownloadFinished())); } void StartMenuButton::openGlobalSearch() { if (m_searchInterface) { m_searchInterface->asyncCall(QStringLiteral("mainWindowSwitch")); } else { qDebug() << "Can't connect to ukui-search DBus!"; UkuiQuick::AppLauncher::instance()->launchApp("/usr/share/applications/ukui-search-menu.desktop"); } } QString StartMenuButton::getAppLocalName(QString desktop) { return m_appLocalNames.value(desktop); } void StartMenuButton::openContextMenu(QQuickItem *item) { QMenu *menu = new QMenu; menu->setAttribute(Qt::WA_DeleteOnClose); //电源管理 QAction *powerManager = new QAction(QIcon::fromTheme("battery-symbolic"), tr("Power Manager"), menu); connect(powerManager, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->runCommand("ukui-control-center -m power"); }); menu->addAction(powerManager); //关于本机 QAction *aboutThisComputer = new QAction(QIcon::fromTheme("help-about-symbolic"), tr("About This Computer"), menu); connect(aboutThisComputer, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->runCommand("ukui-control-center -m about"); }); menu->addAction(aboutThisComputer); //网络设置 QAction *networkSettings = new QAction(QIcon::fromTheme("network-wired-symbolic"), tr("Network Settings"), menu); connect(networkSettings, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->runCommand("ukui-control-center -m netconnect"); }); menu->addAction(networkSettings); //分隔符 menu->addSeparator(); //系统监视器 QAction *systemMonitor = new QAction(QIcon::fromTheme("ukui-system-monitor"), getAppLocalName("ukui-system-monitor"), menu); connect(systemMonitor, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->launchApp("/usr/share/applications/ukui-system-monitor.desktop"); }); menu->addAction(systemMonitor); //设置 QAction *controlCenter = new QAction(QIcon::fromTheme("ukui-control-center"), getAppLocalName("ukui-control-center"), menu); connect(controlCenter, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->launchApp("/usr/share/applications/ukui-control-center.desktop"); }); menu->addAction(controlCenter); //文件管理器 QAction *fileManager = new QAction(QIcon::fromTheme("system-file-manager"), getAppLocalName("peony"), menu); connect(fileManager, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->launchApp("/usr/share/applications/peony.desktop"); }); menu->addAction(fileManager); //搜索 QAction *search = new QAction(QIcon::fromTheme("kylin-search"), tr("Search"), menu); connect(search, &QAction::triggered, this, &StartMenuButton::openGlobalSearch); menu->addAction(search); //终端 QAction *terminal = new QAction(QIcon::fromTheme("utilities-terminal"), getAppLocalName("mate-terminal"), menu); connect(terminal, &QAction::triggered, []() { UkuiQuick::AppLauncher::instance()->runCommand("/usr/bin/x-terminal-emulator"); }); menu->addAction(terminal); //分隔符 menu->addSeparator(); //切换用户或注销子菜单 if (!m_userActions.isEmpty()) { QMenu *userSubMenu = new QMenu(tr("Switch User or Log Out"), menu); userSubMenu->addActions(m_userActions); QAction *userMenuAction = menu->addMenu(userSubMenu); userMenuAction->setIcon(QIcon::fromTheme("user-available-symbolic")); } //电源子菜单 if (!m_powerActions.isEmpty()) { QMenu *powerSubMenu = new QMenu(tr("Power"), menu); powerSubMenu->addActions(m_powerActions); QAction *powerMenuAction = menu->addMenu(powerSubMenu); powerMenuAction->setIcon(QIcon::fromTheme("system-shutdown-symbolic")); } //显示桌面 QAction *showDesktop = new QAction(QIcon::fromTheme("desktop-symbolic"), tr("Show Desktop"), menu); connect(showDesktop, &QAction::triggered, this, &StartMenuButton::showDesktop); menu->addAction(showDesktop); //分隔符 menu->addSeparator(); //所有应用 QAction *allApps = new QAction(QIcon::fromTheme("preferences-desktop-apps-symbolic"), tr("All Applications"), menu); connect(allApps, &QAction::triggered, this, &StartMenuButton::openStartMenu); menu->addAction(allApps); //设置父窗口 menu->winId(); if(menu->windowHandle()) { menu->windowHandle()->setTransientParent(item->window()); } menu->popup(QCursor::pos()); } bool StartMenuButton::disableMouseLeftButton() const { return m_disableMouseLeftButton; } bool StartMenuButton::disableMouseRightButton() const { return m_disableMouseRightButton; } QScreen* StartMenuButton::currentScreen() const { return m_currentScreen; } bool StartMenuButton::menuWindowVisible() const { return m_menuWindowVisible; } void StartMenuButton::connectGlobalInterface() { UkuiQuick::DbusConnector *dbusCon = new UkuiQuick::DbusConnector("com.ukui.search.service", "/", "org.ukui.search.service", QDBusConnection::sessionBus()); connect(dbusCon, &UkuiQuick::DbusConnector::ready, this, [this](QDBusInterface *dbus) { m_searchInterface = dbus; }); dbusCon->start(); } void StartMenuButton::connectMenuInterface() { UkuiQuick::DbusConnector *dbusCon = new UkuiQuick::DbusConnector("org.ukui.menu", "/org/ukui/menu", "org.freedesktop.DBus.Properties", QDBusConnection::sessionBus()); connect(dbusCon, &UkuiQuick::DbusConnector::ready, this, [this](QDBusInterface *interface) { if (!interface || !interface->isValid()) return; m_menuInterface = interface; getMenuVisible(); if (!QDBusConnection::sessionBus().connect("org.ukui.menu", "/org/ukui/menu", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(onMenuPropertiesChanged(QString, QVariantMap, QStringList)))) { qWarning() << "MenuStarter: QDBusConnection::sessionBus() connect onPropertiesChanged failed"; } }); dbusCon->start(); } void StartMenuButton::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-menu-starter-v11")); onFunctionControlChanged(QStringLiteral("ukui-menu-starter-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-menu-starter-v11"), true); }); } void StartMenuButton::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-menu-starter-v11")) { return; } auto controlConfig = exit ? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "StartMenuButton function control config:" << controlConfig; //是否禁用左键点击 if (controlConfig.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } //是否禁用右键点击 if (controlConfig.contains(QStringLiteral("disableMouseRightButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseRightButton")).toBool(); if (disable != m_disableMouseRightButton) { m_disableMouseRightButton = disable; Q_EMIT disableMouseRightButtonChanged(); } } else { m_disableMouseRightButton = false; Q_EMIT disableMouseRightButtonChanged(); } } bool StartMenuButton::canUpgrade() { QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMUPGRADE_SERVICE, SYSTEMUPGRADE_PATH, SYSTEMUPGRADE_INTERFACE, CHECK_INSTALL_REQUIRED); QDBusMessage res = QDBusConnection::systemBus().call(msg); if (res.type() == QDBusMessage::ReplyMessage && res.arguments().count() > 1) { m_estimatedLeftMinutes = res.arguments().at(1).toInt(); return res.arguments().at(0).toBool(); } return false; } QString StartMenuButton::minutesToHour(int estmateTime) { if (estmateTime > 60) { int hour = estmateTime / 60; int min = estmateTime % 60; return tr("Estimated %1 hour %2 minutes").arg(hour).arg(min); } else if (estmateTime > 0) { return tr("Estimated %1 minutes").arg(estmateTime); } return {}; } bool StartMenuButton::checkHideUpdate() { QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMUPGRADE_SERVICE, SYSTEMUPGRADE_PATH, SYSTEMUPGRADE_INTERFACE, CHECK_HIDE_UPDATE); QDBusMessage res = QDBusConnection::systemBus().call(msg); if (res.type() == QDBusMessage::ReplyMessage) { return res.arguments().at(0).toBool(); } qWarning() << "Call 'com.kylin.systemupgrade' interface method 'CheckHideUpdate' failed" << res.errorMessage(); return false; } void StartMenuButton::getCurrentScreen() { QScreen* screen = UkuiQuick::WindowProxy::currentScreen(); if (m_currentScreen == screen) return; m_currentScreen = screen; Q_EMIT currentScreenChanged(); } void StartMenuButton::getMenuVisible() { bool menuWindowVisible = false; if (!m_menuInterface || !m_menuInterface->isValid()) { qWarning() << "MenuStarter: menu interface is not valid"; } else { QDBusReply result = m_menuInterface->call("Get", "org.ukui.menu", "Visible"); if (result.isValid()) { menuWindowVisible = result.value().toBool(); } else { qWarning() << "MenuStarter: call get('Visible') failed: " << result.error().name() << result.error().message(); } } if (m_menuWindowVisible != menuWindowVisible) { m_menuWindowVisible = menuWindowVisible; if (m_menuWindowVisible) { getCurrentScreen(); } Q_EMIT menuWindowVisibleChanged(); } } void StartMenuButton::initAppLocalNames() { if (!m_applicationInfo) return; QHash appNames = { {"ukui-system-monitor", tr("System Monitor")}, {"ukui-control-center", tr("Control Center")}, {"peony", tr("File Manager")}, {"mate-terminal", tr("Open Terminal")} }; for (const QString& appName : appNames.keys()) { QString fullPath; m_applicationInfo->desktopFilePathFromName(appName, fullPath); if (!fullPath.isEmpty()) { QVariant localName = m_applicationInfo->getInfo(fullPath, UkuiSearch::ApplicationProperty::Property::LocalName); m_appLocalNames.insert(appName, localName.toString()); } else { qWarning() << "Can't get desktop file path from name:" << appName; m_appLocalNames.insert(appName, appNames.value(appName)); } } } void StartMenuButton::execUpgradeAction(const QString &action) { QDBusInterface interface(SYSTEMUPGRADE_SERVICE, SYSTEMUPGRADE_PATH, SYSTEMUPGRADE_INTERFACE, QDBusConnection::systemBus()); if (interface.isValid()) { interface.asyncCall(TRIGGER_INSTALL_ON_SHUTDOWN, action); } else { qCritical() << "'com.kylin.systemupgrade' interface is invalid!" << QDBusConnection::systemBus().lastError().message(); } } void StartMenuButton::onUpdateDownloadFinished() { qDebug() << "Update download finished. Add two actions in Power Option"; bool isUpgradable = canUpgrade(); if (m_upgradeRebootAct) { m_upgradeRebootAct->setVisible(isUpgradable); m_upgradeRebootAct->setToolTip(minutesToHour(m_estimatedLeftMinutes)); } if (m_upgradeShutdownAct) { m_upgradeShutdownAct->setVisible(isUpgradable); m_upgradeShutdownAct->setToolTip(minutesToHour(m_estimatedLeftMinutes)); } bool isNeedToHide = checkHideUpdate(); qDebug() << "Update download finished. Hide shutdown and reboot or not: " << isNeedToHide; if (m_rebootAct) m_rebootAct->setVisible(isNeedToHide); if (m_shutdownAct) m_shutdownAct->setVisible(isNeedToHide); } void StartMenuButton::onMenuPropertiesChanged(QString interface, QVariantMap property, QStringList list) { Q_UNUSED(list) if (interface != "org.ukui.menu") return; if (property.keys().contains("Visible")) { bool menuWindowVisible = property.value("Visible").toBool(); if (m_menuWindowVisible != menuWindowVisible) { m_menuWindowVisible = menuWindowVisible; if (m_menuWindowVisible) { getCurrentScreen(); } Q_EMIT menuWindowVisibleChanged(); } } } ukui-panel/widgets/ukui-menu-starter/plugin/start-menu-plugin.h0000664000175000017500000000206715167645100023675 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_START_MENU_PLUGIN_H #define UKUI_PANEL_START_MENU_PLUGIN_H #include class StartMenuPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif //UKUI_PANEL_START_MENU_PLUGIN_H ukui-panel/widgets/ukui-menu-starter/plugin/start-menu-plugin.cpp0000664000175000017500000000215315167645100024224 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "start-menu-plugin.h" #include "start-menu-button.h" #include "qqml.h" void StartMenuPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.menu.starter")); qmlRegisterSingletonType(uri, 1, 0, "StartMenuButton", [] (QQmlEngine *, QJSEngine *) -> QObject* { return &StartMenuButton::self(); }); } ukui-panel/widgets/ukui-menu-starter/plugin/start-menu-button.h0000664000175000017500000001035715167645111023715 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_START_MENU_BUTTON_H #define UKUI_PANEL_START_MENU_BUTTON_H #include #include #include #include #include #define ACCOUNTS_SERVICE_NAME "org.freedesktop.Accounts" #define ACCOUNTS_SERVICE_PATH "/org/freedesktop/Accounts" #define ACCOUNTS_SERVICE_INTERFACE "org.freedesktop.Accounts" //系统更新 #define SYSTEMUPGRADE_SERVICE "com.kylin.systemupgrade" #define SYSTEMUPGRADE_PATH "/com/kylin/systemupgrade" #define SYSTEMUPGRADE_INTERFACE "com.kylin.systemupgrade.interface" #define CHECK_INSTALL_REQUIRED "CheckInstallRequired" #define CHECK_HIDE_UPDATE "CheckHideUpdate" #define TRIGGER_INSTALL_ON_SHUTDOWN "TriggerInstallOnShutdown" class QAction; class StartMenuButton : public QObject { Q_OBJECT Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) Q_PROPERTY(bool disableMouseRightButton READ disableMouseRightButton NOTIFY disableMouseRightButtonChanged) Q_PROPERTY(QScreen* currentScreen READ currentScreen NOTIFY currentScreenChanged) Q_PROPERTY(bool menuWindowVisible READ menuWindowVisible NOTIFY menuWindowVisibleChanged) public: explicit StartMenuButton(QObject *parent=nullptr); static StartMenuButton &self(); ~StartMenuButton() override; Q_INVOKABLE void openStartMenu(); Q_INVOKABLE void showDesktop(); Q_INVOKABLE void openGlobalSearch(); Q_INVOKABLE void openContextMenu(QQuickItem *item); bool disableMouseLeftButton() const; bool disableMouseRightButton() const; QScreen* currentScreen() const; bool menuWindowVisible() const; Q_SIGNALS: void disableMouseLeftButtonChanged(); void disableMouseRightButtonChanged(); void currentScreenChanged(); void menuWindowVisibleChanged(); public Q_SLOTS: void execSessionAction(const QString &action); void onUserCountChange(); void onFunctionControlChanged(const QString& name, bool exit = false); void execUpgradeAction(const QString &action); void onUpdateDownloadFinished(); void onMenuPropertiesChanged(QString interface, QVariantMap property, QStringList list); // TODO: Reload Config // void reloadActions(); private: void loadUserAction(); void loadPowerAction(); void connectGlobalInterface(); void connectMenuInterface(); void initFunctionControl(); //检测是否需要更新 bool canUpgrade(); QString minutesToHour(int estmateTime); //检测有更新时是否需要隐藏关机和重启选项 bool checkHideUpdate(); void getCurrentScreen(); void getMenuVisible(); void initAppLocalNames(); QString getAppLocalName(QString desktop); private: QList m_userActions; QList m_powerActions; QAction* m_switchUserAction {nullptr}; QDBusInterface *m_searchInterface {nullptr}; UkuiSearch::ApplicationInfo *m_applicationInfo{nullptr}; QDBusInterface *m_menuInterface {nullptr}; bool m_disableMouseLeftButton = false; bool m_disableMouseRightButton = false; QScreen* m_currentScreen = nullptr; bool m_menuWindowVisible = false; //检测更新并重启和更新并关机预计剩余时间(单位:分钟) int m_estimatedLeftMinutes = 0; QAction *m_upgradeRebootAct {nullptr}; QAction *m_upgradeShutdownAct {nullptr}; QAction *m_rebootAct {nullptr}; QAction *m_shutdownAct {nullptr}; QHash m_appLocalNames; }; #endif //UKUI_PANEL_START_MENU_BUTTON_H ukui-panel/widgets/ukui-panel-separator/0000775000175000017500000000000015167645100017275 5ustar fengfengukui-panel/widgets/ukui-panel-separator/widget/0000775000175000017500000000000015167645100020560 5ustar fengfengukui-panel/widgets/ukui-panel-separator/widget/ui/0000775000175000017500000000000015167645111021177 5ustar fengfengukui-panel/widgets/ukui-panel-separator/widget/ui/main.qml0000664000175000017500000000332215167645111022636 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? 1 : width Layout.preferredHeight: isHorizontal ? height : 1 StyleBackground { useStyleTransparency: false alpha: 0.3 paletteRole: Theme.ButtonText anchors.centerIn: parent // anchors.fill: parent width: root.isHorizontal ? parent.width : parent.width * 0.5 height: root.isHorizontal ? parent.height * 0.5 : parent.height // anchors.leftMargin: root.isHorizontal ? 0 : 8 // anchors.rightMargin: root.isHorizontal ? 0 : 8 // // anchors.topMargin: root.isHorizontal ? 8 : 0 // anchors.bottomMargin: root.isHorizontal ? 8 : 0 } } ukui-panel/widgets/ukui-panel-separator/widget/metadata.json0000664000175000017500000000076415167645100023242 0ustar fengfeng{ "Authors": [ { "Name": "hxf", "Email": "hewenfei@kylinos.cn" } ], "Id": "org.ukui.panel.separator", "Icon": "ukui-panel", "Name": "Separator", "Name[zh_CN]": "分隔线", "Tooltip": "", "Tooltip[zh_CN]": "", "Description": "Separator", "Description[zh_CN]": "分隔线", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "Contents": { "Main": "ui/main.qml" } } ukui-panel/widgets/ukui-panel-separator/CMakeLists.txt0000664000175000017500000000025415167645100022036 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel-separator VERSION 4.1) install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.separator") ukui-panel/widgets/ukui-panel-calendar/0000775000175000017500000000000015167645111017050 5ustar fengfengukui-panel/widgets/ukui-panel-calendar/i18n/0000775000175000017500000000000015167645100017625 5ustar fengfengukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_de.ts0000664000175000017500000000165115167645100025261 0ustar fengfeng Calendar new notification new notifications Notification center main Set Time and Date Open Set up notification center ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_es.ts0000664000175000017500000000165115167645100025300 0ustar fengfeng Calendar new notification new notifications Notification center main Set Time and Date Open Set up notification center ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_bo_CN.ts0000664000175000017500000000220015167645100025640 0ustar fengfeng Calendar new notification བརྡ་ཐོ། new notifications བརྡ་ཐོ། Notification center ལྟེ་གནས་ལ་བརྡ་ཐོ་གཏོང main Set Time and Date དུས་ཚོད་ཀྱི་ཚེས་གྲངས་བཀོད་སྒྲིག་བྱ། Open ཁ་ཕྱེ་བ། Set up notification center བརྡ་ཐོའི་ལྟེ་གནས་འཛུགས་དགོས། ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_zh_CN.ts0000664000175000017500000000162015167645100025666 0ustar fengfeng Calendar new notification 条新通知 new notifications 条新通知 Notification center 通知中心 main Set Time and Date 设置时间日期 Open 打开 Set up notification center 设置通知中心 ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_ky.ts0000664000175000017500000000172515167645100025316 0ustar fengfeng Calendar new notification حابارلاۋ new notifications حابارلاۋ Notification center حابارلاۋ كىندىك main Set Time and Date ۇباقىت، چىسلا بەلگىلۅۅ Open اچۇۇ Set up notification center سالۋ حابارلاۋ كىندىك ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_kk.ts0000664000175000017500000000172415167645100025277 0ustar fengfeng Calendar new notification حابارلاۋ new notifications حابارلاۋ Notification center حابارلاۋ كىندىك main Set Time and Date ۋاقىت، چيسىلا بەلگٸلەۋ Open ٸشٸۋ Set up notification center سالۋ حابارلاۋ كىندىك ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_mn.ts0000664000175000017500000000211115167645100025273 0ustar fengfeng Calendar new notification ᠮᠡᠳᠡᠭᠳᠡᠯ new notifications ᠮᠡᠳᠡᠭᠳᠡᠯ Notification center ᠮᠡᠳᠡᠭᠳᠡᠯ main Set Time and Date ᠴᠠᠭ ᠡᠳᠦᠷ ᠰᠠᠷ᠎ᠠ᠎ᠶᠢᠨ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠤᠯᠳᠠ Open ᠨᠡᠬᠡᠬᠡᠬᠦ Set up notification center ᠮᠡᠳᠡᠭᠳᠡᠬᠦ ᠲᠦᠪ᠎ᠢ᠋ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_fr.ts0000664000175000017500000000165115167645100025300 0ustar fengfeng Calendar new notification new notifications Notification center main Set Time and Date Open Set up notification center ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_ug.ts0000664000175000017500000000174515167645100025310 0ustar fengfeng Calendar new notification ئۇقتۇرۇش new notifications ئۇقتۇرۇش Notification center ئۇقتۇرۇش مەركىزى main Set Time and Date ۋاقىت، چېسلا بەلگىلەش Open ئېچىش Set up notification center ئۇقتۇرۇش مەركىزى تەسىس قىلىش ukui-panel/widgets/ukui-panel-calendar/i18n/org.ukui.panel.calendar_zh_HK.ts0000664000175000017500000000162015167645100025670 0ustar fengfeng Calendar new notification 條新通知 new notifications 條新通知 Notification center 通知中心 main Set Time and Date 設置時間日期 Open 打開 Set up notification center 設置通知中心 ukui-panel/widgets/ukui-panel-calendar/widget/0000775000175000017500000000000015167645100020331 5ustar fengfengukui-panel/widgets/ukui-panel-calendar/widget/ui/0000775000175000017500000000000015167645100020746 5ustar fengfengukui-panel/widgets/ukui-panel-calendar/widget/ui/main.qml0000664000175000017500000002667515167645100022425 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * zy-yuan1 */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.items 1.0 import org.ukui.panel.calendar 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation === Types.Horizontal property real ratio: parent.ratio ? parent.ratio : 1 property bool isInTopBar: isHorizontal && (root.height <= 36) Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? layout.width : width Layout.preferredHeight: isHorizontal ? height : layout.height onWidthChanged: { if (!isHorizontal) { updateText(); } } onHeightChanged: { if (isHorizontal) { updateText(); } } onIsInTopBarChanged: { updateText(); } Component.onCompleted: { updateText(); //isClearRedpoint(); } Calendar { id: calendar onTimeUpdated: { updateText(); } } function updateText() { //单行显示 if (isInTopBar) { dateText.text = textInOneline(); return; } //多行显示 let text = calendar.time; //time ap let s = text; if (isOverFlow(s)) { if (s.match(" ")) { var parts = text.split(" "); text = parts[0]; for (var i = 1; i < parts.length; ++ i) { text += "\n" + parts[i]; } } else { var match = s.match(/[0-9]/); if (match) { text = s.slice(0, match.index) + "\n" + s.slice(match.index) } } } // week text += (isHorizontal ? " " : "\n") + calendar.week; // year text += ("\n" + calendar.year); // month s = calendar.year + " " + calendar.month; text += (isOverFlow(s) ? "\n" : calendar.separator) + calendar.month; dateText.text = text; } function isOverFlow(string) { if (isHorizontal) { return false; } let temp = tempText.createObject(root, {text: string}); let tempWidth = temp.contentWidth; temp.destroy(); return tempWidth >= (root.width - 4); } Component { id: tempText Text { width: root.width - 4 height: contentHeight fontSizeMode: Text.HorizontalFit opacity: 0 } } function textInOneline() { let text = calendar.time + " " + calendar.week + " " + calendar.year + calendar.separator + calendar.month; return text; } GridLayout { id: layout height: { if (isHorizontal) return parent.height; } width: { if (!isHorizontal) return parent.width; } rows: isHorizontal? 1 : 2 columns: isHorizontal ? 2 : 1 columnSpacing: 0 rowSpacing: 0 DtThemeBackground { id: backGround Accessible.role: Accessible.Button Accessible.description: "This is a calendar button of ukui-panel" Accessible.name: "ukui-panel_calendar_button" Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? dateText.contentWidth + 8 : width Layout.preferredHeight: isHorizontal ? height : dateText.contentHeight + 4 Layout.rightMargin: isHorizontal ? 0 : 4 * ratio Layout.leftMargin: isHorizontal ? 0 : 4 * ratio Layout.topMargin: isInTopBar ? 2 * ratio : isHorizontal ? 4 * ratio : 0 Layout.bottomMargin: isInTopBar ? 2 * ratio : isHorizontal ? 4 * ratio : 0 clip: true useStyleTransparency: false backgroundColor: mouseArea.containsPress ? GlobalTheme.kComponentAlphaClick : mouseArea.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kContainGeneralAlphaNormal radius: iconBackGround.radius DtThemeText { id: dateText anchors.centerIn: parent verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter width: isHorizontal ? contentWidth : parent.width - 4 height: isHorizontal ? parent.height - 4 : contentHeight fontSizeMode: isHorizontal ? Text.VerticalFit : Text.HorizontalFit minimumPointSize: 1 } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton Tooltip { anchors.fill: parent mainText: calendar.tooltipText posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: isHorizontal ? 8 + backGround.Layout.topMargin : 8 + backGround.Layout.leftMargin } Menu { id: calendarMenu transientParent: parent content: [ MenuItem { icon: "system-settings-symbolic" text: qsTr("Set Time and Date") onClicked: function () { AppLauncher.launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", ["-m", "Date"]); } } ] } onClicked: { // TODO: open calendar if (mouse.button === Qt.RightButton && !calendar.disableMouseRightButton) { calendarMenu.open(); } else if (mouse.button === Qt.LeftButton && !calendar.disableMouseLeftButton){ calendar.activeCalendar(); } } } } DtThemeBackground { id: iconBackGround Accessible.role: Accessible.Button Accessible.description: "This is a sidebar button of ukui-panel" Accessible.name: "ukui-panel sidebar button" Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.rightMargin: isHorizontal ? 0 : 4 * ratio Layout.leftMargin: isHorizontal ? 0 : 4 * ratio Layout.topMargin: isHorizontal ? 4 * ratio : 0 Layout.bottomMargin: isHorizontal ? 4 * ratio : 0 useStyleTransparency: false backgroundColor: iconMouseArea.containsPress ? GlobalTheme.kComponentAlphaClick : iconMouseArea.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kContainGeneralAlphaNormal radius: isInTopBar ? 0 : GlobalTheme.kRadiusNormal // 任务栏内容区域默认高度是44 property real iconZoom: isHorizontal ? (root.height / 44) * 8 : (root.width / 44) * 8 Layout.preferredWidth: isInTopBar ? root.height : (isHorizontal ? Math.ceil(iconZoom * 4) : Math.ceil(iconZoom * 5)) Layout.preferredHeight: isInTopBar ? root.height : (isHorizontal ? Math.ceil(iconZoom * 5) : Math.ceil(iconZoom * 4)) Icon { id: icon anchors.centerIn: parent property bool isClearRedpoint: calendar.unreadMsgCount <= 0 width: isInTopBar ? parent.width - 8 : Math.ceil(parent.iconZoom * 2) height: width source: isClearRedpoint ? "ukui-tool-symbolic" : "ukui-tool-box-null-symbolic" mode: Icon.AutoHighlight } MouseArea { id: iconMouseArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton Tooltip { anchors.fill: parent mainText: String(calendar.notifyIconTooltipText) posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: isHorizontal ? 8 + iconBackGround.Layout.topMargin : 8 + iconBackGround.Layout.leftMargin } Menu { id: notiMenu transientParent: parent content: [ MenuItem { icon: "ukui-tool-symbolic" text: qsTr("Open") onClicked: calendar.openSidebar() }, MenuItem { icon: "system-settings-symbolic" text: qsTr("Set up notification center") onClicked: function () { AppLauncher.launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", ["-m", "Notice"]); } } ] } onClicked: { if (mouse.button === Qt.LeftButton && !calendar.disableMouseLeftButton) { calendar.openSidebar(); } else if (mouse.button === Qt.RightButton && !calendar.disableMouseRightButton) { notiMenu.open(); } } } } } } ukui-panel/widgets/ukui-panel-calendar/widget/metadata.json0000775000175000017500000000205515167645100023011 0ustar fengfeng{ "Authors": [ { "Name": "hxf", "Email": "hewenfei@kylinos.cn" } ], "Id": "org.ukui.panel.calendar", "Icon": "ukui-calendar", "Name": "Calendar", "Name[zh_CN]": "日历", "Name[zh_HK]": "日曆", "Name[bo_CN]": "ལོ་ཐོ།", "Name[ug_CN]": "كالېندار", "Name[kk_KZ]": "كالەندٸر", "Name[ky_KG]": "كالەندار", "Tooltip": "Calendar", "Tooltip[zh_CN]": "显示时间及日期", "Tooltip[zh_HK]": "顯示時間及日期", "Tooltip[bo_CN]": "དུས་ཚོད་དང་ཚེས་གྲངས་འཆར་བ།", "Description": "Calendar", "Description[zh_CN]": "显示时间及日期", "Description[zh_HK]": "顯示時間及日期", "Description[bo_CN]": "དུས་ཚོད་དང་ཚེས་གྲངས་འཆར་བ།", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel,Sidebar", "Contents": { "Main": "ui/main.qml", "I18n": "i18n/org.ukui.panel.calendar" } } ukui-panel/widgets/ukui-panel-calendar/CMakeLists.txt0000664000175000017500000000466015167645111021616 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel-calendar VERSION 4.1) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick Widgets DBus LinguistTools REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick Widgets DBus LinguistTools REQUIRED) find_package(ukui-quick COMPONENTS platform) find_package(PkgConfig REQUIRED) set(EXTERNAL_LIBS "") if (QT_VERSION_MAJOR EQUAL "5") set(PC_PKGS gsettings-qt kysdk-systime) elseif (QT_VERSION_MAJOR EQUAL "6") set(PC_PKGS gsettings-qt6 kysdk-systime) endif() foreach(external_lib IN ITEMS ${PC_PKGS}) pkg_check_modules(${external_lib} REQUIRED IMPORTED_TARGET ${external_lib}) if(${${external_lib}_FOUND}) include_directories(${${external_lib}_INCLUDE_DIRS}) link_directories(${${external_lib}_LIBRARY_DIRS}) list(APPEND EXTERNAL_LIBS PkgConfig::${external_lib}) endif() endforeach() set(PROJECT_SOURCES plugin/calendar-plugin.h plugin/calendar-plugin.cpp plugin/calendar.h plugin/calendar.cpp ) file(GLOB TS_FILES i18n/*.ts) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) qt_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) else() qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES} ${QM_FILES}) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG> ) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus ${EXTERNAL_LIBS} ukui-quick::platform ) set(PLUGIN_INSTALL_ROOT_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/panel/calendar") install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.calendar") install(FILES ${QM_FILES} DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.calendar/i18n") install(FILES "plugin/qmldir" DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) ukui-panel/widgets/ukui-panel-calendar/plugin/0000775000175000017500000000000015167645100020344 5ustar fengfengukui-panel/widgets/ukui-panel-calendar/plugin/calendar-plugin.cpp0000664000175000017500000000175415167645100024124 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "calendar-plugin.h" #include "calendar.h" #include void CalendarPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.calendar")); qmlRegisterType(uri, 1, 0, "Calendar"); } ukui-panel/widgets/ukui-panel-calendar/plugin/qmldir0000664000175000017500000000007215167645100021556 0ustar fengfengmodule org.ukui.panel.calendar plugin ukui-panel-calendar ukui-panel/widgets/ukui-panel-calendar/plugin/calendar.cpp0000664000175000017500000002365615167645100022635 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "calendar.h" #include #include #include #include #include #include #include #include #include #include #include #include "kysdk/kysdk-system/libkydate.h" #define HOUR_SYSTEM_CONTROL "org.ukui.control-center.panel.plugins" #define DATE_FORMAT "date" // 日期格式:yyyy/MM/dd、yyyy-MM-dd #define TIME_FORMAT "hoursystem" // 时间格式:12小时制、24小时制 #define EN_FORMAT "en_US" #define KYSDK_TIMER_SERVER "com.kylin.kysdk.TimeServer" #define KYSDK_TIMER_PATH "/com/kylin/kysdk/Timer" #define KYSDK_TIMER_INTERFACE "com.kylin.kysdk.TimeInterface" #define KYSDK_DATESERVER "com.kylin.kysdk.DateServer" #define KYSDK_DATEPATH "/com/kylin/kysdk/Date" #define KYSDK_DATEINTERFACE "com.kylin.kysdk.DateInterface" #define UKUI_SIDEBAR_SERVER "org.ukui.Sidebar" #define UKUI_SIDEBAR_PATH "/org/ukui/Sidebar" #define UKUI_SIDEBAR_INTERFACE "org.ukui.Sidebar" #define SDK2CPP(func) []()->QString { char* p = func(); QString str(p); free(p); return str; } Calendar::Calendar(QObject *parent) : QObject(parent) { initGSetting(); //使用系统提供的sdk刷新时间显示 QDBusConnection::systemBus().connect(KYSDK_TIMER_SERVER, KYSDK_TIMER_PATH, KYSDK_TIMER_INTERFACE, "TimeSignal",this, SLOT(timeSignalSlot())); QDBusConnection::systemBus().connect(KYSDK_TIMER_SERVER, KYSDK_TIMER_PATH, KYSDK_TIMER_INTERFACE, "TimeChangeSignal",this, SLOT(timeSignalSlot())); QDBusConnection::sessionBus().connect(KYSDK_DATESERVER, KYSDK_DATEPATH, KYSDK_DATEINTERFACE, "ShortDateSignal",this, SLOT(onShortDateSignal())); //get notification state QDBusConnection::sessionBus().connect(UKUI_SIDEBAR_SERVER, UKUI_SIDEBAR_PATH, UKUI_SIDEBAR_INTERFACE, "stateChange", this, SLOT(onStateChanged(QString,QVariantMap))); //init shortformat date updateShortformatDate(); initFunctionControl(); } Calendar::~Calendar() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-calendar-v11")); } void Calendar::initGSetting() { const QByteArray id(HOUR_SYSTEM_CONTROL); if (QGSettings::isSchemaInstalled(id)) { auto gSettings = new QGSettings(id, QByteArray(), this); QStringList keys = gSettings->keys(); // "cn" ... if(keys.contains(DATE_FORMAT)) { m_dateFormat = gSettings->get(DATE_FORMAT).toString(); } // 12, 24 if(keys.contains(TIME_FORMAT)) { m_hourSystem = gSettings->get(TIME_FORMAT).toString(); } connect(gSettings, &QGSettings::changed, this, [gSettings, this] (const QString &key) { if (key == DATE_FORMAT) { m_dateFormat = gSettings->get(DATE_FORMAT).toString(); Q_EMIT timeUpdated(); } else if(key == TIME_FORMAT) { m_hourSystem = gSettings->get(TIME_FORMAT).toString(); Q_EMIT timeUpdated(); } }); } } void Calendar::updateShortformatDate() { m_shortDate = SDK2CPP(kdk_system_get_shortformat_date)(); if (m_shortDate.contains(QStringLiteral("/"))) { m_separator = QStringLiteral("/"); } else if (m_shortDate.contains(QStringLiteral("-"))) { m_separator = QStringLiteral("-"); } else if (m_shortDate.contains(QStringLiteral("."))) { m_separator = QStringLiteral("."); } else { m_separator = m_dateFormat == QStringLiteral("cn") ? QStringLiteral("/") : QStringLiteral("-"); } } void Calendar::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-calendar-v11")); onFunctionControlChanged(QStringLiteral("ukui-panel-calendar-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-calendar-v11"), true); }); } void Calendar::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-calendar-v11")) { return; } auto controlConfig = exit ? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "Calendar function control config:" << controlConfig; //是否禁用左键点击 if (controlConfig.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } //是否禁用右键点击 if (controlConfig.contains(QStringLiteral("disableMouseRightButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseRightButton")).toBool(); if (disable != m_disableMouseRightButton) { m_disableMouseRightButton = disable; Q_EMIT disableMouseRightButtonChanged(); } } else { m_disableMouseRightButton = false; Q_EMIT disableMouseRightButtonChanged(); } } bool Calendar::disableMouseLeftButton() const { return m_disableMouseLeftButton; } bool Calendar::disableMouseRightButton() const { return m_disableMouseRightButton; } QString Calendar::time() const { return SDK2CPP(kdk_system_nowtime)(); #if 0 if (m_hourSystem == QStringLiteral("24")) { return QDateTime::currentDateTime().toString(QStringLiteral("HH:mm")); } return QDateTime::currentDateTime().toString(QStringLiteral("hh:mm ap")).split(" ").first(); #endif } QString Calendar::ap() const { if (m_hourSystem == QStringLiteral("24")) { return {}; } return QDateTime::currentDateTime().toString("ap"); } QString Calendar::week() const { if (QLocale::system().name() == EN_FORMAT) { return SDK2CPP(kdk_system_shortweek)(); } else { return SDK2CPP(kdk_system_longweek)(); } //return QDateTime::currentDateTime().toString("ddd"); } QString Calendar::year() const { QStringList dateParts = m_shortDate.split(separator()); if (dateParts.count() > 0 && !dateParts[0].isEmpty()) { return dateParts[0]; } else { qWarning() << "[ukui-panel] calendar short format date from sdk invalid, return format 'yyyy'."; return QDateTime::currentDateTime().toString("yyyy"); } } QString Calendar::month() const { QStringList dateParts = m_shortDate.split(separator()); if (m_shortDate.split(separator()).count() > 2 && !dateParts[1].isEmpty() && !dateParts[2].isEmpty()) { return dateParts[1] + m_separator + dateParts[2]; } else { qWarning() << "[ukui-panel] calendar short format date from sdk invalid, return format 'MM dd'."; QString fmt = "MM" + separator() + "dd"; return QDateTime::currentDateTime().toString(fmt); } } QString Calendar::separator() const { return m_separator; } QString Calendar::tooltipText() const { return SDK2CPP(kdk_system_get_longformat_date)(); } QStringList Calendar::allData() const { QStringList list; list << time(); list << ap(); list << week(); list << year(); list << month(); return list; } int Calendar::unreadMsgCount() const { return m_unreadmsgCount; } QString Calendar::notifyIconTooltipText() { if (unreadMsgCount() == 1) { return QString::number(1) + QString(tr(" new notification")); } else if (unreadMsgCount() > 1) { return QString::number(unreadMsgCount()) + QString(tr(" new notifications")); } return QString(tr("Notification center")); } void Calendar::openSidebar() { QDBusInterface sidebarIFace(UKUI_SIDEBAR_SERVER, UKUI_SIDEBAR_PATH, UKUI_SIDEBAR_INTERFACE, QDBusConnection::sessionBus(), this); sidebarIFace.asyncCallWithArgumentList("active", (QVariantList() << "sidebar")); } void Calendar::timeSignalSlot() { m_shortDate = SDK2CPP(kdk_system_get_shortformat_date)(); Q_EMIT timeUpdated(); } void Calendar::onStateChanged(const QString &module, const QVariantMap &data) { if (module == QStringLiteral("sidebar")) { if (data.contains(QStringLiteral("unreadMsg"))) { m_unreadmsgCount = data.value(QStringLiteral("unreadMsg")).toInt(); Q_EMIT unreadMsgChanged(); } } } void Calendar::onShortDateSignal() { updateShortformatDate(); Q_EMIT timeUpdated(); } void Calendar::activeCalendar() { QDBusInterface calendar(QStringLiteral("org.ukui.kylin_calendar"), QStringLiteral("/org/ukui/kylin_calendar"), QStringLiteral("org.ukui.kylin_calendar")); calendar.asyncCall("command_Control", QVariant("")); } ukui-panel/widgets/ukui-panel-calendar/plugin/calendar-plugin.h0000664000175000017500000000205415167645100023563 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_CALENDAR_PLUGIN_H #define UKUI_PANEL_CALENDAR_PLUGIN_H #include class CalendarPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif //UKUI_PANEL_CALENDAR_PLUGIN_H ukui-panel/widgets/ukui-panel-calendar/plugin/calendar.h0000664000175000017500000000575715167645100022304 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_CALENDAR_H #define UKUI_PANEL_CALENDAR_H #include class Calendar : public QObject { Q_OBJECT Q_PROPERTY(QString time READ time NOTIFY timeUpdated) Q_PROPERTY(QString ap READ ap NOTIFY timeUpdated) Q_PROPERTY(QString week READ week NOTIFY timeUpdated) Q_PROPERTY(QString year READ year NOTIFY timeUpdated) Q_PROPERTY(QString month READ month NOTIFY timeUpdated) Q_PROPERTY(QString separator READ separator NOTIFY timeUpdated) Q_PROPERTY(QString tooltipText READ tooltipText NOTIFY timeUpdated) Q_PROPERTY(QStringList allData READ allData NOTIFY timeUpdated) Q_PROPERTY(int unreadMsgCount READ unreadMsgCount NOTIFY unreadMsgChanged) Q_PROPERTY(QString notifyIconTooltipText READ notifyIconTooltipText NOTIFY unreadMsgChanged) Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) Q_PROPERTY(bool disableMouseRightButton READ disableMouseRightButton NOTIFY disableMouseRightButtonChanged) public: explicit Calendar(QObject *parent = nullptr); ~Calendar() override; QString time() const; QString ap() const; QString week() const; QString year() const; QString month() const; QString separator() const; QString tooltipText() const; QStringList allData() const; int unreadMsgCount() const; QString notifyIconTooltipText(); bool disableMouseLeftButton() const; bool disableMouseRightButton() const; Q_INVOKABLE void openSidebar(); Q_INVOKABLE void activeCalendar(); Q_SIGNALS: void timeUpdated(); void unreadMsgChanged(); void disableMouseLeftButtonChanged(); void disableMouseRightButtonChanged(); private Q_SLOTS: void timeSignalSlot(); void onStateChanged(const QString &module, const QVariantMap &data); void onShortDateSignal(); void onFunctionControlChanged(const QString& name, bool exit = false); private: void initGSetting(); void updateShortformatDate(); void initFunctionControl(); bool m_disableMouseLeftButton = false; bool m_disableMouseRightButton = false; QString m_dateFormat {"cn"}; QString m_hourSystem {"24"}; QString m_separator; QString m_shortDate; int m_unreadmsgCount = 0; }; #endif //UKUI_PANEL_CALENDAR_H ukui-panel/widgets/ukui-panel-taskView/0000775000175000017500000000000015167645111017074 5ustar fengfengukui-panel/widgets/ukui-panel-taskView/widget/0000775000175000017500000000000015167645100020355 5ustar fengfengukui-panel/widgets/ukui-panel-taskView/widget/ui/0000775000175000017500000000000015167645100020772 5ustar fengfengukui-panel/widgets/ukui-panel-taskView/widget/ui/main.qml0000664000175000017500000001007215167645100022431 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.panel.taskView 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal property int spacing: isMiniLayout ? 2 : parent.ratio ? 4 * parent.ratio : 4 property bool isMiniLayout: isHorizontal && (height <= 36) Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? height - mouseArea.anchors.topMargin - mouseArea.anchors.bottomMargin : width Layout.preferredHeight: isHorizontal ? height : width - mouseArea.anchors.leftMargin - mouseArea.anchors.rightMargin //使其右键不显示父窗口的菜单 MouseArea { anchors.fill: root acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { return; } } } MouseArea { id: mouseArea Accessible.role: Accessible.Button Accessible.description: "This is a taskview button of ukui-panel" Accessible.name: "ukui-panel-taskView" anchors.fill: parent hoverEnabled: true anchors { leftMargin: root.isHorizontal? 0 : spacing topMargin: root.isHorizontal? spacing : 0 rightMargin: root.isHorizontal? 0 : spacing bottomMargin: root.isHorizontal? spacing : 0 } DtThemeBackground { id: backGround anchors.fill: parent radius: GlobalTheme.kRadiusNormal backgroundColor: mouseArea.containsPress ? GlobalTheme.kComponentAlphaClick : mouseArea.containsMouse ? GlobalTheme.kComponentAlphaHover : GlobalTheme.kContainGeneralAlphaNormal useStyleTransparency: false Icon { id: icon anchors.fill: parent anchors.margins: spacing source: "ukui-taskview-black-symbolic" mode: Icon.AutoHighlight scale: mouseArea.containsPress ? 0.8 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } } } TaskViewButton { id: taskviewButton } onClicked: (mouse) => { if (mouse.button === Qt.LeftButton && !taskviewButton.disableMouseLeftButton) { AppLauncher.runCommand("ukui-window-switch --show-workspace"); } } Tooltip { id: tooltip anchors.fill: parent mainText: Widget.tooltip posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: 8 + root.spacing } } } ukui-panel/widgets/ukui-panel-taskView/widget/metadata.json0000775000175000017500000000363315167645100023040 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.panel.taskView", "Icon": "ukui-taskview-black-symbolic", "Name": "ukui-panel-taskView", "Name[zh_CN]": "多任务视图", "Name[zh_HK]": "多任務視圖", "Name[bo_CN]": "འགན་མང་མཐོང་རིས།", "Name[ug_CN]": "كۆپ ۋەزىپە ۋىدېيوسى", "Name[kk_KZ]": "كوپ مىندەتتى ۋىدېيوسى", "Name[ky_KG]": "كۅپ مىلدەت ۋىدېيوسى", "Name[mn_MN]": "ᠣᠯᠠᠨ ᠡᠭᠦᠷᠭᠡ ᠶᠢᠨ ᠵᠢᠷᠤᠭ ᠢ ᠦᠵᠡᠨ᠎ᠡ", "Tooltip": "Show task view", "Tooltip[zh_CN]": "多任务视图", "Tooltip[zh_HK]": "多任務視圖", "Tooltip[bo_CN]": "འགན་མང་མཐོང་རིས་འཆར་བ།", "Tooltip[ug_CN]": "كۆپ ۋەزىپە كۆرۈنۈشىنى كۆرسىتىش", "Tooltip[kk_KZ]": "كوپ مىندەتتى كورىنۋدى كورسەتۋ", "Tooltip[ky_KG]": "كۅپ مىلدەت گۅرۉنۉشۉن   كۅرسۅتۉۉ", "Tooltip[mn_MN]": "ᠣᠯᠠᠨ ᠡᠭᠦᠷᠭᠡ ᠶᠢᠨ ᠵᠢᠷᠤᠭ ᠢ ᠦᠵᠡᠨ᠎ᠡ", "Description": "Show task view", "Description[zh_CN]": "显示多任务视图", "Description[zh_HK]": "顯示多任務視圖", "Description[bo_CN]": "འགན་མང་མཐོང་རིས་འཆར་བ།", "Description[ug_CN]": "كۆپ ۋەزىپە كۆرۈنۈشىنى كۆرسىتىش", "Description[kk_KZ]": "كوپ مىندەتتى كورىنۋدى كورسەتۋ", "Description[ky_KG]": "كۅپ مىلدەت گۅرۉنۉشۉن   كۅرسۅتۉۉ", "Description[mn_MN]": "ᠣᠯᠠᠨ ᠡᠭᠦᠷᠭᠡ ᠶᠢᠨ ᠵᠢᠷᠤᠭ ᠢ ᠦᠵᠡᠨ᠎ᠡ", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "Contents": { "Main": "ui/main.qml" } } ukui-panel/widgets/ukui-panel-taskView/CMakeLists.txt0000664000175000017500000000300415167645111021631 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel-taskView VERSION 4.1) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick DBus LinguistTools REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick DBus LinguistTools REQUIRED) find_package(ukui-quick COMPONENTS platform) set(PROJECT_SOURCES plugin/task-view-button.h plugin/task-view-plugin.h plugin/task-view-plugin.cpp plugin/task-view-button.cpp ) add_compile_definitions(UKUI_TASK_MANAGER_VERSION="${UKUI_TASK_MANAGER_VERSION}") if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES}) else() add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCES}) endif() target_compile_definitions(${PROJECT_NAME} PRIVATE $<$,$>:QT_QML_DEBUG> ) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::DBus ukui-quick::platform ) set(PLUGIN_INSTALL_ROOT_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/panel/taskView") install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.taskView") install(FILES "plugin/qmldir" DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_ROOT_PATH}) ukui-panel/widgets/ukui-panel-taskView/plugin/0000775000175000017500000000000015167645100020370 5ustar fengfengukui-panel/widgets/ukui-panel-taskView/plugin/qmldir0000664000175000017500000000007215167645100021602 0ustar fengfengmodule org.ukui.panel.taskView plugin ukui-panel-taskView ukui-panel/widgets/ukui-panel-taskView/plugin/task-view-button.h0000664000175000017500000000266515167645100023775 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_START_MENU_BUTTON_H #define UKUI_PANEL_START_MENU_BUTTON_H #include class TaskViewButton : public QObject { Q_OBJECT Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) public: explicit TaskViewButton(QObject *parent=nullptr); ~TaskViewButton() override; Q_INVOKABLE void showTaskView(); bool disableMouseLeftButton() const; Q_SIGNALS: void disableMouseLeftButtonChanged(); public Q_SLOTS: void onFunctionControlChanged(const QString& name, bool exit = false); private: void initFunctionControl(); bool m_disableMouseLeftButton = false; }; #endif //UKUI_PANEL_START_MENU_BUTTON_H ukui-panel/widgets/ukui-panel-taskView/plugin/task-view-button.cpp0000664000175000017500000000567615167645100024335 0ustar fengfeng /* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "task-view-button.h" #include #include #include #include #include TaskViewButton::TaskViewButton(QObject *parent) : QObject(parent) { initFunctionControl(); } TaskViewButton::~TaskViewButton() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-taskView-v11")); } void TaskViewButton::showTaskView() { QDBusInterface interface(QStringLiteral("org.ukui.KWin"), QStringLiteral("/MultitaskView"), QStringLiteral("org.kde.KWin.MultitaskView"), QDBusConnection::sessionBus()); interface.asyncCall(QStringLiteral("show")); } bool TaskViewButton::disableMouseLeftButton() const { return m_disableMouseLeftButton; } void TaskViewButton::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-taskView-v11")) { return; } auto controlConfig = exit ? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "TaskViewButton function control config:" << controlConfig; //是否禁用左键点击 if (controlConfig.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = controlConfig.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } } void TaskViewButton::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-taskView-v11")); onFunctionControlChanged(QStringLiteral("ukui-panel-taskView-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-taskView-v11"), true); }); } ukui-panel/widgets/ukui-panel-taskView/plugin/task-view-plugin.h0000664000175000017500000000207415167645100023752 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef UKUI_PANEL_START_MENU_PLUGIN_H #define UKUI_PANEL_START_MENU_PLUGIN_H #include class StartMenuPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: void registerTypes(const char *uri) override; }; #endif //UKUI_PANEL_START_MENU_PLUGIN_H ukui-panel/widgets/ukui-panel-taskView/plugin/task-view-plugin.cpp0000664000175000017500000000200715167645100024301 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "task-view-plugin.h" #include "task-view-button.h" #include "qqml.h" void StartMenuPlugin::registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.taskView")); qmlRegisterType(uri, 1, 0, "TaskViewButton"); } ukui-panel/widgets/ukui-panel-idm/0000775000175000017500000000000015167645100016046 5ustar fengfengukui-panel/widgets/ukui-panel-idm/widget/0000775000175000017500000000000015167645100017331 5ustar fengfengukui-panel/widgets/ukui-panel-idm/widget/ui/0000775000175000017500000000000015167645100017746 5ustar fengfengukui-panel/widgets/ukui-panel-idm/widget/ui/main.qml0000664000175000017500000000624715167645100021416 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.12 import QtQuick.Layouts 1.12 import org.ukui.quick.widgets 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 WidgetItem { id: root property bool isHorizontal: Widget.orientation == Types.Horizontal property real ratio: parent.ratio ? parent.ratio : 1 Layout.fillWidth: !isHorizontal Layout.fillHeight: isHorizontal Layout.preferredWidth: isHorizontal ? height - mouseArea.anchors.topMargin - mouseArea.anchors.bottomMargin : width Layout.preferredHeight: isHorizontal ? height : width - mouseArea.anchors.leftMargin - mouseArea.anchors.rightMargin property bool isMiniLayout: isHorizontal && (height <= 36) // 更新tooltip Widget.tooltip: Widget.tooltip MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true anchors { leftMargin: root.isHorizontal? 0 : 4 * root.ratio topMargin: isMiniLayout ? 2 * root.ratio : root.isHorizontal? 4 * root.ratio : 0 rightMargin: root.isHorizontal? 0 : 4 * root.ratio bottomMargin: isMiniLayout ? 2 * root.ratio : root.isHorizontal? 4 * root.ratio : 0 } StyleBackground { anchors.fill: parent radius: Theme.normalRadius useStyleTransparency: false paletteRole: Theme.WindowText alpha: parent.containsPress ? 0.16 : parent.containsMouse ? 0.08 : 0 Tooltip { id: tooltip anchors.fill: parent mainText: Widget.tooltip posFollowCursor: false location: { switch(Widget.container.position) { case Types.Bottom: return Dialog.BottomEdge; case Types.Left: return Dialog.LeftEdge; case Types.Top: return Dialog.TopEdge; case Types.Right: return Dialog.RightEdge; } } margin: 6 } } Icon { anchors.fill: parent anchors.margins: isMiniLayout ? 2 * root.ratio : 4 * root.ratio source: Widget.icon scale: parent.containsPress ? 0.95 : 1.0 } onClicked: { AppLauncher.runCommand("ukui-intelligent-data-manager -s"); } } } ukui-panel/widgets/ukui-panel-idm/widget/metadata.json0000664000175000017500000000111015167645100021775 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.panel.idm", "Icon": "ukui-intelligent-data-manager", "Name": "ukui idm", "Name[zh_CN]": "数据管理", "Tooltip": "UKUI Intelligent Data Manager", "Tooltip[zh_CN]": "数据管理", "Description": "UKUI Intelligent Data Manager", "Description[zh_CN]": "数据管理", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "Contents": { "Main": "ui/main.qml" } } ukui-panel/widgets/ukui-panel-idm/CMakeLists.txt0000664000175000017500000000024115167645100020603 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-panel-idm VERSION 4.1) install(DIRECTORY "widget/" DESTINATION "/usr/share/ukui/widgets/org.ukui.panel.idm") ukui-panel/.gitignore0000664000175000017500000000046115167645100013550 0ustar fengfeng# Ignore the following files .vscode *~ *.[oa] *.diff *.kate-swp *.kdev4 .kdev_include_paths *.kdevelop.pcs *.moc *.moc.cpp *.orig *.user .*.swp .swp.* Doxyfile Makefile avail random_seed /build*/ CMakeLists.txt.user* *.unc-backup* .clang-format /compile_commands.json .clangd .idea /cmake-build* .cache ukui-panel/panel/0000775000175000017500000000000015167645111012660 5ustar fengfengukui-panel/panel/src/0000775000175000017500000000000015167645111013447 5ustar fengfengukui-panel/panel/src/message-processor.cpp0000664000175000017500000001421515167645100017615 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "message-processor.h" #include #include #include "rep_remote-config_replica.h" MessageProcessor::MessageProcessor(QObject* parent) : QObject(parent) { } MessageProcessor::~MessageProcessor() { if(m_configReplica) { m_configReplica->disconnect(); delete m_configReplica; m_configReplica = nullptr; } } bool MessageProcessor::preprocessMessage(const QStringList &message) { QCommandLineOption helpOption = m_parser.addHelpOption(); QCommandLineOption versionOption = m_parser.addVersionOption(); QCommandLineOption panelLocationOption("panelLocation", QObject::tr("Show current panel location")); QCommandLineOption panelSizePolicyOption("panelSizePolicy", QObject::tr("Show current panel size policy")); QCommandLineOption panelAutoHideOption("panelAutoHide", QObject::tr("Show current panel auto hide status")); QCommandLineOption panelLockOption("panelLock", QObject::tr("Show current panel lock status")); QCommandLineOption disabledWidgetsOption("disabledWidgets", QObject::tr("Show current panel disabledWidgets")); QCommandLineOption trayIconsInhibitedOption("trayIconsInhibited", QObject::tr("Show current inhibited tray icons")); QCommandLineOption taskBarIconsShowedOnOption("taskBarIconsShowedOn", QObject::tr("Show where taskBar icons showed on")); QCommandLineOption showPanelOnAllScreensOption("showPanelOnAllScreens", QObject::tr("Whether show panel on all screens")); QCommandLineOption showSystemTrayOnAllPanelsOption("showSystemTrayOnAllPanels", QObject::tr("Whether show system tray on all panels")); QCommandLineOption panelTypeOption("panelType", QObject::tr("Show Current panel type")); m_parser.addOption(panelLocationOption); m_parser.addOption(panelSizePolicyOption); m_parser.addOption(panelAutoHideOption); m_parser.addOption(panelLockOption); m_parser.addOption(disabledWidgetsOption); m_parser.addOption(trayIconsInhibitedOption); m_parser.addOption(taskBarIconsShowedOnOption); m_parser.addOption(showPanelOnAllScreensOption); m_parser.addOption(showSystemTrayOnAllPanelsOption); m_parser.addOption(panelTypeOption); m_parser.parse(message); if(message.size() <= 1 || !m_parser.unknownOptionNames().isEmpty() || m_parser.isSet(helpOption)) { m_parser.showHelp(); } if (m_parser.isSet(versionOption)) { m_parser.showVersion(); } m_qroNode.connectToNode(nodeUrl()); m_configReplica = m_qroNode.acquire(); connect(m_configReplica, &QRemoteObjectReplica::initialized, this, [=, this]() { auto panelType = m_configReplica->panelType(); QString message; if (m_parser.isSet(panelLocationOption)) { QMetaEnum me = QMetaEnum::fromType(); message = me.valueToKey(panelType == GeneralConfigDefine::Version4 ? m_configReplica->panelLocation() : m_configReplica->panelLocationNext()); } else if (m_parser.isSet(panelSizePolicyOption)) { QMetaEnum me = QMetaEnum::fromType(); message = me.valueToKey(panelType == GeneralConfigDefine::Version4 ? m_configReplica->panelSizePolicy() : m_configReplica->panelSizePolicyNext()); } else if (m_parser.isSet(panelAutoHideOption)) { message = (panelType == GeneralConfigDefine::Version4 ? m_configReplica->panelAutoHide() : m_configReplica->panelAutoHideNext())? "true" : "false"; } else if (m_parser.isSet(panelLockOption)) { message = (panelType == GeneralConfigDefine::Version4 ? m_configReplica->panelLock() : m_configReplica->panelLockNext())? "true" : "false"; } else if (m_parser.isSet(disabledWidgetsOption)) { message = panelType == GeneralConfigDefine::Version4 ? m_configReplica->disabledWidgets().join(",") : m_configReplica->disabledWidgetsNext().join(","); } else if (m_parser.isSet(trayIconsInhibitedOption)) { message = m_configReplica->trayIconsInhibited().join(","); } else if (m_parser.isSet(taskBarIconsShowedOnOption)) { QMetaEnum me = QMetaEnum::fromType(); message = me.valueToKey(m_configReplica->taskBarIconsShowedOn()); } else if (m_parser.isSet(panelTypeOption)) { QMetaEnum me = QMetaEnum::fromType(); message = me.valueToKey(panelType); } else if (m_parser.isSet(showPanelOnAllScreensOption)) { message =m_configReplica->showPanelOnAllScreens()? "true" : "false"; } else if (m_parser.isSet(showSystemTrayOnAllPanelsOption)) { message =m_configReplica->showSystemTrayOnAllPanels()? "true" : "false"; } else { m_parser.showHelp(); } fputs(qPrintable(message + "\n"), stdout); qApp->quit(); }); return false; } QUrl MessageProcessor::nodeUrl() { QString displayEnv = (qgetenv("XDG_SESSION_TYPE") == "wayland") ? QLatin1String("WAYLAND_DISPLAY") : QLatin1String("DISPLAY"); QString display(qgetenv(displayEnv.toUtf8().data())); return QUrl(QStringLiteral("local:ukui-panel-config-") + QString(qgetenv("USER")) + display); } ukui-panel/panel/src/remote-config.rep0000664000175000017500000000400715167645100016714 0ustar fengfeng// // Copyright (C) 2024, KylinSoft Co., Ltd. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // Authors: iaom // #include "general-config-define.h" #include class RemoteConfig { PROP(GeneralConfigDefine::MergeIcons mergeIcons READWRITE); PROP(GeneralConfigDefine::PanelLocation panelLocation READWRITE); PROP(GeneralConfigDefine::PanelSizePolicy panelSizePolicy READWRITE); PROP(bool allowCustomSize READONLY); PROP(bool panelAutoHide READWRITE); PROP(bool panelLock READWRITE); PROP(QStringList panelWidgets READWRITE); PROP(QStringList disabledWidgets READONLY); PROP(QStringList trayIconsInhibited READWRITE); PROP(QStringList trayIconsCanInhibited READONLY); PROP(GeneralConfigDefine::TaskBarIconsShowedOn taskBarIconsShowedOn READWRITE); PROP(GeneralConfigDefine::PanelType panelType READWRITE); PROP(bool showPanelOnAllScreens READWRITE); PROP(bool showSystemTrayOnAllPanels READWRITE); PROP(GeneralConfigDefine::PanelLocation panelLocationNext READWRITE); PROP(GeneralConfigDefine::PanelSizePolicy panelSizePolicyNext READWRITE); PROP(bool panelAutoHideNext READWRITE); PROP(bool panelLockNext READWRITE); PROP(QStringList panelWidgetsNext READWRITE); PROP(QStringList disabledWidgetsNext READONLY); SLOT(disableWidget(const QString &id, bool disable)) SLOT(disableWidgetNext(const QString &id, bool disable)) }; ukui-panel/panel/src/view/0000775000175000017500000000000015167645111014421 5ustar fengfengukui-panel/panel/src/view/panel.h0000664000175000017500000001410615167645111015673 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * iaom */ #ifndef UKUI_PANEL_PANEL_H #define UKUI_PANEL_PANEL_H #include #include #include #include #include #include #include #include #include #include #include "screens-manager.h" #include "general-config-define.h" #include "common.h" class QAction; namespace UkuiPanel { Q_DECLARE_LOGGING_CATEGORY(PANEL_PANEL) class Panel : public UkuiQuick::IslandView { Q_OBJECT Q_PROPERTY(bool lockPanel READ lockPanel NOTIFY lockPanelChanged) Q_PROPERTY(bool enableCustomSize READ enableCustomSize NOTIFY enableCustomSizeChanged) Q_PROPERTY(bool disableMouseLeftButton READ disableMouseLeftButton NOTIFY disableMouseLeftButtonChanged) Q_PROPERTY(bool disableMouseRightButton READ disableMouseRightButton NOTIFY disableMouseRightButtonChanged) Q_PROPERTY(bool disableMouseHover READ disableMouseHover NOTIFY disableMouseHoverChanged) Q_PROPERTY(bool disableContextMenu READ disableContextMenu NOTIFY disableContextMenuChanged) public: Panel(Screen *screen, const QString &id, QWindow *parent = nullptr); ~Panel() override; void setPanelScreen(Screen *screen); bool lockPanel() const; bool enableCustomSize() const; Q_INVOKABLE void changeCursor(const QString &type); Q_INVOKABLE void changePanelPos(UkuiQuick::Types::Pos pos); Q_INVOKABLE void startResizeCustomPanelSize(const Qt::Edges &edge); Q_INVOKABLE void endResizeCustomPanelSize(); bool disableMouseLeftButton() const; bool disableMouseRightButton() const; bool disableMouseHover() const; bool disableContextMenu() const; Q_SIGNALS: void lockPanelChanged(); void enableCustomSizeChanged(); void disableMouseLeftButtonChanged(); void disableMouseRightButtonChanged(); void disableMouseHoverChanged(); void disableContextMenuChanged(); protected: bool event(QEvent *e) override; public Q_SLOTS: /** * @brief primaryScreenChanged 主屏改变时修改托盘的显示状态 * @param screen 改变之后的主屏 * @return */ void primaryScreenChanged(Screen *screen); private Q_SLOTS: void onScreenGeometryChanged(const QRect &geometry); void onConfigChanged(const QString &key); void setPosition(UkuiQuick::Types::Pos position, bool updateConfig = true); void setPanelSize(int size, bool updateConfig = true); void setPanelPolicy(GeneralConfigDefine::PanelSizePolicy sizePolicy, bool updateConfig = true); void resetWorkArea(bool cut); void setLockPanel(bool locked, bool updateConfig = true); // widget opt void widgetActionTriggered(const QAction *); void disableWidget(const QString &id, bool disable); void updateHideState(); void setAutoHide(bool autoHide, bool updateConfig = true); void setHidden(bool hidden); void activeHideTimer(bool active = true); void onFunctionControlChanged(const QString& name, bool exit = false); private: void initConfig(); void initPanelConfig(); void loadWidgetsConfig(); void updateGeometry(); /** * 根据panel的大小,计算窗口大小、窗口中panel的对应区域 * @param size */ void calculatePanelRectFromSize(int size); /** * 更新panel窗口尺寸限制(最大、最小宽高) */ void updateLimitSize(); /** * 调用m_windowProxy接口,设置窗口属性(geometry) */ void setGeometry(); void initGsettings(); void loadActions(); void initSizeAction(); void updateSizeAction(); void initPositionAction(); void updatePositionAction(); void initLockPanelAction(); void updateLockPanelAction(); void updateMask(); void initIsland(); //初始化系统托盘是否显示 void setShowSystemTrayStatus(); void setGSettings(const QString &key, const QVariant &value); private: int m_panelSize {48}; int m_panelPosition {0};// 任务栏位置与屏幕:上: 1, 下: 0, 左: 2, 右: 3, 如果为其他值,则说明任务栏不存在 QRect m_windowRegion; GeneralConfigDefine::PanelSizePolicy m_sizePolicy {GeneralConfigDefine::Small}; QString m_id; Screen *m_screen {nullptr}; QAction *m_sizeAction {nullptr}; QAction *m_positionAction {nullptr}; QAction *m_lockPanelAction {nullptr}; QAction *m_autoHideAction {nullptr}; QList m_widgetActions; QStringList m_disabledWidgets; bool m_startUp = true;//任务栏是否正在启动 bool m_isHidden = false;//当前是否已经隐藏 bool m_autoHide = false;//是否自动隐藏(鼠标离开任务栏区域即隐藏) bool m_isResizingPanel = false;// 任务栏是否正在被拖拽改变大小 bool m_lockPanel = false; QTimer *m_hideTimer = nullptr; UnavailableArea m_unavailableArea; UkuiQuick::WindowProxy *m_windowProxy = nullptr; QGSettings *m_settings = nullptr; bool m_containsMouse = false; int m_panelMaxSize = 92; int m_panelMinSize = 48; int m_systemTrayInstance = -1; QString m_lastConfigVersion; QString m_lastPanelConfigVersion; //管控配置 bool m_disableMouseLeftButton = false; bool m_disableMouseRightButton = false; bool m_disableMouseHover = false; bool m_disableContextMenu = false; }; } // UkuiPanel Q_DECLARE_METATYPE(QList) #endif //UKUI_PANEL_PANEL_H ukui-panel/panel/src/view/panel-top-bar.cpp0000664000175000017500000007061615167645100017576 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #include "panel-top-bar.h" #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #else #include #endif #include #include #include #include #include #include #include "island-drag-helper.h" #include "widget-model.h" #include "panel-gsettings.h" #define PANEL_TOP_BAR_SIZE 32 namespace UkuiPanel { PanelTopBar::PanelTopBar(Screen* screen, const QString&id, QWindow* parent) : UkuiQuick::IslandView( QStringLiteral("panel"), QStringLiteral("ukui-panel")) { qRegisterMetaType>(); qmlRegisterType("org.ukui.panel.impl", 1, 0, "WidgetSortModel"); rootContext()->setContextProperty("panelTopBar", this); setColor(Qt::transparent); setFlags(flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus); m_windowProxy = new UkuiQuick::WindowProxy(this); m_windowProxy->setWindowType(UkuiQuick::WindowType::Dock); initMainContainer(); setTopBarScreen(screen); initIslandsConfig(); initConfig(); for(auto island : mainView()->widgets()) { m_islands.insert(island->id(), dynamic_cast(island)); } loadActions(); m_hideTimer = new QTimer(this); m_hideTimer->setSingleShot(true); m_hideTimer->setInterval(500); connect(m_hideTimer, &QTimer::timeout, this, [this] { setHidden(true); }); connect(mainView(), &UkuiQuick::WidgetContainer::widgetAdded, this, &PanelTopBar::onWidgetAdded); connect(mainView(), &UkuiQuick::WidgetContainer::widgetRemoved, this, &PanelTopBar::onWidgetRemoved); updateVisbility(); updateDisableWidget(); loadMainViewItem(); updateIslandState(); //island从顶栏拖拽移除 connect(IslandDragHelper::self(), &IslandDragHelper::dragRemoveFromTopBar, this, &PanelTopBar::dragRemove); //island从任务栏拖拽中 connect(IslandDragHelper::self(), &IslandDragHelper::dragRemovingFromPanel, this, &PanelTopBar::dragAdding); connect(this, &PanelTopBar::heightChanged, this, [this] { setTopBarSize(height()); }); } PanelTopBar::~PanelTopBar() { qDeleteAll(m_menus); } void PanelTopBar::setTopBarScreen(Screen* screen) { if (!screen || screen == m_screen) { return; } if (m_screen) { m_screen->disconnect(this); } m_screen = screen; setScreen(screen->internal()); mainView()->setScreen(screen->internal()); updateGeometry(); connect(screen, &Screen::geometryChanged, this, &PanelTopBar::onScreenGeometryChanged); } void PanelTopBar::addIsland(const QString& id) { addContainer(id); updateIslandFormAction(); } void PanelTopBar::removeIsland(const QString& id) { if(m_islands.contains(id)){ mainView()->addDisableInstance(m_islands.value(id)->instanceId()); m_islands.remove(id); } } void PanelTopBar::dragRemove(const QString& id) { QTimer::singleShot(0, this, [this, id]() { removeIsland(id); updateVisbility(); }); } void PanelTopBar::dragAdding(const QString& id, bool addWhenDrop) { updateVisbility(); } void PanelTopBar::onScreenGeometryChanged(const QRect&geometry) { Q_UNUSED(geometry) updateGeometry(); } void PanelTopBar::resetWorkArea(bool cut) { if (cut) { // 为窗管添加不可显示区域 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) KX11Extras::setExtendedStrut(winId(), m_unavailableArea.leftWidth, m_unavailableArea.leftStart, m_unavailableArea.leftEnd, m_unavailableArea.rightWidth, m_unavailableArea.rightStart, m_unavailableArea.rightEnd, m_unavailableArea.topWidth, m_unavailableArea.topStart, m_unavailableArea.topEnd, m_unavailableArea.bottomWidth, m_unavailableArea.bottomStart, m_unavailableArea.bottomEnd ); #else KWindowSystem::setExtendedStrut(winId(), m_unavailableArea.leftWidth, m_unavailableArea.leftStart, m_unavailableArea.leftEnd, m_unavailableArea.rightWidth, m_unavailableArea.rightStart, m_unavailableArea.rightEnd, m_unavailableArea.topWidth, m_unavailableArea.topStart, m_unavailableArea.topEnd, m_unavailableArea.bottomWidth, m_unavailableArea.bottomStart, m_unavailableArea.bottomEnd ); #endif m_windowProxy->setPanelAutoHide(false); } else { // 为窗管移除不可显示区域 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) KX11Extras::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); #else KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); #endif m_windowProxy->setPanelAutoHide(true); } } void PanelTopBar::setPosition(UkuiQuick::Types::Pos position) { auto container = mainView(); if (position != container->position()) { // 任务栏位置与屏幕:上: 1, 下: 0, 左: 2, 右: 3, 如果为其他值,则说明任务栏不存在 int panelPosition = 0; switch (position) { case UkuiQuick::Types::Left: panelPosition = 2; break; case UkuiQuick::Types::Top: panelPosition = 1; break; case UkuiQuick::Types::Right: panelPosition = 3; break; default: case UkuiQuick::Types::Bottom: panelPosition = 0; position = UkuiQuick::Types::Pos::Bottom; break; } container->setPosition(position); updateGeometry(); if (position == UkuiQuick::Types::Left || position == UkuiQuick::Types::Right) { container->setOrientation(UkuiQuick::Types::Vertical); } else { container->setOrientation(UkuiQuick::Types::Horizontal); } mainView()->config()->setValue(QStringLiteral("position"), position); } } void PanelTopBar::updateVisbility() { m_dragAdding = IslandDragHelper::self()->dragging() && !IslandDragHelper::self()->islandPendingAdd2Panel(); if(mainView()->widgets().count() > 0 || m_dragAdding) { QTimer::singleShot(1, this, [&]() { resetWorkArea(mainView()->widgets().count() > 0); setHidden(false); }); } else { QTimer::singleShot(1, this, [&]() { resetWorkArea(false); setHidden(true); }); } } void PanelTopBar::setAutoHide(bool autoHide) { if (m_autoHide == autoHide) { return; } m_autoHide = autoHide; activeHideTimer(false); setHidden(m_autoHide); resetWorkArea(!m_autoHide); } void PanelTopBar::setHidden(bool hidden) { auto panelContent = rootItem(); if (!panelContent || m_isHidden == hidden) { return; } m_isHidden = hidden; hide(); panelContent->setVisible(!m_isHidden); updateMask(); show(); } void PanelTopBar::activeHideTimer(bool active) { if (!m_hideTimer) { return; } if (active) { m_hideTimer->start(); } else { m_hideTimer->stop(); } } void PanelTopBar::onWidgetAdded(UkuiQuick::Widget *widget) { PanelGSettings::instance()->setIslandPosition(widget->id(), 1); updateVisbility(); } void PanelTopBar::onWidgetRemoved(UkuiQuick::Widget *widget) { PanelGSettings::instance()->setIslandPosition(widget->id(), 0); updateVisbility(); } void PanelTopBar::initMainContainer() { UkuiQuick::WidgetContainer::widgetLoader().addWidgetSearchPath(QStringLiteral(":/ukui-panel")); loadMainViewWithoutItem(QStringLiteral("org.ukui.panelTopBar")); } void PanelTopBar::updateGeometry() { refreshRect(); updateMask(); resetWorkArea(true); } void PanelTopBar::refreshRect() { int panelSize = m_panelTopBarSize; auto container = PanelTopBar::mainView(); const auto margin = container->margin(); // panelRect 为实际占用的区域,包括外边距(margin) QRect screenGeometry = container->screen()->geometry(), panelRect; UnavailableArea unavailableArea; switch (container->position()) { default: case UkuiQuick::Types::Pos::Bottom: panelSize += (margin->top() + margin->bottom()); panelRect = screenGeometry.adjusted(0, screenGeometry.height() - panelSize, 0, 0); unavailableArea.bottomWidth = panelRect.height(); unavailableArea.bottomStart = panelRect.left(); unavailableArea.bottomEnd = panelRect.right(); m_windowProxy->slideWindow(UkuiQuick::WindowProxy::BottomEdge); break; case UkuiQuick::Types::Pos::Left: panelSize += (margin->left() + margin->right()); panelRect = screenGeometry.adjusted(0, 0, panelSize - screenGeometry.width(), 0); unavailableArea.leftWidth = panelRect.width(); unavailableArea.leftStart = panelRect.top(); unavailableArea.leftEnd = panelRect.bottom(); m_windowProxy->slideWindow(UkuiQuick::WindowProxy::LeftEdge); break; case UkuiQuick::Types::Pos::Top: panelSize += (margin->top() + margin->bottom()); panelRect = screenGeometry.adjusted(0, 0, 0, panelSize - screenGeometry.height()); unavailableArea.topWidth = panelRect.height(); unavailableArea.topStart = panelRect.left(); unavailableArea.topEnd = panelRect.right(); m_windowProxy->slideWindow(UkuiQuick::WindowProxy::TopEdge); break; case UkuiQuick::Types::Pos::Right: panelSize += (margin->left() + margin->right()); panelRect = screenGeometry.adjusted(screenGeometry.width() - panelSize, 0, 0, 0); unavailableArea.rightWidth = panelRect.width(); unavailableArea.rightStart = panelRect.top(); unavailableArea.rightEnd = panelRect.bottom(); m_windowProxy->slideWindow(UkuiQuick::WindowProxy::RightEdge); break; } QRect rect = panelRect.adjusted(margin->left(), margin->top(), -margin->right(), -margin->bottom()); container->setGeometry(rect); m_windowProxy->setGeometry(panelRect); m_unavailableArea = unavailableArea; } void PanelTopBar::updateMask() { QRegion mask; if (m_isHidden) { const int maskSize = 4; switch (mainView()->position()) { case UkuiQuick::Types::Left: mask = QRegion(0, 0, maskSize, geometry().height()); break; case UkuiQuick::Types::Top: mask = QRegion(0, 0, geometry().width(), maskSize); break; case UkuiQuick::Types::Right: mask = QRegion(geometry().width() - maskSize, 0, maskSize, geometry().height()); break; case UkuiQuick::Types::Bottom: mask = QRegion(0, geometry().height() - maskSize, geometry().width(), maskSize); break; default: break; } m_windowProxy->setBlurRegion(false); } else { m_windowProxy->setBlurRegion(true); } setMask(mask); } void PanelTopBar::initConfig() { QMap defaultList; defaultList.insert(QStringLiteral("leftMargin"), 0); defaultList.insert(QStringLiteral("topMargin"), 0); defaultList.insert(QStringLiteral("rightMargin"), 0); defaultList.insert(QStringLiteral("bottomMargin"), 0); defaultList.insert(QStringLiteral("leftPadding"), 0); defaultList.insert(QStringLiteral("topPadding"), 0); defaultList.insert(QStringLiteral("rightPadding"), 0); defaultList.insert(QStringLiteral("bottomPadding"), 0); defaultList.insert(QStringLiteral("panelTopBarSize"), PANEL_TOP_BAR_SIZE); auto config = mainView()->config(); for (const auto &key : defaultList.keys()) { if(config->getValue(key).isNull()) { config->setValue(key, defaultList.value(key)); } } // panelSize m_panelTopBarSize = config->getValue(QStringLiteral("panelTopBarSize")).isNull()? PANEL_TOP_BAR_SIZE : config->getValue(QStringLiteral("panelTopBarSize")).toInt(); // m_panelTopBarSize = 300; // container auto cont = mainView(); cont->setHost(UkuiQuick::WidgetMetadata::Host::Panel); auto margin = cont->margin(); auto padding = cont->padding(); margin->setLeft(config->getValue(QStringLiteral("leftMargin")).toInt()); margin->setTop(config->getValue(QStringLiteral("topMargin")).toInt()); margin->setRight(config->getValue(QStringLiteral("rightMargin")).toInt()); margin->setBottom(config->getValue(QStringLiteral("bottomMargin")).toInt()); padding->setLeft(config->getValue(QStringLiteral("leftPadding")).toInt()); padding->setTop(config->getValue(QStringLiteral("topPadding")).toInt()); padding->setRight(config->getValue(QStringLiteral("rightPadding")).toInt()); padding->setBottom(config->getValue(QStringLiteral("bottomPadding")).toInt()); // position int position = config->getValue(QStringLiteral("position")).isNull()? UkuiQuick::Types::Pos::Top : config->getValue(QStringLiteral("position")).toInt(); setPosition(UkuiQuick::Types::Pos(position)); // connect(cont, &UkuiQuick::WidgetContainer::activeChanged, this, &PanelTopBar::onContainerActiveChanged); } void PanelTopBar::initIslandsConfig() { auto mainViewConfig = mainView()->config(); mainViewConfig->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); //三岛默认配置 if (mainViewConfig->numberOfChildren(QStringLiteral("widgets")) == 0) { QVariantList order; QVariantMap wData; //数据岛 wData.insert(QStringLiteral("id"), "org.ukui.dataIsland"); wData.insert(QStringLiteral("instanceId"), 0); wData.insert(QStringLiteral("type"), "data"); wData.insert(QStringLiteral("minimumWidth"), 64); wData.insert(QStringLiteral("maximumWidth"), 208); mainViewConfig->addChild(QStringLiteral("widgets"), wData); order << 0; //配置岛 wData.clear(); wData.insert(QStringLiteral("id"), "org.ukui.settingsIsland"); wData.insert(QStringLiteral("instanceId"), 1); wData.insert(QStringLiteral("type"), "settings"); wData.insert(QStringLiteral("minimumWidth"), 192); wData.insert(QStringLiteral("maximumWidth"), QWINDOWSIZE_MAX); mainViewConfig->addChild(QStringLiteral("widgets"), wData); order << 1; mainViewConfig->setValue(QStringLiteral("widgetsOrder"), order); UkuiQuick::ConfigList islandsConfig = mainView()->config()->children(QStringLiteral("widgets")); for (const auto config: islandsConfig) { config->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); //每个岛中的widgets默认配置 if (config->numberOfChildren(QStringLiteral("widgets")) == 0) { // 默认加载widgets QStringList defaultWidgets; QString type = config->getValue(QStringLiteral("type")).toString(); if (type == "data") { defaultWidgets << QStringLiteral("org.ukui.menu.starter"); defaultWidgets << QStringLiteral("org.ukui.panel.idm"); defaultWidgets << QStringLiteral("org.ukui.panel.taskView"); } else { defaultWidgets << QStringLiteral("org.ukui.systemTray"); defaultWidgets << QStringLiteral("org.ukui.panel.calendar"); } qDebug() << "defaultWidgets" << type << defaultWidgets; QVariantList order; for (const auto&widget: defaultWidgets) { int instanceId = order.count(); order << instanceId; QVariantMap wData; wData.insert(QStringLiteral("id"), widget); wData.insert(QStringLiteral("instanceId"), instanceId); config->addChild(QStringLiteral("widgets"), wData); config->setValue(QStringLiteral("widgetsOrder"), order); } } } mainView()->setDisableInstances(QList{0, 1}); } } void PanelTopBar::addContainer(const QString &id) { const QStringList validId{"org.ukui.dataIsland", "org.ukui.settingsIsland"}; if(validId.contains(id)) { qDebug() << mainView()->widgets(); for(auto w : mainView()->widgets()) { if(w->id() == id) { qWarning() << id << "has already been added!"; return; } } auto mainViewConfig = mainView()->config(); UkuiQuick::ConfigList islandsConfig = mainViewConfig->children(QStringLiteral("widgets")); for(auto child : islandsConfig) { if(child->getValue(QStringLiteral("id")) == id) { mainView()->removeDisableInstance(child->id().toInt()); child->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); if(child->children(QStringLiteral("widgets")).size() != 0) { QList disableInstances; for(auto disabledWidget : mainViewConfig->getValue("disabledWidgets").toStringList()) { for (const auto &widget: child->children(QStringLiteral("widgets"))) { if (widget->getValue(QStringLiteral("id")).toString() == disabledWidget) { disableInstances.append(widget->getValue(QStringLiteral("instanceId")).toInt()); } } } QJsonArray jsonArray; for (int value : disableInstances) { jsonArray.append(value); } child->setValue(QStringLiteral("disabledInstances"), jsonArray); } mainView()->addWidget(id, child->id().toInt()); for (UkuiQuick::Widget* w: mainView()->widgets()) { if(w->id() == id) { if (id == QStringLiteral("org.ukui.dataIsland")) { w->setActions(m_dataIslandActions); } else if (id == QStringLiteral("org.ukui.settingsIsland")) { w->setActions(m_settingsIslandActions); } m_islands.insert(w->id(), dynamic_cast(w)); break; } } break; } } } } void PanelTopBar::loadActions() { auto settings = new QAction(tr("Panel Settings"), this); connect(settings, &QAction::triggered, this, [] { UkuiQuick::AppLauncher::instance()->launchAppWithArguments( QStringLiteral("/usr/share/applications/ukui-control-center.desktop"), {"-m", "Panel"}); }); m_dataIslandActions << settings; m_settingsIslandActions << settings; auto showDesktop = new QAction(tr("Show Desktop"), this); connect(showDesktop, &QAction::triggered, this, [] { UkuiQuick::WindowManager::setShowingDesktop(!UkuiQuick::WindowManager::showingDesktop()); }); m_dataIslandActions << showDesktop; m_settingsIslandActions << showDesktop; auto systemMonitor = new QAction(tr("System Monitor"), this); connect(systemMonitor, &QAction::triggered, this, [] { UkuiQuick::AppLauncher::instance()->launchApp( QStringLiteral("/usr/share/applications/ukui-system-monitor.desktop")); }); m_dataIslandActions << systemMonitor; m_settingsIslandActions << systemMonitor; initIslandFormAction(); m_dataIslandActions << m_dataIslandFormAction; m_settingsIslandActions << m_settingsIslandFormAction; auto switchPanel = new QAction(tr("Switch to Classical Panel"), this); connect(switchPanel, &QAction::triggered, this, [] { QTimer::singleShot(1, []() { Shell::self()->switchTo(Shell::PanelType::Version4); }); }); m_dataIslandActions << switchPanel; m_settingsIslandActions << switchPanel; for (auto island: m_islands) { if (island->id() == QStringLiteral("org.ukui.dataIsland")) { island->setActions(m_dataIslandActions); } else if (island->id() == QStringLiteral("org.ukui.settingsIsland")) { island->setActions(m_settingsIslandActions); } } } void PanelTopBar::changeForm(const QString& id, GeneralConfigDefine::IslandsForm form) { if(form == GeneralConfigDefine::IslandsForm::TopBar) { addContainer(id); } else { if(m_islands.contains(id)) { mainView()->addDisableInstance(m_islands.value(id)->config()->id().toInt()); m_islands.remove(id); Q_EMIT islandRemoved(id); } } } void PanelTopBar::initIslandFormAction() { //数据岛特有aciton m_dataIslandFormAction = new QAction(tr("Data Island Form"), this); m_dataIslandFormAction->setMenu(new QMenu()); m_menus.append(m_dataIslandFormAction->menu()); auto group0 = new QActionGroup(m_dataIslandFormAction); QAction* action = m_dataIslandFormAction->menu()->addAction(tr("Islands")); action->setCheckable(true); group0->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::Panel); action = m_dataIslandFormAction->menu()->addAction(tr("Top Bar")); action->setCheckable(true); group0->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::TopBar); connect(group0, &QActionGroup::triggered, this, [this](QAction* action) { auto form = action->property("form").value(); changeForm(QStringLiteral("org.ukui.dataIsland"), form); }); //配置岛特有action m_settingsIslandFormAction = new QAction(tr("Settings Island Form"), this); m_settingsIslandFormAction->setMenu(new QMenu()); m_menus.append(m_settingsIslandFormAction->menu()); auto group1 = new QActionGroup(m_dataIslandFormAction); action = m_settingsIslandFormAction->menu()->addAction(tr("Islands")); action->setCheckable(true); group1->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::Panel); action = m_settingsIslandFormAction->menu()->addAction(tr("Top Bar")); action->setCheckable(true); group1->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::TopBar); connect(group1, &QActionGroup::triggered, this, [this](QAction* action) { auto form = action->property("form").value(); changeForm(QStringLiteral("org.ukui.settingsIsland"), form); }); updateIslandFormAction(); } void PanelTopBar::updateIslandFormAction() { bool containDataIsland = false; bool containSettingsIsland = false; for(auto island : m_islands) { if(island->id() == QStringLiteral("org.ukui.dataIsland")) { containDataIsland = true; } else if(island->id() == QStringLiteral("org.ukui.settingsIsland")) { containSettingsIsland = true; } } for(auto action : m_dataIslandFormAction->menu()->actions()) { auto form = action->property("form").value(); action->setChecked(form == GeneralConfigDefine::IslandsForm::TopBar && containDataIsland); } for(auto action : m_settingsIslandFormAction->menu()->actions()) { auto form = action->property("form").value(); action->setChecked(form == GeneralConfigDefine::IslandsForm::TopBar && containSettingsIsland); } } void PanelTopBar::updateDisableWidget() { //初始化disableWidgets auto mainViewConfig = mainView()->config(); if(!mainViewConfig->getValue(QStringLiteral("disabledWidgets")).isValid()) { mainViewConfig->setValue(QStringLiteral("disabledWidgets"), QStringList()); } m_disabledWidgets = mainViewConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); UkuiQuick::ConfigList islandsConfig = mainViewConfig->children(QStringLiteral("widgets")); for(auto child : islandsConfig) { child->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); if(child->children(QStringLiteral("widgets")).size() == 0) { continue; } QList disableInstances; for(auto disabledWidget : m_disabledWidgets) { for (const auto &widget: child->children(QStringLiteral("widgets"))) { if (widget->getValue(QStringLiteral("id")).toString() == disabledWidget) { disableInstances.append(widget->getValue(QStringLiteral("instanceId")).toInt()); } } } QJsonArray jsonArray; for (int value : disableInstances) { jsonArray.append(value); } child->setValue(QStringLiteral("disabledInstances"), jsonArray); } connect(mainView()->config(), &UkuiQuick::Config::configChanged, this, [this] (const QString &key) { if (key == QStringLiteral("disabledWidgets")) { QStringList disabledWidgets = mainView()->config()->getValue(key).toStringList(); if (disabledWidgets == m_disabledWidgets) { return; } QStringList tmp; tmp.append(disabledWidgets); tmp.append(m_disabledWidgets); tmp.removeDuplicates(); for (const auto &item : tmp) { disableWidget(item, disabledWidgets.contains(item)); } } }); } void PanelTopBar::disableWidget(const QString &id, bool disable) { if (disable) { // 禁用 if (m_disabledWidgets.contains(id)) { return; } m_disabledWidgets.append(id); // 卸载全部widget for(auto island : m_islands) { QVector widgets = island->widgets(); QList instances; for (const auto &item: widgets) { if (item->id() == id) { instances.append(item->instanceId()); } } instances.append(island->disableInstances()); island->setDisableInstances(instances); } } else { // 启用 if (m_disabledWidgets.removeAll(id) == 0) { return; } // 重新激活全部widget for(auto island : m_islands) { UkuiQuick::ConfigList children = island->config()->children(QStringLiteral("widgets")); for (const auto &child : children) { const QString widgetId = child->getValue(QStringLiteral("id")).toString(); if (widgetId == id) { island->removeDisableInstance(child->id().toInt()); island->addWidget(widgetId, child->id().toInt()); } } } } } void PanelTopBar::updateIslandState() { int dataIslandPosition = 0, settingsIslandPosition = 0; for (UkuiQuick::Widget* widget : mainView()->widgets()) { if (widget->id() == "org.ukui.dataIsland") { dataIslandPosition = 1; } if (widget->id() == "org.ukui.settingsIsland") { settingsIslandPosition = 1; } } PanelGSettings::instance()->setIslandPosition("org.ukui.dataIsland", dataIslandPosition); PanelGSettings::instance()->setIslandPosition("org.ukui.settingsIsland", settingsIslandPosition); } void PanelTopBar::setTopBarSize(int size) { PanelGSettings::instance()->setTopBarSize(size); } } ukui-panel/panel/src/view/common.h0000664000175000017500000000410315167645100016056 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #ifndef UKUI_PANEL_COMMON_H #define UKUI_PANEL_COMMON_H #include namespace UkuiPanel { /** * 屏幕不可用区域 * 一般存在于屏幕四周 */ class UnavailableArea { public: int leftWidth = 0; int leftStart = 0; int leftEnd = 0; int rightWidth = 0; int rightStart = 0; int rightEnd = 0; int topWidth = 0; int topStart = 0; int topEnd = 0; int bottomWidth = 0; int bottomStart = 0; int bottomEnd = 0; }; class NumberSetting { public: NumberSetting(QString k, int d, int l, int r) : key(std::move(k)), defaultValue(d), min(l), max(r) {} QString key; int defaultValue{0}; int min{0}; int max{0}; }; /* * 配置文件版本号 * 由于历史原因,panel的版本号曾经使用主版本CONFIG_VERSION号记录,所以将主版本号从 空 或 1.0 改为 1.1的操作在panel中进行 * 在后续版本中,主版本号的兼容操作需要放到shell中进行,且 * panel的版本号使用PANEL_CONFIG_VERSION记录 * panel-next的版本号使用PANEL_NEXT_CONFIG_VERSION记录 * panel-top-bar的版本号使用PANEL_TOP_BAR_CONFIG_VERSION记录 */ #define CONFIG_VERSION "1.1" #define PANEL_CONFIG_VERSION "1.0" #define PANEL_NEXT_CONFIG_VERSION "1.0" #define PANEL_TOP_BAR_CONFIG_VERSION "1.0" #define QWINDOWSIZE_MAX ((1<<24)-1) } #endif //UKUI_PANEL_COMMON_H ukui-panel/panel/src/view/panel-top-bar.h0000664000175000017500000000606515167645100017240 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #ifndef PANEL_TOP_BAR_H #define PANEL_TOP_BAR_H #include #include #include "screens-manager.h" #include "general-config-define.h" #include "common.h" namespace UkuiPanel { class PanelTopBar : public UkuiQuick::IslandView { Q_OBJECT public: PanelTopBar(Screen* screen, const QString&id, QWindow* parent = nullptr); ~PanelTopBar(); void setTopBarScreen(Screen* screen); void addIsland(const QString &id); void removeIsland(const QString &id); void dragRemove(const QString &id); void dragAdding(const QString &id, bool addWhenDrop); Q_SIGNALS: void islandRemoved(const QString &id); private Q_SLOTS: void onScreenGeometryChanged(const QRect&geometry); void resetWorkArea(bool cut); void setPosition(UkuiQuick::Types::Pos position); void updateVisbility(); void setAutoHide(bool autoHide); void setHidden(bool hidden); void activeHideTimer(bool active = true); void onWidgetAdded(UkuiQuick::Widget *widget); void onWidgetRemoved(UkuiQuick::Widget *widget); private: void initMainContainer(); void updateGeometry(); void refreshRect(); void updateMask(); void initConfig(); void initIslandsConfig(); void addContainer(const QString &id); void loadActions(); void changeForm(const QString &id, GeneralConfigDefine::IslandsForm form); void initIslandFormAction(); void updateIslandFormAction(); void updateDisableWidget(); void disableWidget(const QString &id, bool disable); void updateIslandState(); void setTopBarSize(int size); QString m_id; UkuiQuick::WindowProxy *m_windowProxy = nullptr; Screen *m_screen {nullptr}; int m_panelTopBarSize {32}; UnavailableArea m_unavailableArea; GeneralConfigDefine::PanelSizePolicy m_sizePolicy {GeneralConfigDefine::Small}; bool m_isHidden = true; bool m_autoHide = false; bool m_lockPanel = false; QTimer *m_hideTimer = nullptr; QMap m_islands; QList m_dataIslandActions; QList m_settingsIslandActions; QList m_menus; //用于QMenu的统一销毁 QAction* m_dataIslandFormAction{nullptr}; QAction* m_settingsIslandFormAction{nullptr}; bool m_dragAdding = false; QStringList m_disabledWidgets; }; } #endif //PANEL_TOP_BAR_H ukui-panel/panel/src/view/panel.cpp0000664000175000017500000014457415167645111016243 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * iaom */ #include "panel.h" #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "general-config-define.h" #include "widget-model.h" #include "shell.h" #include "data-collector.h" namespace UkuiPanel { #define DEFAULT_PANEL_SIZE 48 #define UKUI_PANEL_SETTINGS_ID "org.ukui.panel.settings" #define UKUI_PANEL_SETTINGS_PATH "/org/ukui/panel/settings/" Q_LOGGING_CATEGORY(PANEL_PANEL, "org.ukui.panel.panel") // 如果需要不同Panel加载不同的Config,将id设置为不同即可 Panel::Panel(Screen *screen, const QString &id, QWindow *parent) : UkuiQuick::IslandView(QStringLiteral("panel"), QStringLiteral("ukui-panel")), m_id(id) { qRegisterMetaType>(); qmlRegisterType("org.ukui.panel.impl", 1, 0, "WidgetSortModel"); rootContext()->setContextProperty("panel", this); m_lastConfigVersion = config()->getValue(QStringLiteral("panelConfigVersion")).toString(); initIsland(); setColor(Qt::transparent); setFlags(flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus); m_windowProxy = new UkuiQuick::WindowProxy(this); m_windowProxy->setWindowType(UkuiQuick::WindowType::Dock); // contents setPanelScreen(screen); //基础配置 initConfig(); // 加载widgets配置 loadWidgetsConfig(); setShowSystemTrayStatus(); loadMainViewItem(); // 加载任务栏额外设置项 initPanelConfig(); // m_autoHideAction需要先同步配置文件,再加载 loadActions(); // 用于执行隐藏的定时器 m_hideTimer = new QTimer(this); m_hideTimer->setSingleShot(true); m_hideTimer->setInterval(500); connect(m_hideTimer, &QTimer::timeout, this, [this] { setHidden(true); }); updateHideState(); // 初始化gsettings,将已经初始化完成的值更新到gsettings中 initGsettings(); // 自定义拖拽大小,更新毛玻璃区域 connect(this, &QQuickView::widthChanged, this, [this]() { if (m_isResizingPanel && (mainView()->orientation() == UkuiQuick::Types::Vertical)) { calculatePanelRectFromSize(width() - mainView()->margin()->right() - mainView()->margin()->left()); updateMask(); setGSettings(QStringLiteral("panelsize"), m_windowRegion.width()); } }); connect(this, &QQuickView::heightChanged, this, [this]() { if (m_isResizingPanel && (mainView()->orientation() == UkuiQuick::Types::Horizontal)) { calculatePanelRectFromSize(height() - mainView()->margin()->bottom() - mainView()->margin()->top()); updateMask(); setGSettings(QStringLiteral("panelsize"), m_windowRegion.height()); } }); UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-v11")); onFunctionControlChanged(QStringLiteral("ukui-panel-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-v11"), true); }); m_startUp = false; qCDebug(PANEL_PANEL) << "panel init finished with id:" << m_id; } Panel::~Panel() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-v11")); } void Panel::initIsland() { const QString defaultViewId = QStringLiteral("org.ukui.panel"); // 添加panel包所在的qrc路径 UkuiQuick::WidgetContainer::widgetLoader().addWidgetSearchPath(QStringLiteral(":/ukui-panel")); // TODO: 配置错误检查 if (!loadMainViewWithoutItem(defaultViewId)) { // 全部使用默认配置 auto metadata = UkuiQuick::WidgetMetadata(QStringLiteral(":/ukui-panel/org.ukui.panel")); auto cont = new UkuiQuick::WidgetContainer(metadata, this); cont->setConfig(UkuiQuick::ConfigLoader::getConfig(QStringLiteral("panel"))); setMainView(cont); } } void Panel::setPanelScreen(Screen *screen) { if (!screen || screen == m_screen) { return; } if (m_screen) { m_screen->disconnect(this); } m_screen = screen; setScreen(screen->internal()); mainView()->setScreen(screen->internal()); updateGeometry(); connect(screen, &Screen::geometryChanged, this, &Panel::onScreenGeometryChanged); } void Panel::onScreenGeometryChanged(const QRect &geometry) { Q_UNUSED(geometry) updateLimitSize(); updateGeometry(); } void Panel::onConfigChanged(const QString& key) { auto configValue = mainView()->config()->getValue(key); if (key == QStringLiteral("position")) { setPosition(UkuiQuick::Types::Pos(configValue.toInt()), false); } else if (key == QStringLiteral("panelSize")) { setPanelSize(configValue.value(), false); } else if (key == QStringLiteral("panelSizePolicy")) { setPanelPolicy(configValue.value(), false); } else if (key == QStringLiteral("panelAutoHide")) { setAutoHide(configValue.toBool(), false); } else if (key == QStringLiteral("lockPanel")) { setLockPanel(configValue.toBool(), false); } else if (key == QStringLiteral("showSystemTrayOnAllPanels")) { //根据托盘是否显示在任务栏上面的值更新托盘的启用状态 if (configValue.toBool()) { mainView()->addWidget(QStringLiteral("org.ukui.systemTray"), m_systemTrayInstance); } else { if (m_screen->internal() != qApp->primaryScreen()) { mainView()->removeWidget(QStringLiteral("org.ukui.systemTray")); } } } else if (key == QStringLiteral("disabledWidgets")) { QStringList disabledWidgets = configValue.toStringList(); if (disabledWidgets == m_disabledWidgets) { return; } QStringList tmp; tmp.append(disabledWidgets); tmp.append(m_disabledWidgets); tmp.removeDuplicates(); for (const auto&item : tmp) { disableWidget(item, disabledWidgets.contains(item)); } } } void Panel::initPanelConfig() { auto config = mainView()->config(); QVariant value = config->getValue(QStringLiteral("lockPanel")); if (!value.isValid()) { value = false; config->setValue(QStringLiteral("lockPanel"), value); } setLockPanel(value.toBool(), false); value = config->getValue(QStringLiteral("panelAutoHide")); if (!value.isValid()) { value = false; config->setValue(QStringLiteral("panelAutoHide"), value); } m_autoHide = value.toBool(); resetWorkArea(!m_autoHide); connect(config, &UkuiQuick::Config::configChanged, this, &Panel::onConfigChanged); } void Panel::initConfig() { // border, margin QMap defaultList; defaultList.insert(QStringLiteral("leftMargin"), 0); defaultList.insert(QStringLiteral("topMargin"), 0); defaultList.insert(QStringLiteral("rightMargin"), 0); defaultList.insert(QStringLiteral("bottomMargin"), 0); defaultList.insert(QStringLiteral("leftPadding"), 0); defaultList.insert(QStringLiteral("topPadding"), 0); defaultList.insert(QStringLiteral("rightPadding"), 0); defaultList.insert(QStringLiteral("bottomPadding"), 0); defaultList.insert(QStringLiteral("panelMinimumSize"), 48); defaultList.insert(QStringLiteral("panelMaximumSize"), 92); defaultList.insert(QStringLiteral("panelSize"), DEFAULT_PANEL_SIZE); defaultList.insert(QStringLiteral("panelDefaultSize"), DEFAULT_PANEL_SIZE); defaultList.insert(QStringLiteral("radius"), 0); defaultList.insert(QStringLiteral("position"), UkuiQuick::Types::Pos::Bottom); defaultList.insert(QStringLiteral("panelSizePolicy"), GeneralConfigDefine::Small); defaultList.insert(QStringLiteral("lockPanel"), false); defaultList.insert(QStringLiteral("panelAutoHide"), false); auto viewConfig = mainView()->config(); // 当前版本号不等于PANEL_CONFIG_VERSION时,配置文件内容更新 if (CONFIG_VERSION != m_lastConfigVersion) { if (m_lastConfigVersion.isEmpty()) { for (const auto&key : defaultList.keys()) { if (!config()->getValue(key).isNull()) { defaultList.insert(key, config()->getValue(key).toInt()); config()->removeKey(key); } if (viewConfig->getValue(key).isNull()) { viewConfig->setValue(key, defaultList.value(key)); } } config()->setValue(QStringLiteral("panelConfigVersion"), CONFIG_VERSION); } else if (m_lastConfigVersion == "1.0") { // 1.0 -> 1.1版本更改默认padding值为0(原来默认值为2),如果用户之前设置过padding将不会修改 QStringList paddingList = {"bottomPadding", "leftPadding", "topPadding", "rightPadding"}; for (const auto padding : paddingList) { if (viewConfig->getValue(padding).toInt() == 2 || viewConfig->getValue(padding).isNull()) { viewConfig->setValue(padding, defaultList.value(padding)); } } config()->setValue(QStringLiteral("panelConfigVersion"), CONFIG_VERSION); } else { for (const auto&key : defaultList.keys()) { viewConfig->setValue(key, defaultList.value(key)); } } } for (const auto &key : defaultList.keys()) { if(viewConfig->getValue(key).isNull()) { viewConfig->setValue(key, defaultList.value(key)); } } // panelSize m_panelMaxSize = viewConfig->getValue(QStringLiteral("panelMaximumSize")).isNull()? 92 : viewConfig->getValue(QStringLiteral("panelMaximumSize")).toInt(); m_panelMinSize = viewConfig->getValue(QStringLiteral("panelMinimumSize")).isNull()? 48 : viewConfig->getValue(QStringLiteral("panelMinimumSize")).toInt(); int policy = viewConfig->getValue(QStringLiteral("panelSizePolicy")).isNull()? GeneralConfigDefine::Medium : viewConfig->getValue(QStringLiteral("panelSizePolicy")).toInt(); if(policy == GeneralConfigDefine::Custom) { m_panelSize = viewConfig->getValue(QStringLiteral("customPanelSize")).isNull()? DEFAULT_PANEL_SIZE : viewConfig->getValue(QStringLiteral("customPanelSize")).toInt(); } else { m_panelSize = viewConfig->getValue(QStringLiteral("panelSize")).isNull()? DEFAULT_PANEL_SIZE : viewConfig->getValue(QStringLiteral("panelSize")).toInt(); } setPanelPolicy(static_cast(policy), false); // container auto cont = mainView(); cont->setHost(UkuiQuick::WidgetMetadata::Host::Panel); cont->setRadius(viewConfig->getValue(QStringLiteral("radius")).toInt()); auto margin = cont->margin(); auto padding = cont->padding(); margin->setLeft(viewConfig->getValue(QStringLiteral("leftMargin")).toInt()); margin->setTop(viewConfig->getValue(QStringLiteral("topMargin")).toInt()); margin->setRight(viewConfig->getValue(QStringLiteral("rightMargin")).toInt()); margin->setBottom(viewConfig->getValue(QStringLiteral("bottomMargin")).toInt()); padding->setLeft(viewConfig->getValue(QStringLiteral("leftPadding")).toInt()); padding->setTop(viewConfig->getValue(QStringLiteral("topPadding")).toInt()); padding->setRight(viewConfig->getValue(QStringLiteral("rightPadding")).toInt()); padding->setBottom(viewConfig->getValue(QStringLiteral("bottomPadding")).toInt()); // position int position = viewConfig->getValue(QStringLiteral("position")).isNull()? UkuiQuick::Types::Pos::Bottom : viewConfig->getValue(QStringLiteral("position")).toInt(); setPosition(static_cast(position), false); connect(cont, &UkuiQuick::WidgetContainer::activeChanged, this, &Panel::updateHideState); } void Panel::setPosition(UkuiQuick::Types::Pos position, bool updateConfig) { auto container = Panel::mainView(); if (position != container->position()) { switch (position) { case UkuiQuick::Types::Left: m_panelPosition = 2; break; case UkuiQuick::Types::Top: m_panelPosition = 1; break; case UkuiQuick::Types::Right: m_panelPosition = 3; break; default: case UkuiQuick::Types::Bottom: m_panelPosition = 0; position = UkuiQuick::Types::Pos::Bottom; break; } container->setPosition(position); if (position == UkuiQuick::Types::Left || position == UkuiQuick::Types::Right) { container->setOrientation(UkuiQuick::Types::Vertical); } else { container->setOrientation(UkuiQuick::Types::Horizontal); } updateLimitSize(); hide(); updateGeometry(); show(); setGSettings(QStringLiteral("panelposition"), m_panelPosition); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("position"), position); DataCollector::setPanelPositionEvent(m_panelPosition); } } if (m_positionAction) { updatePositionAction(); } } void Panel::setPanelSize(int size, bool updateConfig) { if (size == m_panelSize) { return; } if (size < m_panelMinSize) { size = m_panelMinSize; } else if (size > m_panelMaxSize) { size = m_panelMaxSize; } m_panelSize = size; updateGeometry(); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("panelSize"), m_panelSize); setGSettings(QStringLiteral("panelsize"), mainView()->orientation() == UkuiQuick::Types::Horizontal ? m_windowRegion.height() : m_windowRegion.width()); DataCollector::setPanelSizeEvent(m_panelSize); } } void Panel::loadWidgetsConfig() { auto containerConfig = mainView()->config(); containerConfig->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); QVector> positionedWidgets { {QStringLiteral("org.ukui.menu.starter"), 0}, {QStringLiteral("org.ukui.panel.search"), 0}, {QStringLiteral("org.ukui.panel.taskView"), 0}, {QStringLiteral("org.ukui.panel.separator"), 0}, {QStringLiteral("org.ukui.panel.taskManager"), 0}, {QStringLiteral("org.ukui.systemTray"), 1}, {QStringLiteral("org.ukui.panel.calendar"), 1}, {QStringLiteral("org.ukui.ai.assistant"), 1}, {QStringLiteral("org.ukui.panel.showDesktop"), 1} }; if (containerConfig->numberOfChildren(QStringLiteral("widgets")) == 0 ) { // 默认加载widgets QVariantList order; for (const auto& widgetPair : positionedWidgets) { int instanceId = order.count(); order << instanceId; QVariantMap wData; wData.insert(QStringLiteral("id"), widgetPair.first); wData.insert(QStringLiteral("instanceId"), instanceId); wData.insert(QStringLiteral("layoutIndex"), widgetPair.second); containerConfig->addChild(QStringLiteral("widgets"), wData); if(widgetPair.first == QStringLiteral("org.ukui.systemTray")) { m_systemTrayInstance = instanceId; } mainView()->addWidget(widgetPair.first, instanceId); } containerConfig->setValue(QStringLiteral("widgetsOrder"), order); containerConfig->setValue(QStringLiteral("disabledWidgets"), QStringList()); } //1.0增加AI助手按钮 放在右起第二个 if (containerConfig->getValue(QStringLiteral("panelConfigVersion")).toString() != PANEL_CONFIG_VERSION) { auto configList = containerConfig->children("widgets"); bool needAdd = true; for (auto widgetConfig : configList) { if (widgetConfig->getValue(QStringLiteral("id")).toString() == QStringLiteral("org.ukui.ai.assistant")) { needAdd = false; break; } } //增加AI助手按钮 if (needAdd) { QVariantMap wData; int instanceId = configList.count(); wData.insert(QStringLiteral("id"), QStringLiteral("org.ukui.ai.assistant")); wData.insert(QStringLiteral("instanceId"), instanceId); wData.insert(QStringLiteral("layoutIndex"), 1); containerConfig->addChild(QStringLiteral("widgets"), wData); mainView()->addWidget(QStringLiteral("org.ukui.ai.assistant"), instanceId); QVariantList order = containerConfig->getValue(QStringLiteral("widgetsOrder")).toList(); order.insert(order.count() - 1, instanceId); containerConfig->setValue(QStringLiteral("widgetsOrder"), order); } containerConfig->setValue(QStringLiteral("panelConfigVersion"), PANEL_CONFIG_VERSION); } // 添加layoutIndex for (auto widgetConfig : containerConfig->children("widgets")) { if (!widgetConfig->contains("layoutIndex")) { QString id = widgetConfig->getValue("id").toString(); auto it = std::find_if(positionedWidgets.begin(), positionedWidgets.end(), [&](const QPair &pair) { return pair.first == id;}); if (it != positionedWidgets.end()) { widgetConfig->setValue("layoutIndex", it->second); } else { widgetConfig->setValue("layoutIndex", -1); } } } m_disabledWidgets = containerConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); // 卸载插件选项 QStringList canRemove; canRemove << QStringLiteral("org.ukui.panel.search"); canRemove << QStringLiteral("org.ukui.panel.taskView"); for (const auto &widgetPair : positionedWidgets) { QString wid = widgetPair.first; if (canRemove.contains(wid)) { UkuiQuick::WidgetMetadata metadata = UkuiQuick::WidgetContainer::widgetLoader().loadMetadata(wid); if (!metadata.isValid()) { continue; } QString actionName = QString(tr("Show")) + metadata.name(); auto action = new QAction(actionName); action->setProperty("widget", wid); action->setCheckable(true); action->setChecked(!m_disabledWidgets.contains(wid)); if (wid == "org.ukui.panel.search") { action->setIcon(QIcon::fromTheme("kylin-search")); } else if (wid == "org.ukui.panel.taskView") { action->setIcon(QIcon::fromTheme("ukui-taskview-symbolic")); } m_widgetActions << action; connect(action, &QAction::triggered, this, [this, action] { widgetActionTriggered(action); }); } } } void Panel::updateGeometry() { calculatePanelRectFromSize(m_panelSize); setGeometry(); updateMask(); resetWorkArea(!m_autoHide); } void Panel::setGeometry() { switch (Panel::mainView()->position()) { default: case UkuiQuick::Types::Pos::Bottom: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::BottomEdge); break; case UkuiQuick::Types::Pos::Left: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::LeftEdge); break; case UkuiQuick::Types::Pos::Top: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::TopEdge); break; case UkuiQuick::Types::Pos::Right: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::RightEdge); break; } // TODO: 使用WindowProxy2 m_windowProxy->setGeometry(m_windowRegion); } void Panel::initGsettings() { if (QGSettings::isSchemaInstalled(UKUI_PANEL_SETTINGS_ID)) { m_settings = new QGSettings(UKUI_PANEL_SETTINGS_ID, UKUI_PANEL_SETTINGS_PATH, this); setGSettings(QStringLiteral("panelposition"), m_panelPosition); setGSettings(QStringLiteral("panelsize"), mainView()->orientation() == UkuiQuick::Types::Horizontal ? m_windowRegion.height() : m_windowRegion.width()); setGSettings(QStringLiteral("hidepanel"), m_autoHide); setGSettings(QStringLiteral("lockpanel"), m_lockPanel); } } void Panel::calculatePanelRectFromSize(int panelSize) { auto container = Panel::mainView(); const auto margin = container->margin(); // panelRect 为实际占用的区域,包括外边距(margin) QRect screenGeometry = container->screen()->geometry(), panelRect; if (screenGeometry.width() <= 0 || screenGeometry.height() <= 0) { screenGeometry.setSize({1920, 1080}); } UnavailableArea unavailableArea; switch (container->position()) { default: case UkuiQuick::Types::Pos::Bottom: panelSize += (margin->top() + margin->bottom()); panelRect = screenGeometry.adjusted(0, screenGeometry.height() - panelSize, 0, 0); unavailableArea.bottomWidth = panelRect.height(); unavailableArea.bottomStart = panelRect.left(); unavailableArea.bottomEnd = panelRect.right(); break; case UkuiQuick::Types::Pos::Left: panelSize += (margin->left() + margin->right()); panelRect = screenGeometry.adjusted(0, 0, panelSize - screenGeometry.width(), 0); unavailableArea.leftWidth = panelRect.width(); unavailableArea.leftStart = panelRect.top(); unavailableArea.leftEnd = panelRect.bottom(); break; case UkuiQuick::Types::Pos::Top: panelSize += (margin->top() + margin->bottom()); panelRect = screenGeometry.adjusted(0, 0, 0, panelSize - screenGeometry.height()); unavailableArea.topWidth = panelRect.height(); unavailableArea.topStart = panelRect.left(); unavailableArea.topEnd = panelRect.right(); break; case UkuiQuick::Types::Pos::Right: panelSize += (margin->left() + margin->right()); panelRect = screenGeometry.adjusted(screenGeometry.width() - panelSize, 0, 0, 0); unavailableArea.rightWidth = panelRect.width(); unavailableArea.rightStart = panelRect.top(); unavailableArea.rightEnd = panelRect.bottom(); break; } QRect rect = panelRect.adjusted(margin->left(), margin->top(), -margin->right(), -margin->bottom()); container->setGeometry(rect); m_windowRegion = panelRect; m_unavailableArea = unavailableArea; } void Panel::updateLimitSize() { auto container = Panel::mainView(); const auto margin = container->margin(); if (container->orientation() == UkuiQuick::Types::Vertical) { setMaximumWidth(m_panelMaxSize + (margin->left() + margin->right())); setMinimumWidth(m_panelMinSize + (margin->left() + margin->right())); setMaximumHeight(container->screen()->geometry().height()); } else { setMaximumHeight(m_panelMaxSize + (margin->top() + margin->bottom())); setMinimumHeight(m_panelMinSize + (margin->top() + margin->bottom())); setMaximumWidth(container->screen()->geometry().width()); } } void Panel::setPanelPolicy(GeneralConfigDefine::PanelSizePolicy sizePolicy, bool updateConfig) { if (sizePolicy != m_sizePolicy) { switch (sizePolicy) { default: case GeneralConfigDefine::Small: m_sizePolicy = GeneralConfigDefine::Small; setPanelSize(48); break; case GeneralConfigDefine::Medium: m_sizePolicy = GeneralConfigDefine::Medium; setPanelSize(72); break; case GeneralConfigDefine::Large: m_sizePolicy = GeneralConfigDefine::Large; setPanelSize(92); break; case GeneralConfigDefine::Custom: m_sizePolicy = GeneralConfigDefine::Custom; setPanelSize(mainView()->config()->getValue(QStringLiteral("customPanelSize")).toInt()); break; } if (updateConfig) { mainView()->config()->setValue(QStringLiteral("panelSizePolicy"), m_sizePolicy); } emit enableCustomSizeChanged(); } if (m_sizeAction) { updateSizeAction(); } } void Panel::widgetActionTriggered(const QAction *action) { QString id = action->property("widget").toString(); if (id.isEmpty()) { return; } disableWidget(id, !action->isChecked()); mainView()->config()->setValue(QStringLiteral("disabledWidgets"), m_disabledWidgets); } void Panel::disableWidget(const QString &id, bool disable) { if (disable) { // 禁用 if (m_disabledWidgets.contains(id)) { return; } m_disabledWidgets.append(id); // 卸载全部widget QVector widgets = mainView()->widgets(); QList instances; for (const auto &item: widgets) { if (item->id() == id) { instances.append(item->instanceId()); } } instances.append(mainView()->disableInstances()); mainView()->setDisableInstances(instances); } else { // 启用 if (m_disabledWidgets.removeAll(id) == 0) { return; } // 重新激活全部widget UkuiQuick::ConfigList children = mainView()->config()->children(QStringLiteral("widgets")); for (const auto &child : children) { const QString widgetId = child->getValue(QStringLiteral("id")).toString(); if (widgetId == id) { mainView()->removeDisableInstance(child->id().toInt()); mainView()->addWidget(widgetId, child->id().toInt()); } } } for (const auto &action: m_widgetActions) { if (action->property("widget").toString() == id) { action->setChecked(!disable); break; } } } void Panel::loadActions() { QList actions; // widget操作 actions << m_widgetActions; // 分割线 auto *separator = new QAction(this); separator->setSeparator(true); actions << separator; auto showDesktop = new QAction(QIcon::fromTheme("desktop-symbolic"), tr("Show Desktop"), this); showDesktop->setProperty("id", "show-desktop"); connect(showDesktop, &QAction::triggered, this, [] { UkuiQuick::WindowManager::setShowingDesktop(!UkuiQuick::WindowManager::showingDesktop()); }); actions << showDesktop; auto systemMonitor = new QAction(QIcon::fromTheme("ukui-system-monitor"), tr("System Monitor"), this); systemMonitor->setProperty("id", "system-monitor"); connect(systemMonitor, &QAction::triggered, this, [] { UkuiQuick::AppLauncher::instance()->launchApp(QStringLiteral("/usr/share/applications/ukui-system-monitor.desktop")); }); actions << systemMonitor; // 分割线 auto *separator2 = new QAction(this); separator2->setSeparator(true); actions << separator2; // actions initSizeAction(); initPositionAction(); initLockPanelAction(); // 调整大小 actions << m_sizeAction; // 调整位置 actions << m_positionAction; actions << m_lockPanelAction; // 自动隐藏 m_autoHideAction = new QAction(QIcon::fromTheme("ukui-taskbar-hide-symbolic"), tr("Auto Hide"), this); m_autoHideAction->setProperty("id", "panelAutoHide"); m_autoHideAction->setCheckable(true); m_autoHideAction->setChecked(m_autoHide); connect(m_autoHideAction, &QAction::triggered, this, [this] { setAutoHide(m_autoHideAction->isChecked()); }); actions << m_autoHideAction; auto switchPanel = new QAction(tr("Switch to New Panel"), this); switchPanel->setProperty("id", "switch-to-new-panel"); connect(switchPanel, &QAction::triggered, this, [] { QTimer::singleShot(1, [](){ Shell::self()->switchTo(Shell::PanelType::Version5); }); }); actions << switchPanel; // 分割线 auto *separator3 = new QAction(this); separator3->setSeparator(true); actions << separator3; auto panelSetting = new QAction(QIcon::fromTheme("settings-app-symbolic"), tr("Panel Setting"), this); panelSetting->setProperty("id", "panel-setting"); connect(panelSetting, &QAction::triggered, this, [] { UkuiQuick::AppLauncher::instance()->launchAppWithArguments(QStringLiteral("/usr/share/applications/ukui-control-center.desktop"), {"-m", "Panel"}); }); actions << panelSetting; mainView()->setActions(actions); } void Panel::initSizeAction() { auto *sizeAction = new QAction(QIcon::fromTheme("ukui-taskbar-size-symbolic"), tr("Panel Size"), this); sizeAction->setMenu(new QMenu()); QAction *action = sizeAction->menu()->addAction(tr("Large")); action->setProperty("sizePolicy", GeneralConfigDefine::Large); action = sizeAction->menu()->addAction(tr("Medium")); action->setProperty("sizePolicy", GeneralConfigDefine::Medium); action = sizeAction->menu()->addAction(tr("Small")); action->setProperty("sizePolicy", GeneralConfigDefine::Small); auto customAction = new QAction(tr("Custom")); sizeAction->menu()->addAction(customAction); customAction->setProperty("sizePolicy", GeneralConfigDefine::Custom); customAction->setEnabled(mainView()->config()->contains(QStringLiteral("customPanelSize"))); connect(sizeAction->menu(), &QMenu::triggered, this, [this](QAction *action) { auto sizePolicy = action->property("sizePolicy").value(); setPanelPolicy(sizePolicy); }); m_sizeAction = sizeAction; m_sizeAction->setProperty("id", "panelSizePolicy"); updateSizeAction(); } void Panel::updateSizeAction() { for (const auto &action: m_sizeAction->menu()->actions()) { action->setCheckable(true); auto sp = action->property("sizePolicy").value(); if (sp == GeneralConfigDefine::PanelSizePolicy::Custom) { action->setEnabled(mainView()->config()->contains(QStringLiteral("customPanelSize"))); } action->setChecked(sp == m_sizePolicy); } m_sizeAction->setEnabled(!m_lockPanel); } void Panel::initPositionAction() { auto *positionAction = new QAction(QIcon::fromTheme("ukui-taskbar-place-symbolic"), tr("Panel Position"), this); positionAction->setMenu(new QMenu()); QAction *action = positionAction->menu()->addAction(tr("Top")); action->setProperty("position", UkuiQuick::Types::Top); action = positionAction->menu()->addAction(tr("Bottom")); action->setProperty("position", UkuiQuick::Types::Bottom); action = positionAction->menu()->addAction(tr("Left")); action->setProperty("position", UkuiQuick::Types::Left); action = positionAction->menu()->addAction(tr("Right")); action->setProperty("position", UkuiQuick::Types::Right); connect(positionAction->menu(), &QMenu::triggered, this, [this](QAction *action) { auto pos = action->property("position").value(); setPosition(pos); }); m_positionAction = positionAction; m_positionAction->setProperty("id", "panelLocation"); updatePositionAction(); } void Panel::updatePositionAction() { for (const auto &action: m_positionAction->menu()->actions()) { action->setCheckable(true); action->setChecked(action->property("position").value() == mainView()->position()); } m_positionAction->setEnabled(!m_lockPanel); } void Panel::initLockPanelAction() { m_lockPanelAction = new QAction(QIcon::fromTheme("ukui-taskbar-lock-symbolic"), tr("Lock Panel"), this); m_lockPanelAction->setProperty("id", "panelLock"); m_lockPanelAction->setCheckable(true); connect(m_lockPanelAction, &QAction::triggered, this, [this] { setLockPanel(m_lockPanelAction->isChecked()); }); updateLockPanelAction(); } void Panel::updateLockPanelAction() { if(m_lockPanelAction) { m_lockPanelAction->setChecked(m_lockPanel); } if(m_sizeAction) { m_sizeAction->setEnabled(!m_lockPanel); } if(m_positionAction) { m_positionAction->setEnabled(!m_lockPanel); } } void Panel::resetWorkArea(bool cut) { if (cut) { // 为窗管添加不可显示区域 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) KX11Extras::setExtendedStrut(winId(), m_unavailableArea.leftWidth, m_unavailableArea.leftStart, m_unavailableArea.leftEnd, m_unavailableArea.rightWidth, m_unavailableArea.rightStart, m_unavailableArea.rightEnd, m_unavailableArea.topWidth, m_unavailableArea.topStart, m_unavailableArea.topEnd, m_unavailableArea.bottomWidth, m_unavailableArea.bottomStart, m_unavailableArea.bottomEnd ); #else KWindowSystem::setExtendedStrut(winId(), m_unavailableArea.leftWidth, m_unavailableArea.leftStart, m_unavailableArea.leftEnd, m_unavailableArea.rightWidth, m_unavailableArea.rightStart, m_unavailableArea.rightEnd, m_unavailableArea.topWidth, m_unavailableArea.topStart, m_unavailableArea.topEnd, m_unavailableArea.bottomWidth, m_unavailableArea.bottomStart, m_unavailableArea.bottomEnd ); #endif m_windowProxy->setPanelAutoHide(false); } else { // 为窗管移除不可显示区域 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) KX11Extras::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); #else KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); #endif m_windowProxy->setPanelAutoHide(true); } } /** * 设置panel是否自动隐藏 * 如果自动隐藏,那么需要向窗管归还可用区域 * 将任务栏调整为屏幕边缘的一个小条 * 并且将内容隐藏 * * @param autoHide */ void Panel::setAutoHide(bool autoHide, bool updateConfig) { if (m_autoHide == autoHide) { return; } m_autoHide = autoHide; resetWorkArea(!m_autoHide); if (m_autoHideAction) { m_autoHideAction->setChecked(m_autoHide); } updateHideState(); setGSettings(QStringLiteral("hidepanel"), m_autoHide); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("panelAutoHide"), m_autoHide); } } bool Panel::event(QEvent *e) { switch (e->type()) { case QEvent::Leave: { m_containsMouse = false; updateHideState(); break; } case QEvent::Enter: { m_containsMouse = true; updateHideState(); break; } default: break; } return QQuickWindow::event(e); } void Panel::changeCursor(const QString &type) { if (type.isEmpty()) { QGuiApplication::restoreOverrideCursor(); return; } Qt::CursorShape shape = Qt::CustomCursor; if (type == "resizeVec") { shape = Qt::SizeVerCursor; } else if (type == "resizeHor") { shape = Qt::SizeHorCursor; } else if (type == "move") { shape = Qt::SizeAllCursor; } if (shape == Qt::CustomCursor) { QGuiApplication::restoreOverrideCursor(); return; } auto cursor = QGuiApplication::overrideCursor(); if (cursor && cursor->shape() == shape) { return; } QGuiApplication::setOverrideCursor({shape}); } bool Panel::enableCustomSize() const { return m_sizePolicy == GeneralConfigDefine::Custom; } void Panel::changePanelPos(UkuiQuick::Types::Pos pos) { setPosition(pos); } void Panel::startResizeCustomPanelSize(const Qt::Edges &edge) { startSystemResize(edge); m_isResizingPanel = true; } void Panel::endResizeCustomPanelSize() { int size; if (mainView()->orientation() == UkuiQuick::Types::Vertical) { size = width() - mainView()->margin()->right() - mainView()->margin()->left(); } else { size = height() - mainView()->margin()->bottom() - mainView()->margin()->top(); } if (!mainView()->config()->contains(QStringLiteral("customPanelSize")) || mainView()->config()->getValue(QStringLiteral("customPanelSize")).toInt() != size) { mainView()->config()->setValue(QStringLiteral("customPanelSize"), size); } if (m_panelSize != size) { m_panelSize = size; mainView()->config()->setValue(QStringLiteral("panelSize"), m_panelSize); setGSettings(QStringLiteral("panelsize"), mainView()->orientation() == UkuiQuick::Types::Horizontal ? m_windowRegion.height() : m_windowRegion.width()); DataCollector::setPanelSizeEvent(m_panelSize); } if (m_sizePolicy != GeneralConfigDefine::Custom) { setPanelPolicy(GeneralConfigDefine::Custom, true); } m_isResizingPanel = false; } bool Panel::disableMouseLeftButton() const { return m_disableMouseLeftButton; } bool Panel::disableMouseRightButton() const { return m_disableMouseRightButton; } bool Panel::disableMouseHover() const { return m_disableMouseHover; } bool Panel::disableContextMenu() const { return m_disableContextMenu; } void Panel::setLockPanel(bool locked, bool updateConfig) { if (locked == m_lockPanel && !m_startUp) { return; } m_lockPanel = locked; if (!m_startUp) { updateLockPanelAction(); emit lockPanelChanged(); } setGSettings(QStringLiteral("lockpanel"), m_lockPanel); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("lockPanel"), m_lockPanel); } } bool Panel::lockPanel() const { return m_lockPanel; } void Panel::updateHideState() { if (m_autoHide && !m_containsMouse && !mainView()->active()) { if (m_startUp) { setHidden(true); } else { activeHideTimer(); } } else { activeHideTimer(false); setHidden(false); } } void Panel::updateMask() { QRegion mask; if (m_isHidden) { const int maskSize = 4; switch (mainView()->position()) { case UkuiQuick::Types::Left: mask = QRegion(0, 0, maskSize, geometry().height()); break; case UkuiQuick::Types::Top: mask = QRegion(0, 0, geometry().width(), maskSize); break; case UkuiQuick::Types::Right: mask = QRegion(geometry().width() - maskSize, 0, maskSize, geometry().height()); break; case UkuiQuick::Types::Bottom: mask = QRegion(0, geometry().height() - maskSize, geometry().width(), maskSize); break; default: break; } m_windowProxy->setBlurRegion(false); } else { // TODO: region圆角 auto blurRegion = QRegion(QRect{QPoint{mainView()->margin()->left(), mainView()->margin()->top()}, mainView()->geometry().size()}); m_windowProxy->setBlurRegion(true, blurRegion); } setMask(mask); } /** * 进入隐藏状态,并在过程中执行过渡动画 * 隐藏状态是指任务栏内容不可见,并在屏幕边缘保留有一个小小的条状区域用于接受鼠标事件,动态激活界面 * 基本逻辑分为以下两个部分 if (hidden) { 执行动画(由) 关闭毛玻璃 隐藏内容 显示小条 } else { 开启毛玻璃 显示内容 执行显示动画 } * * @param hidden */ void Panel::setHidden(bool hidden) { auto panelContent = rootItem(); if (!panelContent || (m_isHidden == hidden && !m_startUp)) { return; } m_isHidden = hidden; hide(); panelContent->setVisible(!m_isHidden); updateMask(); show(); } void Panel::activeHideTimer(bool active) { if (!m_hideTimer) { return; } if (active) { m_hideTimer->start(); } else { m_hideTimer->stop(); } } void Panel::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-v11")) { return; } //管控中有值时,设置为管控值,否则设置为配置文件中的值 auto config = exit? QJsonObject(): UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "Panel" << m_id << "function control config:" << config; //是否一直隐藏任务栏 if (config.contains(QStringLiteral("panelHide"))) { setVisible(!config.value(QStringLiteral("panelHide")).toBool()); } else { setVisible(true); } //任务栏是否自动隐藏 if (config.contains(QStringLiteral("panelAutoHide"))) { setAutoHide(config.value(QStringLiteral("panelAutoHide")).toBool(), false); } else { setAutoHide(mainView()->config()->getValue(QStringLiteral("panelAutoHide")).toBool(), false); } //是否锁定任务栏 if (config.contains(QStringLiteral("panelLock"))) { setLockPanel(config.value(QStringLiteral("panelLock")).toBool(), false); updateLockPanelAction(); } else { setLockPanel(mainView()->config()->getValue(QStringLiteral("lockPanel")).toBool(), false); } //任务栏位置 0-底部;1-左侧;2-顶部;3-右侧 if (config.contains(QStringLiteral("panelLocation"))) { int pos = config.value(QStringLiteral("panelLocation")).toInt(); switch (pos) { default: case GeneralConfigDefine::Bottom: pos = UkuiQuick::Types::Bottom; break; case GeneralConfigDefine::Left: pos = UkuiQuick::Types::Left; break; case GeneralConfigDefine::Top: pos = UkuiQuick::Types::Top; break; case GeneralConfigDefine::Right: pos = UkuiQuick::Types::Right; break; } setPosition(static_cast(pos), false); } else { setPosition(static_cast(mainView()->config()->getValue(QStringLiteral("position")).toInt()), false); } //任务栏尺寸 0-小;1-中;2-大;3-自定义 if (config.contains(QStringLiteral("panelSizePolicy"))) { setPanelPolicy(static_cast(config.value(QStringLiteral("panelSizePolicy")).toInt()), false); } else { setPanelPolicy(static_cast(mainView()->config()->getValue(QStringLiteral("panelSizePolicy")).toInt()), false); } //任务栏主体的右键菜单中禁用的项 QStringList disableActions; for (QVariant&action: config.value(QStringLiteral("contextMenuDisableActions")).toArray().toVariantList()) { disableActions.append(action.toString()); } bool lock = m_lockPanelAction->isChecked(); for (auto &action: mainView()->actions()) { qDebug() << "Panel" << m_id << "action" << action->property("id").toString() << disableActions; if (disableActions.contains(action->property("id").toString())) { action->setEnabled(false); } else { if (action->property("id").toString() == QStringLiteral("panelSizePolicy")) { action->setEnabled(!lock && !config.contains(QStringLiteral("panelSizePolicy"))); } else if (action->property("id").toString() == QStringLiteral("panelLocation")) { action->setEnabled(!lock && !config.contains(QStringLiteral("panelLocation"))); } else if (action->property("id").toString() == QStringLiteral("panelAutoHide")) { action->setEnabled(!config.contains(QStringLiteral("panelAutoHide"))); } else if (action->property("id").toString() == QStringLiteral("panelLock")) { action->setEnabled(!config.contains(QStringLiteral("panelLock"))); } } } QStringList disableWidgets; for (QVariant &action : config.value(QStringLiteral("disableWidgets")).toArray().toVariantList()) { disableWidgets.append(action.toString()); } QStringList enableWidgets; for (QVariant&action: config.value(QStringLiteral("enableWidgets")).toArray().toVariantList()) { enableWidgets.append(action.toString()); } for (auto &action: m_widgetActions) { QString id = action->property("widget").toString(); if (id == QStringLiteral("org.ukui.panel.search") && (disableActions.contains(QStringLiteral("show-ukui-panel-search")) || disableWidgets.contains(id) || enableWidgets.contains(id))) { action->setEnabled(false); continue; } if (id == QStringLiteral("org.ukui.panel.taskView") && (disableActions.contains(QStringLiteral("show-ukui-panel-taskView")) || disableWidgets.contains(id) || enableWidgets.contains(id))) { action->setEnabled(false); continue; } action->setEnabled(true); } auto disabledWidgetsInConfig = mainView()->config()->getValue(QStringLiteral("disabledWidgets")).toStringList(); for (auto &widgetConfig: mainView()->config()->children("widgets")) { QString id = widgetConfig->getValue("id").toString(); if (disableWidgets.contains(id)) { disableWidget(id, true); } else if (enableWidgets.contains(id)) { disableWidget(id, false); } else { disableWidget(id, disabledWidgetsInConfig.contains(id)); } } //是否禁用左键点击(任务栏整体禁用) if (config.contains(QStringLiteral("disableMouseLeftButton"))) { bool disable = config.value(QStringLiteral("disableMouseLeftButton")).toBool(); if (disable != m_disableMouseLeftButton) { m_disableMouseLeftButton = disable; Q_EMIT disableMouseLeftButtonChanged(); } } else { m_disableMouseLeftButton = false; Q_EMIT disableMouseLeftButtonChanged(); } //是否禁用右键点击(任务栏整体禁用) if (config.contains(QStringLiteral("disableMouseRightButton"))) { bool disable = config.value(QStringLiteral("disableMouseRightButton")).toBool(); if (disable != m_disableMouseRightButton) { m_disableMouseRightButton = disable; Q_EMIT disableMouseRightButtonChanged(); } } else { m_disableMouseRightButton = false; Q_EMIT disableMouseRightButtonChanged(); } //是否禁用任务栏鼠标悬浮效果(任务栏整体) if (config.contains(QStringLiteral("disableMouseHover"))) { bool disable = config.value(QStringLiteral("disableMouseHover")).toBool(); if (disable != m_disableMouseHover) { m_disableMouseHover = disable; Q_EMIT disableMouseHoverChanged(); } } else { m_disableMouseHover = false; Q_EMIT disableMouseHoverChanged(); } //是否禁用任务栏主体的右键菜单 if (config.contains(QStringLiteral("disableContextMenu"))) { bool disable = config.value(QStringLiteral("disableContextMenu")).toBool(); if (disable != m_disableContextMenu) { m_disableContextMenu = disable; Q_EMIT disableContextMenuChanged(); } } else { m_disableContextMenu = false; Q_EMIT disableContextMenuChanged(); } } void Panel::primaryScreenChanged(Screen *screen) { if(m_screen == screen) { mainView()->addWidget(QStringLiteral("org.ukui.systemTray"), m_systemTrayInstance); } else { if(mainView()->config()->getValue("showSystemTrayOnAllPanels").toBool()) { mainView()->addWidget(QStringLiteral("org.ukui.systemTray"), m_systemTrayInstance); } else { mainView()->removeWidget(QStringLiteral("org.ukui.systemTray")); } } } void Panel::setShowSystemTrayStatus() { //读取托盘是否始终显示在任务栏上 auto value = mainView()->config()->getValue(QStringLiteral("showSystemTrayOnAllPanels")); if (!value.isValid()) { value = true; mainView()->config()->setValue(QStringLiteral("showSystemTrayOnAllPanels"), value); } //获取系统托盘的instanceid if(m_systemTrayInstance == -1) { auto widgetsList = mainView()->config()->children(QStringLiteral("widgets")); for (const auto widgetConfig : widgetsList) { if(widgetConfig->getValue(QStringLiteral("id")).toString() == QStringLiteral("org.ukui.systemTray")) { m_systemTrayInstance = widgetConfig->getValue(QStringLiteral("instanceId")).toInt(); break; } } } if(m_screen->internal() != qApp->primaryScreen() && !value.toBool()) { mainView()->removeWidget(QStringLiteral("org.ukui.systemTray")); } } void Panel::setGSettings(const QString& key, const QVariant &value) { if (!m_settings) { return; } if (m_settings->keys().contains(key)) { m_settings->set(key, value); } } } // UkuiPanel ukui-panel/panel/src/view/widget-model.cpp0000664000175000017500000000656315167645100017516 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #include "widget-model.h" #include #include #include #include #include #include #include namespace UkuiPanel { WidgetSortModel::WidgetSortModel(QObject *parent) : QSortFilterProxyModel(parent) { } bool WidgetSortModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { auto leftItem = source_left.data(UkuiQuick::WidgetItemModel::WidgetItemRole).value(); auto rightItem = source_right.data(UkuiQuick::WidgetItemModel::WidgetItemRole).value(); int lIdx = m_widgetOrder.indexOf(leftItem->widget()->instanceId()); int rIdx = m_widgetOrder.indexOf(rightItem->widget()->instanceId()); if (lIdx < 0) { return false; } return lIdx < rIdx; } bool WidgetSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if (m_layoutIndex == -1) { return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent); auto widget = sourceIndex.data(UkuiQuick::WidgetItemModel::WidgetItemRole).value()->widget(); return widget->config()->getValue("layoutIndex").toInt() == m_layoutIndex; } void WidgetSortModel::setSourceModel(QAbstractItemModel *sourceModel) { QSortFilterProxyModel::setSourceModel(sourceModel); QSortFilterProxyModel::sort(0); } QVariant WidgetSortModel::data(const QModelIndex& index, int role) const { if (role == WidgetLayoutIndex) { QModelIndex sourceIndex = mapToSource(index); auto widget = sourceIndex.data(UkuiQuick::WidgetItemModel::WidgetItemRole).value()->widget(); // 返回 layoutIndex 配置值 return widget->config()->getValue("layoutIndex").toInt(); } return sourceModel()->data(mapToSource(index), role); } QHash WidgetSortModel::roleNames() const { QHash roles; roles.insert(WidgetItemRole, "widgetItem"); roles.insert(WidgetLayoutIndex, "widgetLayoutIndex"); return roles; } QList WidgetSortModel::widgetOrder() const { return m_widgetOrder; } void WidgetSortModel::setWidgetOrder(const QList &order) { m_widgetOrder = order; invalidate(); Q_EMIT widgetOrderChanged(); } int WidgetSortModel::layoutIndex() const { return m_layoutIndex; } void WidgetSortModel::setLayoutIndex(int index) { m_layoutIndex = index; invalidate(); Q_EMIT layoutIndexChanged(); } } // UkuiPanel ukui-panel/panel/src/view/panel-next.h0000664000175000017500000001342315167645100016646 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #ifndef UKUI_PANEL_PANEL_NEXT_H #define UKUI_PANEL_PANEL_NEXT_H #include #include #include #include #include #include #include #include #include "common.h" #include "screens-manager.h" #include "blur-region-helper.h" #include "general-config-define.h" namespace UkuiPanel { Q_DECLARE_LOGGING_CATEGORY(PANEL_PANELNEXT) class AutoHideHelper : public QObject { Q_OBJECT public: explicit AutoHideHelper(Screen *screen, QObject* parent = nullptr); void setScreen(Screen *screen); bool needAutoHide(); private: void update(); Screen *m_screen = nullptr; bool m_needAutoHide = false; QString m_activeWindow; Q_SIGNALS: void autoHideStateChanged(bool); }; class PanelNext : public UkuiQuick::IslandView { Q_OBJECT Q_PROPERTY(bool lockPanel READ lockPanel NOTIFY lockPanelChanged) Q_PROPERTY(bool enableCustomSize READ enableCustomSize NOTIFY enableCustomSizeChanged) public: PanelNext(Screen* screen, const QString&id, QWindow* parent = nullptr); ~PanelNext(); void setPanelScreen(Screen* screen); bool lockPanel() const; bool enableCustomSize() const; void addIsland(const QString &id); void removeIsland(const QString &id); void dragRemove(const QString &id); void dragAdding(const QString &id, bool addWhenDrop); bool addCustomWidget(const QString &id, int instanceId = -1); bool removeCustomWidget(const QString &id, int instanceId = -1); Q_INVOKABLE void setPanelLength(int length); Q_INVOKABLE void endResizeCustomPanelSize(); Q_INVOKABLE void changeCursor(const QString &type); Q_INVOKABLE void startResizeCustomPanelSize(const Qt::Edges &edge); Q_SIGNALS: void lockPanelChanged(); void enableCustomSizeChanged(); void islandRemoved(const QString &id); void customWidgetAdded(const QString &id, int instanceId); void customWidgetRemoved(const QString &id, int instanceId); protected: bool event(QEvent* e) override; private Q_SLOTS: void onConfigChanged(const QString &key); void onScreenGeometryChanged(const QRect&geometry); void setPanelPolicy(GeneralConfigDefine::PanelSizePolicy sizePolicy, bool updateConfig = true); void setPosition(UkuiQuick::Types::Pos position, bool updateConfig = true); void setPanelSize(int size, bool updateConfig = true); void setLockPanel(bool locked, bool updateConfig = true); void setAutoHide(bool autoHide, bool updateConfig = true); void setHidden(bool hidden); void activeHideTimer(bool active = true); void onBlurRegionChanged(QRegion region); void changeForm(const QString &id, GeneralConfigDefine::IslandsForm form); void updateHideState(); private: void initGSettings(); void initMainContainer(); void initIslandsConfig(); void updateGeometry(); void initConfig(); /** * 根据panel的大小,计算窗口大小、窗口中panel的对应区域 * @param size */ void calculatePanelRectFromSize(int panelSize); /** * 更新panel窗口尺寸限制(最大、最小宽高) */ void updateLimitSize(); /** * 调用m_windowProxy接口,设置窗口属性(geometry) */ void setGeometry(); void updateMask(); void initPanelConfig(); void loadActions(); void initSizeAction(); void updateSizeAction(); void initPositionAction(); void updatePositionAction(); void initIslandFormAction(); void updateIslandFormAction(); void disableWidget(const QString &id, bool disable); void updateDisableWidget(); void setGSettings(const QString &key, const QVariant &value); private: QString m_id; QRect m_windowRegion; UkuiQuick::WindowProxy* m_windowProxy = nullptr; Screen* m_screen{nullptr}; int m_panelSize{56}; int m_panelPosition{0}; GeneralConfigDefine::PanelSizePolicy m_sizePolicy{GeneralConfigDefine::Small}; QAction* m_sizeAction{nullptr}; QAction* m_lockPanelAction{nullptr}; QAction* m_autoHideAction{nullptr}; QAction* m_dataIslandFormAction{nullptr}; QAction* m_settingsIslandFormAction{nullptr}; bool m_isHidden = false;//当前是否已经隐藏 bool m_autoHide = false;//是否自动隐藏(鼠标离开任务栏区域即隐藏) bool m_needHide = false;//当前是否有激活的最大化窗口需要任务栏隐藏 bool m_lockPanel = false; bool m_startUp = true; bool m_isResizingPanel = false;//当前任务栏是否在拖拽改变大小 QTimer* m_hideTimer = nullptr; QGSettings *m_settings = nullptr; QMap m_islands; BlurRegionHelper* m_blurHelper = nullptr; QList m_dataIslandActions; QList m_appIslandActions; QList m_settingsIslandActions; QList m_menus; //用于QMenu的统一销毁 AutoHideHelper *m_autoHideHelper = nullptr; bool m_containsMouse = false; QStringList m_disabledWidgets; }; } // UkuiPanel #endif //UKUI_PANEL_PANEL_NEXT_H ukui-panel/panel/src/view/blur-region-helper.cpp0000664000175000017500000000554015167645100020631 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #include "blur-region-helper.h" #include namespace UkuiPanel { BlurRegionHelper::BlurRegionHelper(QObject *parent) : QObject(parent) { } BlurRegionHelper::~BlurRegionHelper() { } //TODO: find a better way to set blur behind effect void BlurRegionHelper::addItem(QQuickItem *item, int radius ) { if(!item || (m_items.contains(item) && m_items.value(item) == radius)) { return; } m_items.insert(item, radius); connect(item, &QQuickItem::destroyed, this, [&, item]() { removeItem(item); }); requestUpdate(item); } void BlurRegionHelper::removeItem(QQuickItem *item) { if(!item) { return; } item->disconnect(this); m_items.remove(item); m_region.remove(item); m_pendingUpdateItems.removeAll(item); notifyRegionUpdated(); } bool BlurRegionHelper::event(QEvent* event) { if (event->type() == QEvent::UpdateRequest) { if(!m_pendingUpdateItems.isEmpty()) { for(auto item : m_pendingUpdateItems) { updateRegion(item); } m_pendingUpdateItems.clear(); notifyRegionUpdated(); } } return QObject::event(event); } void BlurRegionHelper::requestUpdate(QQuickItem* item) { if(item) { if(!m_pendingUpdateItems.contains(item)) { m_pendingUpdateItems.append(item); QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); } } else { for(auto item : m_items.keys()) { requestUpdate(item); } } } void BlurRegionHelper::updateRegion(QQuickItem* item) { if(item) { QPainterPath path; path.addRoundedRect(item->mapToScene(QPointF(0, 0)).x(), item->mapToScene(QPointF(0, 0)).y(), item->width(), item->height(), m_items.value(item), m_items.value(item)); m_region.insert(item, path.toFillPolygon().toPolygon()); } } void BlurRegionHelper::notifyRegionUpdated() { Q_EMIT regionUpdated(region()); } QRegion BlurRegionHelper::region() { QRegion region; for(const QRegion &r : m_region) { region = region.united(r); } return region; } } // UkuiPanelukui-panel/panel/src/view/widget-model.h0000664000175000017500000000415115167645100017152 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ #ifndef UKUI_PANEL_WIDGET_MODEL_H #define UKUI_PANEL_WIDGET_MODEL_H #include #include #include namespace UkuiQuick{ class WidgetItem; } namespace UkuiPanel { class WidgetSortModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(QList widgetOrder READ widgetOrder WRITE setWidgetOrder NOTIFY widgetOrderChanged) Q_PROPERTY(int layoutIndex READ layoutIndex WRITE setLayoutIndex NOTIFY layoutIndexChanged) public: enum WidgetsRoles { WidgetItemRole, WidgetLayoutIndex }; Q_ENUM(WidgetsRoles) explicit WidgetSortModel(QObject *parent = nullptr); QList widgetOrder() const; void setWidgetOrder(const QList &order); int layoutIndex() const; void setLayoutIndex(int index); void setSourceModel(QAbstractItemModel *sourceModel) override; QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; protected: bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; Q_SIGNALS: void widgetOrderChanged(); void layoutIndexChanged(); private: QList m_widgetOrder; int m_layoutIndex = -1; }; } // UkuiPanel #endif //UKUI_PANEL_WIDGET_MODEL_H ukui-panel/panel/src/view/blur-region-helper.h0000664000175000017500000000314515167645100020275 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #ifndef UKUI_PANEL_BLUR_REGION_HELPER_H #define UKUI_PANEL_BLUR_REGION_HELPER_H #include #include #include namespace UkuiPanel { class BlurRegionHelper : public QObject { Q_OBJECT public: BlurRegionHelper(QObject *parent = nullptr); ~BlurRegionHelper(); Q_INVOKABLE void addItem(QQuickItem *item, int radius = 0); Q_INVOKABLE void removeItem(QQuickItem *item); Q_INVOKABLE void requestUpdate(QQuickItem *item = nullptr); QRegion region(); Q_SIGNALS: void regionUpdated(QRegion region); protected: bool event(QEvent* event) override; private Q_SLOTS: void updateRegion(QQuickItem *item); void notifyRegionUpdated(); private: QMap m_items; QMap m_region; QList m_pendingUpdateItems; }; } // UkuiPanel #endif //UKUI_PANEL_BLUR_REGION_HELPER_H ukui-panel/panel/src/view/island-drag-helper.cpp0000664000175000017500000000434315167645100020571 0ustar fengfeng// // Created by iaom on 2024/9/24. // #include "island-drag-helper.h" #include #include #include #include static IslandDragHelper *g_islandDragHelper = nullptr; static std::once_flag flag_islandDragHelper; IslandDragHelper* IslandDragHelper::self() { std::call_once(flag_islandDragHelper, [ & ] { g_islandDragHelper = new IslandDragHelper(); }); return g_islandDragHelper; } void IslandDragHelper::IslandDragRemovingFromTopBar(bool removeWhenDrop) { setDragging(true); setIslandPendingAdd2Panel(removeWhenDrop); Q_EMIT dragRemovingFromTopBar(m_draggingIsland, removeWhenDrop); } void IslandDragHelper::IslandDragRemovingFromPanel(bool removeWhenDrop) { setDragging(true); setIslandPendingAdd2Panel(!removeWhenDrop); Q_EMIT dragRemovingFromPanel(m_draggingIsland, removeWhenDrop); } void IslandDragHelper::IslandDragRemoveFromTopBar(const QString& island) { if(island != m_draggingIsland) { return; } setDraggingIsland(""); setDragging(false); Q_EMIT dragRemoveFromTopBar(island); } void IslandDragHelper::IslandDragRemoveFromPanel(const QString& island) { if(island != m_draggingIsland) { return; } setDraggingIsland(""); setDragging(false); Q_EMIT dragRemoveFromPanel(island); } bool IslandDragHelper::islandPendingAdd2Panel() const { return m_islandPendingAdd2Panel; } void IslandDragHelper::setIslandPendingAdd2Panel(bool islandPendingAdd2Panel) { if(m_islandPendingAdd2Panel != islandPendingAdd2Panel) { m_islandPendingAdd2Panel = islandPendingAdd2Panel; Q_EMIT islandPendingAdd2PanelChanged(); } } bool IslandDragHelper::dragging() const { return m_dragging; } void IslandDragHelper::setDragging(bool dragging) { if(m_dragging != dragging) { m_dragging = dragging; Q_EMIT draggingChanged(); } } QString IslandDragHelper::draggingIsland() { return m_draggingIsland; } void IslandDragHelper::setDraggingIsland(const QString& draggingIsland) { if(m_draggingIsland != draggingIsland) { m_draggingIsland = draggingIsland; Q_EMIT draggingIslandChanged(); } } IslandDragHelper::IslandDragHelper(QObject* parent) : QObject(parent) { } ukui-panel/panel/src/view/panel-next.cpp0000664000175000017500000012576415167645100017215 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom */ #include #include #include #include #include #include "panel-next.h" #include "island-drag-helper.h" #include "widget-model.h" #include "shell.h" #include "panel-gsettings.h" #include #include #include #define DEFAULT_PANEL_SIZE 56 #define UKUI_PANEL_SETTINGS_ID "org.ukui.panel.settings" #define UKUI_PANEL_SETTINGS_PATH "/org/ukui/panel/settings/" namespace UkuiPanel { using WindowManager = UkuiQuick::WindowManager; Q_LOGGING_CATEGORY(PANEL_PANELNEXT, "org.ukui.panel.panelNext") void AutoHideHelper::setScreen(Screen* screen) { m_screen = screen; update(); } bool AutoHideHelper::needAutoHide() { return m_needAutoHide; } void AutoHideHelper::update() { auto wid = WindowManager::currentActiveWindow(); bool maximized = WindowManager::isMaximized(wid); bool needAutoHide = false; if(maximized && m_screen->internal()->geometry().contains(WindowManager::geometry(wid).center())) { needAutoHide = true; } else { needAutoHide = false; } if(m_needAutoHide != needAutoHide) { m_needAutoHide = needAutoHide; Q_EMIT autoHideStateChanged(m_needAutoHide); } } AutoHideHelper::AutoHideHelper(Screen *screen, QObject* parent): QObject(parent) { m_screen = screen; update(); connect(WindowManager::self(), &WindowManager::activeWindowChanged, this, &AutoHideHelper::update); connect(WindowManager::self(), &WindowManager::maximizedChanged, this, &AutoHideHelper::update); connect(WindowManager::self(), &WindowManager::geometryChanged, this, &AutoHideHelper::update); } PanelNext::PanelNext(Screen* screen, const QString&id, QWindow* parent): UkuiQuick::IslandView( QStringLiteral("panel"), QStringLiteral("ukui-panel")), m_id(id) { qRegisterMetaType>(); qmlRegisterType("org.ukui.panel.impl", 1, 0, "WidgetSortModel"); rootContext()->setContextProperty("panelNext", this); m_blurHelper = new BlurRegionHelper(this); connect(m_blurHelper, &BlurRegionHelper::regionUpdated, this, &PanelNext::onBlurRegionChanged); rootContext()->setContextProperty("blurRegionHelper", m_blurHelper); setColor(Qt::transparent); setFlags(flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus); m_windowProxy = new UkuiQuick::WindowProxy(this); m_windowProxy->setWindowType(UkuiQuick::WindowType::Dock); m_windowProxy->setPanelAutoHide(true); m_autoHideHelper = new AutoHideHelper(screen, this); m_needHide = m_autoHideHelper->needAutoHide(); //关闭自动隐藏是,任务栏根据当前是否有最大化窗口激活决定是否隐藏 connect(m_autoHideHelper, &AutoHideHelper::autoHideStateChanged, this, [this](bool hide) { m_needHide = hide; updateHideState(); }); initMainContainer(); setPanelScreen(screen); initConfig(); initIslandsConfig(); initPanelConfig(); loadActions(); updateDisableWidget(); loadMainViewItem(); // 用于执行隐藏的定时器 m_hideTimer = new QTimer(this); m_hideTimer->setSingleShot(true); m_hideTimer->setInterval(500); connect(m_hideTimer, &QTimer::timeout, this, [this] { setHidden(true); }); updateHideState(); // 初始化gsettings,将已经初始化完成的值更新到gsettings中 initGSettings(); //island从任务栏拖拽移除 connect(IslandDragHelper::self(), &IslandDragHelper::dragRemoveFromPanel, this, &PanelNext::dragRemove); //island从顶栏拖拽中 connect(IslandDragHelper::self(), &IslandDragHelper::dragRemovingFromTopBar, this, &PanelNext::dragAdding); m_startUp = false; connect(this, &QQuickView::heightChanged, this, [this]() { if (m_isResizingPanel && (mainView()->orientation() == UkuiQuick::Types::Horizontal)) { calculatePanelRectFromSize(height() - mainView()->margin()->bottom() - mainView()->margin()->top()); setGSettings(QStringLiteral("panelsize"), m_windowRegion.height()); } }); qCDebug(PANEL_PANELNEXT) << "panel next init finished with id:" << m_id; } PanelNext::~PanelNext() { qDeleteAll(m_menus); } void PanelNext::initMainContainer() { const QString defaultViewId = QStringLiteral("org.ukui.panelNext"); // 添加panel包所在的qrc路径 UkuiQuick::WidgetContainer::widgetLoader().addWidgetSearchPath(QStringLiteral(":/ukui-panel")); // TODO: 配置错误检查 if (!loadMainViewWithoutItem(defaultViewId)) { // 全部使用默认配置 auto metadata = UkuiQuick::WidgetMetadata(QStringLiteral(":/ukui-panel/org.ukui.panelNext")); auto cont = new UkuiQuick::WidgetContainer(metadata, this); cont->setConfig(UkuiQuick::ConfigLoader::getConfig(QStringLiteral("panel"))); setMainView(cont); } } void PanelNext::initIslandsConfig() { auto mainViewConfig = mainView()->config(); mainViewConfig->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); //三岛默认配置 if (mainViewConfig->numberOfChildren(QStringLiteral("widgets")) == 0) { QVariantList order; QVariantMap wData; //数据岛 wData.insert(QStringLiteral("id"), "org.ukui.dataIsland"); wData.insert(QStringLiteral("instanceId"), 0); wData.insert(QStringLiteral("type"), "data"); wData.insert(QStringLiteral("minimumWidth"), 64); wData.insert(QStringLiteral("maximumWidth"), 208); wData.insert(QStringLiteral("defaultHeight"), 56); mainViewConfig->addChild(QStringLiteral("widgets"), wData); order << 0; //应用岛 wData.clear(); wData.insert(QStringLiteral("id"), "org.ukui.appIsland"); wData.insert(QStringLiteral("instanceId"), 1); wData.insert(QStringLiteral("type"), "app"); wData.insert(QStringLiteral("minimumWidth"), 64); wData.insert(QStringLiteral("maximumWidth"), QWINDOWSIZE_MAX); wData.insert(QStringLiteral("defaultHeight"), 56); mainViewConfig->addChild(QStringLiteral("widgets"), wData); order << 1; //配置岛 wData.clear(); wData.insert(QStringLiteral("id"), "org.ukui.settingsIsland"); wData.insert(QStringLiteral("instanceId"), 2); wData.insert(QStringLiteral("type"), "settings"); wData.insert(QStringLiteral("minimumWidth"), 192); wData.insert(QStringLiteral("maximumWidth"), QWINDOWSIZE_MAX); wData.insert(QStringLiteral("defaultHeight"), 56); mainViewConfig->addChild(QStringLiteral("widgets"), wData); order << 2; mainViewConfig->setValue(QStringLiteral("widgetsOrder"), order); UkuiQuick::ConfigList islandsConfig = mainView()->config()->children(QStringLiteral("widgets")); for (const auto config: islandsConfig) { config->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); //每个岛中的widgets默认配置 if (config->numberOfChildren(QStringLiteral("widgets")) == 0) { // 默认加载widgets QStringList defaultWidgets; QString type = config->getValue(QStringLiteral("type")).toString(); if (type == "data") { defaultWidgets << QStringLiteral("org.ukui.menu.starter"); defaultWidgets << QStringLiteral("org.ukui.panel.idm"); defaultWidgets << QStringLiteral("org.ukui.panel.taskView"); } else if (type == "app") { defaultWidgets << QStringLiteral("org.ukui.panel.taskManager"); defaultWidgets << QStringLiteral("org.ukui.panel.search"); } else { defaultWidgets << QStringLiteral("org.ukui.systemTray"); defaultWidgets << QStringLiteral("org.ukui.panel.calendar"); } qCDebug(PANEL_PANELNEXT) << "defaultWidgets" << type << defaultWidgets; QVariantList order; for (const auto&widget: defaultWidgets) { int instanceId = order.count(); order << instanceId; QVariantMap wData; wData.insert(QStringLiteral("id"), widget); wData.insert(QStringLiteral("instanceId"), instanceId); config->addChild(QStringLiteral("widgets"), wData); } config->setValue(QStringLiteral("widgetsOrder"), order); config->setValue(QStringLiteral("disabledWidgets"), QStringList()); } mainView()->addWidget(config->getValue(QStringLiteral("id")).toString(), config->getValue(QStringLiteral("instanceId")).toInt()); } } for (UkuiQuick::Widget* w: mainView()->widgets()) { m_islands.insert(w->id(), dynamic_cast(w)); } } void PanelNext::setPanelScreen(Screen* screen) { if (!screen || screen == m_screen) { return; } if (m_screen) { m_screen->disconnect(this); } m_screen = screen; setScreen(screen->internal()); mainView()->setScreen(screen->internal()); updateGeometry(); connect(screen, &Screen::geometryChanged, this, &PanelNext::onScreenGeometryChanged); m_autoHideHelper->setScreen(screen); } bool PanelNext::lockPanel() const { return m_lockPanel; } bool PanelNext::enableCustomSize() const { return m_sizePolicy == GeneralConfigDefine::Custom; } void PanelNext::addIsland(const QString&id) { changeForm(id, GeneralConfigDefine::Panel); updateIslandFormAction(); } void PanelNext::removeIsland(const QString&id) { if (m_islands.contains(id)) { mainView()->addDisableInstance(m_islands.value(id)->instanceId()); m_islands.remove(id); } } void PanelNext::dragRemove(const QString& id) { QTimer::singleShot(0, this, [this, id]() { changeForm(id, GeneralConfigDefine::TopBar); }); } void PanelNext::dragAdding(const QString& id, bool addWhenDrop) { if(addWhenDrop) { addIsland(id); } else { removeIsland(id); } } bool PanelNext::addCustomWidget(const QString& id, int instanceId) { UkuiQuick::WidgetContainer *appIsland = m_islands.value(QStringLiteral("org.ukui.appIsland")); if(appIsland) { QStringList defaultWidgets{QStringLiteral("org.ukui.panel.taskManager"), QStringLiteral("org.ukui.panel.search")}; if(defaultWidgets.contains(id)) { return false; } if(instanceId >= 0) { //判断是否已经存在 for(auto widget : appIsland->widgets()) { if(widget->instanceId() == instanceId) { return false; } } appIsland->addWidget(id, instanceId); } else { //找到可用的instanceId QList usedInstanceId; UkuiQuick::ConfigList list = appIsland->config()->children(QStringLiteral("widgets")); for(auto config : list) { usedInstanceId.append(config->id().toInt()); } for(instanceId = 0;usedInstanceId.contains(instanceId);instanceId++) {} QVariantList widgetOrder = appIsland->config()->getValue(QStringLiteral("widgetsOrder")).value(); widgetOrder.append(instanceId); appIsland->config()->setValue(QStringLiteral("widgetsOrder"), widgetOrder); appIsland->addWidget(id, instanceId); Q_EMIT customWidgetAdded(id, instanceId); } return true; } return false; } bool PanelNext::removeCustomWidget(const QString& id, int instanceId) { UkuiQuick::WidgetContainer *appIsland = m_islands.value(QStringLiteral("org.ukui.appIsland")); if(appIsland) { if(instanceId >= 0) { appIsland->removeWidget(id); return true; } QStringList defaultWidgets{QStringLiteral("org.ukui.panel.taskManager"), QStringLiteral("org.ukui.panel.search")}; if(defaultWidgets.contains(id)) { return false; } appIsland->removeWidget(id); //移除配置文件 UkuiQuick::ConfigList list = appIsland->config()->children(QStringLiteral("widgets")); QVariantList widgetOrder = appIsland->config()->getValue(QStringLiteral("widgetsOrder")).value(); for(auto config : list) { if(config->getValue(QStringLiteral("id")).toString() == id) { appIsland->config()->removeChild(QStringLiteral("widgets"), config->id()); widgetOrder.removeOne(config->id()); Q_EMIT customWidgetRemoved(id, config->id().toInt()); } } appIsland->config()->setValue(QStringLiteral("widgetsOrder"), widgetOrder); return true; } return false; } void PanelNext::setPanelLength(int length) { PanelGSettings::instance()->setPanelLength(m_screen->internal()->name(), length); } void PanelNext::changeCursor(const QString& type) { if (type.isEmpty()) { QGuiApplication::restoreOverrideCursor(); return; } Qt::CursorShape shape = Qt::CustomCursor; if (type == "SizeVerCursor") { shape = Qt::SizeVerCursor; } else if (type == "SizeHorCursor") { shape = Qt::SizeHorCursor; } if (shape == Qt::CustomCursor) { QGuiApplication::restoreOverrideCursor(); return; } auto cursor = QGuiApplication::overrideCursor(); if (cursor && cursor->shape() == shape) { return; } QGuiApplication::setOverrideCursor({shape}); } void PanelNext::startResizeCustomPanelSize(const Qt::Edges& edge) { if (m_sizePolicy == GeneralConfigDefine::Custom) { bool success = startSystemResize(edge); m_isResizingPanel = success; } } void PanelNext::endResizeCustomPanelSize() { if (m_sizePolicy == GeneralConfigDefine::Custom) { int size; if (mainView()->orientation() == UkuiQuick::Types::Vertical) { size = width() - mainView()->margin()->right() - mainView()->margin()->left(); } else { size = height() - mainView()->margin()->bottom() - mainView()->margin()->top(); } if (m_panelSize != size) { m_panelSize = size; mainView()->config()->setValue(QStringLiteral("customPanelSize"), m_panelSize); mainView()->config()->setValue(QStringLiteral("panelSize"), m_panelSize); setGSettings(QStringLiteral("panelsize"), m_windowRegion.height()); } m_isResizingPanel = false; } } void PanelNext::onScreenGeometryChanged(const QRect&geometry) { Q_UNUSED(geometry) updateLimitSize(); updateGeometry(); } void PanelNext::updateGeometry() { calculatePanelRectFromSize(m_panelSize); setGeometry(); updateMask(); } void PanelNext::initConfig() { QMap defaultList; defaultList.insert(QStringLiteral("leftMargin"), 8); defaultList.insert(QStringLiteral("topMargin"), 0); defaultList.insert(QStringLiteral("rightMargin"), 8); defaultList.insert(QStringLiteral("bottomMargin"), 8); defaultList.insert(QStringLiteral("leftPadding"), 2); defaultList.insert(QStringLiteral("topPadding"), 2); defaultList.insert(QStringLiteral("rightPadding"), 2); defaultList.insert(QStringLiteral("bottomPadding"), 2); defaultList.insert(QStringLiteral("panelMinimumSize"), 48); defaultList.insert(QStringLiteral("panelMaximumSize"), 80); defaultList.insert(QStringLiteral("panelSize"), DEFAULT_PANEL_SIZE); defaultList.insert(QStringLiteral("panelDefaultSize"), DEFAULT_PANEL_SIZE); defaultList.insert(QStringLiteral("customPanelSize"), DEFAULT_PANEL_SIZE); auto config = mainView()->config(); for (const auto&key: defaultList.keys()) { if (config->getValue(key).isNull()) { config->setValue(key, defaultList.value(key)); } } int policy = config->getValue(QStringLiteral("panelSizePolicy")).isNull() ? GeneralConfigDefine::Medium : config->getValue(QStringLiteral("panelSizePolicy")).toInt(); // panelSize if (policy == GeneralConfigDefine::Custom) { m_panelSize = config->getValue(QStringLiteral("customPanelSize")).isNull() ? DEFAULT_PANEL_SIZE : config->getValue(QStringLiteral("customPanelSize")).toInt(); } else { m_panelSize = config->getValue(QStringLiteral("panelSize")).isNull() ? DEFAULT_PANEL_SIZE : config->getValue(QStringLiteral("panelSize")).toInt(); } setPanelPolicy(static_cast(policy), false); // container auto cont = mainView(); cont->setHost(UkuiQuick::WidgetMetadata::Host::Panel); auto margin = cont->margin(); auto padding = cont->padding(); margin->setLeft(config->getValue(QStringLiteral("leftMargin")).toInt()); margin->setTop(config->getValue(QStringLiteral("topMargin")).toInt()); margin->setRight(config->getValue(QStringLiteral("rightMargin")).toInt()); margin->setBottom(config->getValue(QStringLiteral("bottomMargin")).toInt()); padding->setLeft(config->getValue(QStringLiteral("leftPadding")).toInt()); padding->setTop(config->getValue(QStringLiteral("topPadding")).toInt()); padding->setRight(config->getValue(QStringLiteral("rightPadding")).toInt()); padding->setBottom(config->getValue(QStringLiteral("bottomPadding")).toInt()); // position int position = config->getValue(QStringLiteral("position")).isNull() ? UkuiQuick::Types::Pos::Bottom : config->getValue(QStringLiteral("position")).toInt(); setPosition(static_cast(position), false); connect(cont, &UkuiQuick::WidgetContainer::activeChanged, this, &PanelNext::updateHideState); } void PanelNext::setPanelPolicy(GeneralConfigDefine::PanelSizePolicy sizePolicy, bool updateConfig) { if (sizePolicy != m_sizePolicy) { switch (sizePolicy) { default: case GeneralConfigDefine::Small: m_sizePolicy = GeneralConfigDefine::Small; setPanelSize(48); break; case GeneralConfigDefine::Medium: m_sizePolicy = GeneralConfigDefine::Medium; setPanelSize(56); break; case GeneralConfigDefine::Large: m_sizePolicy = GeneralConfigDefine::Large; setPanelSize(64); break; case GeneralConfigDefine::Custom: m_sizePolicy = GeneralConfigDefine::Custom; setPanelSize(mainView()->config()->getValue(QStringLiteral("customPanelSize")).toInt()); break; } if (updateConfig) { mainView()->config()->setValue(QStringLiteral("panelSizePolicy"), m_sizePolicy); } emit enableCustomSizeChanged(); } } void PanelNext::setPosition(UkuiQuick::Types::Pos position, bool updateConfig) { auto container = PanelNext::mainView(); if (position != container->position()) { switch (position) { case UkuiQuick::Types::Left: m_panelPosition = 2; break; case UkuiQuick::Types::Top: m_panelPosition = 1; break; case UkuiQuick::Types::Right: m_panelPosition = 3; break; default: case UkuiQuick::Types::Bottom: m_panelPosition = 0; position = UkuiQuick::Types::Pos::Bottom; break; } container->setPosition(position); if (position == UkuiQuick::Types::Left || position == UkuiQuick::Types::Right) { container->setOrientation(UkuiQuick::Types::Vertical); } else { container->setOrientation(UkuiQuick::Types::Horizontal); } updateLimitSize(); updateGeometry(); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("position"), position); setGSettings(QStringLiteral("panelposition"), m_panelPosition); } } } void PanelNext::calculatePanelRectFromSize(int panelSize) { auto container = PanelNext::mainView(); const auto margin = container->margin(); // panelRect 为实际占用的区域,包括外边距(margin) QRect screenGeometry = container->screen()->geometry(), panelRect; switch (container->position()) { default: case UkuiQuick::Types::Pos::Bottom: panelSize += (margin->top() + margin->bottom()); panelRect = screenGeometry.adjusted(0, screenGeometry.height() - panelSize, 0, 0); break; case UkuiQuick::Types::Pos::Left: panelSize += (margin->left() + margin->right()); panelRect = screenGeometry.adjusted(0, 0, panelSize - screenGeometry.width(), 0); break; case UkuiQuick::Types::Pos::Top: panelSize += (margin->top() + margin->bottom()); panelRect = screenGeometry.adjusted(0, 0, 0, panelSize - screenGeometry.height()); break; case UkuiQuick::Types::Pos::Right: panelSize += (margin->left() + margin->right()); panelRect = screenGeometry.adjusted(screenGeometry.width() - panelSize, 0, 0, 0); break; } m_windowRegion = panelRect; QRect rect = panelRect.adjusted(margin->left(), margin->top(), -margin->right(), -margin->bottom()); container->setGeometry(rect); } void PanelNext::setGeometry() { switch (PanelNext::mainView()->position()) { default: case UkuiQuick::Types::Pos::Bottom: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::BottomEdge); break; case UkuiQuick::Types::Pos::Left: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::LeftEdge); break; case UkuiQuick::Types::Pos::Top: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::TopEdge); break; case UkuiQuick::Types::Pos::Right: m_windowProxy->slideWindow(UkuiQuick::WindowProxy::RightEdge); break; } m_windowProxy->setGeometry(m_windowRegion); } void PanelNext::updateMask() { QRegion maskForHover, mask; const int maskSize = 4; switch (mainView()->position()) { case UkuiQuick::Types::Left: maskForHover = QRegion(0, 0, maskSize, geometry().height()); break; case UkuiQuick::Types::Top: maskForHover = QRegion(0, 0, geometry().width(), maskSize); break; case UkuiQuick::Types::Right: maskForHover = QRegion(geometry().width() - maskSize, 0, maskSize, geometry().height()); break; case UkuiQuick::Types::Bottom: maskForHover = QRegion(0, geometry().height() - maskSize, geometry().width(), maskSize); break; default: break; } if (m_isHidden) { m_windowProxy->setBlurRegion(false); mask = maskForHover; } else { auto blurRegion = m_blurHelper->region(); m_windowProxy->setBlurRegion(true, blurRegion); mask = blurRegion.united(maskForHover); } setMask(mask); } void PanelNext::setPanelSize(int size, bool updateConfig) { if (size == m_panelSize) { return; } int minSize = mainView()->config()->getValue(QStringLiteral("panelMinimumSize")).toInt(); int maxSize = mainView()->config()->getValue(QStringLiteral("panelMaximumSize")).toInt(); size = std::max(std::min(size, maxSize), minSize); m_panelSize = size; updateGeometry(); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("panelSize"), m_panelSize); setGSettings(QStringLiteral("panelsize"), m_windowRegion.height()); } } void PanelNext::initPanelConfig() { auto config = mainView()->config(); QVariant value = config->getValue(QStringLiteral("lockPanel")); if (!value.isValid()) { value = false; config->setValue(QStringLiteral("lockPanel"), value); } setLockPanel(value.toBool(), false); value = config->getValue(QStringLiteral("panelAutoHide")); if (!value.isValid()) { value = false; config->setValue(QStringLiteral("panelAutoHide"), value); } m_autoHide = value.toBool(); connect(config, &UkuiQuick::Config::configChanged, this, &PanelNext::onConfigChanged); } void PanelNext::onConfigChanged(const QString&key) { auto configValue = mainView()->config()->getValue(key); if (key == QStringLiteral("position")) { setPosition(UkuiQuick::Types::Pos(configValue.toInt()), false); } else if (key == QStringLiteral("panelSize")) { auto panelSize = configValue.value(); setPanelSize(panelSize, false); } else if (key == QStringLiteral("panelSizePolicy")) { auto policy = configValue.value(); setPanelPolicy(policy, false); } else if (key == QStringLiteral("panelAutoHide")) { setAutoHide(configValue.toBool(), false); } else if (key == QStringLiteral("lockPanel")) { setLockPanel(configValue.toBool(), false); } else if (key == QStringLiteral("disabledWidgets")) { QStringList disabledWidgets = mainView()->config()->getValue(key).toStringList(); if (disabledWidgets == m_disabledWidgets) { return; } QStringList tmp; tmp.append(disabledWidgets); tmp.append(m_disabledWidgets); tmp.removeDuplicates(); for (const auto&item : tmp) { disableWidget(item, disabledWidgets.contains(item)); } } } void PanelNext::loadActions() { auto settings = new QAction(tr("Panel Settings"), this); connect(settings, &QAction::triggered, this, [] { UkuiQuick::AppLauncher::instance()->launchAppWithArguments( QStringLiteral("/usr/share/applications/ukui-control-center.desktop"), {"-m", "Panel"}); }); m_dataIslandActions << settings; m_appIslandActions << settings; m_settingsIslandActions << settings; auto showDesktop = new QAction(tr("Show Desktop"), this); connect(showDesktop, &QAction::triggered, this, [] { UkuiQuick::WindowManager::setShowingDesktop(!UkuiQuick::WindowManager::showingDesktop()); }); m_dataIslandActions << showDesktop; m_appIslandActions << showDesktop; m_settingsIslandActions << showDesktop; auto systemMonitor = new QAction(tr("System Monitor"), this); connect(systemMonitor, &QAction::triggered, this, [] { UkuiQuick::AppLauncher::instance()->launchApp( QStringLiteral("/usr/share/applications/ukui-system-monitor.desktop")); }); m_dataIslandActions << systemMonitor; m_appIslandActions << systemMonitor; m_settingsIslandActions << systemMonitor; // 分割线 auto* separator1 = new QAction(this); separator1->setSeparator(true); m_dataIslandActions << separator1; m_appIslandActions << separator1; m_settingsIslandActions << separator1; // actions initSizeAction(); // initPositionAction(); // 调整大小 m_dataIslandActions << m_sizeAction; m_appIslandActions << m_sizeAction; m_settingsIslandActions << m_sizeAction; initIslandFormAction(); m_dataIslandActions << m_dataIslandFormAction; m_settingsIslandActions << m_settingsIslandFormAction; // 自动隐藏 m_autoHideAction = new QAction(tr("Auto Hide"), this); m_autoHideAction->setCheckable(true); m_autoHideAction->setChecked(m_autoHide); connect(m_autoHideAction, &QAction::triggered, this, [this] { setAutoHide(m_autoHideAction->isChecked()); }); m_dataIslandActions << m_autoHideAction; m_appIslandActions << m_autoHideAction; m_settingsIslandActions << m_autoHideAction; m_lockPanelAction = new QAction(tr("Lock Panel"), this); m_lockPanelAction->setCheckable(true); m_lockPanelAction->setChecked(m_lockPanel); connect(m_lockPanelAction, &QAction::triggered, this, [this] { setLockPanel(m_lockPanelAction->isChecked()); }); m_dataIslandActions << m_lockPanelAction; m_appIslandActions << m_lockPanelAction; m_settingsIslandActions << m_lockPanelAction; auto switchPanel = new QAction(tr("Switch to Classical Panel"), this); connect(switchPanel, &QAction::triggered, this, [] { QTimer::singleShot(1, []() { Shell::self()->switchTo(Shell::PanelType::Version4); }); }); m_dataIslandActions << switchPanel; m_appIslandActions << switchPanel; m_settingsIslandActions << switchPanel; for (auto island: m_islands) { if (island->id() == QStringLiteral("org.ukui.dataIsland")) { island->setActions(m_dataIslandActions); } else if (island->id() == QStringLiteral("org.ukui.appIsland")) { island->setActions(m_appIslandActions); } else if (island->id() == QStringLiteral("org.ukui.settingsIsland")) { island->setActions(m_settingsIslandActions); } } } void PanelNext::initSizeAction() { auto* sizeAction = new QAction(tr("Panel Size"), this); sizeAction->setMenu(new QMenu()); m_menus.append(sizeAction->menu()); auto group = new QActionGroup(sizeAction); QAction* action = sizeAction->menu()->addAction(tr("Large")); action->setProperty("sizePolicy", GeneralConfigDefine::Large); group->addAction(action); action = sizeAction->menu()->addAction(tr("Medium")); action->setProperty("sizePolicy", GeneralConfigDefine::Medium); group->addAction(action); action = sizeAction->menu()->addAction(tr("Small")); action->setProperty("sizePolicy", GeneralConfigDefine::Small); group->addAction(action); action = sizeAction->menu()->addAction(tr("Custom")); action->setProperty("sizePolicy", GeneralConfigDefine::Custom); group->addAction(action); connect(group, &QActionGroup::triggered, this, [this](QAction* action) { auto sizePolicy = action->property("sizePolicy").value(); setPanelPolicy(sizePolicy); }); m_sizeAction = sizeAction; updateSizeAction(); } void PanelNext::updateSizeAction() { for (const auto&action: m_sizeAction->menu()->actions()) { action->setCheckable(true); auto sp = action->property("sizePolicy").value(); action->setChecked(sp == m_sizePolicy); } } void PanelNext::setLockPanel(bool locked, bool updateConfig) { if (locked == m_lockPanel && !m_startUp) { return; } m_lockPanel = locked; if (!m_startUp) { updatePositionAction(); emit lockPanelChanged(); } setGSettings(QStringLiteral("lockpanel"), m_lockPanel); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("lockPanel"), m_lockPanel); } } void PanelNext::initPositionAction() { m_lockPanelAction = new QAction(tr("Lock Panel"), this); m_lockPanelAction->setCheckable(true); m_lockPanelAction->setChecked(m_lockPanel); connect(m_lockPanelAction, &QAction::triggered, this, [this] { setLockPanel(m_lockPanelAction->isChecked()); }); updatePositionAction(); } void PanelNext::updatePositionAction() { if(m_lockPanelAction) { m_lockPanelAction->setChecked(m_lockPanel); } if(m_sizeAction) { m_sizeAction->setEnabled(!m_lockPanel); } } void PanelNext::initIslandFormAction() { //数据岛特有aciton m_dataIslandFormAction = new QAction(tr("Data Island Form"), this); m_dataIslandFormAction->setMenu(new QMenu()); m_menus.append(m_dataIslandFormAction->menu()); auto group0 = new QActionGroup(m_dataIslandFormAction); QAction* action = m_dataIslandFormAction->menu()->addAction(tr("Islands")); action->setCheckable(true); group0->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::Panel); action = m_dataIslandFormAction->menu()->addAction(tr("Top Bar")); action->setCheckable(true); group0->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::TopBar); connect(group0, &QActionGroup::triggered, this, [this](QAction* action) { auto form = action->property("form").value(); changeForm(QStringLiteral("org.ukui.dataIsland"), form); }); //配置岛特有action m_settingsIslandFormAction = new QAction(tr("Settings Island Form"), this); m_settingsIslandFormAction->setMenu(new QMenu()); m_menus.append(m_settingsIslandFormAction->menu()); auto group1 = new QActionGroup(m_dataIslandFormAction); action = m_settingsIslandFormAction->menu()->addAction(tr("Islands")); action->setCheckable(true); group1->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::Panel); action = m_settingsIslandFormAction->menu()->addAction(tr("Top Bar")); action->setCheckable(true); group1->addAction(action); action->setProperty("form", GeneralConfigDefine::IslandsForm::TopBar); connect(group1, &QActionGroup::triggered, this, [this](QAction* action) { auto form = action->property("form").value(); changeForm(QStringLiteral("org.ukui.settingsIsland"), form); }); updateIslandFormAction(); } void PanelNext::updateIslandFormAction() { bool containDataIsland = false; bool containSettingsIsland = false; for (auto island: m_islands) { if (island->id() == QStringLiteral("org.ukui.dataIsland")) { containDataIsland = true; } else if (island->id() == QStringLiteral("org.ukui.settingsIsland")) { containSettingsIsland = true; } } for (auto action: m_dataIslandFormAction->menu()->actions()) { auto form = action->property("form").value(); action->setChecked(form == GeneralConfigDefine::IslandsForm::Panel && containDataIsland); } for (auto action: m_settingsIslandFormAction->menu()->actions()) { auto form = action->property("form").value(); action->setChecked(form == GeneralConfigDefine::IslandsForm::Panel && containSettingsIsland); } } void PanelNext::setAutoHide(bool autoHide, bool updateConfig) { if (m_autoHide == autoHide) { return; } m_autoHide = autoHide; if (m_autoHideAction) { m_autoHideAction->setChecked(m_autoHide); } updateHideState(); setGSettings(QStringLiteral("hidepanel"), m_autoHide); if (updateConfig) { mainView()->config()->setValue(QStringLiteral("panelAutoHide"), m_autoHide); } } void PanelNext::setHidden(bool hidden) { auto panelContent = rootItem(); if (!panelContent || (m_isHidden == hidden && !m_startUp)) { return; } m_isHidden = hidden; hide(); panelContent->setVisible(!m_isHidden); updateMask(); show(); } void PanelNext::activeHideTimer(bool active) { if (!m_hideTimer) { return; } if (active) { if(m_hideTimer->isActive()) { return; } m_hideTimer->start(); } else { m_hideTimer->stop(); } } bool PanelNext::event(QEvent* e) { switch (e->type()) { case QEvent::Leave: { m_containsMouse = false; updateHideState(); break; } case QEvent::Enter: { m_containsMouse = true; updateHideState(); break; } default: break; } return UkuiQuick::IslandView::event(e); } void PanelNext::onBlurRegionChanged(QRegion region) { if (!m_isHidden) { updateMask(); } } void PanelNext::changeForm(const QString&id, GeneralConfigDefine::IslandsForm form) { if (form == GeneralConfigDefine::IslandsForm::TopBar) { if (m_islands.contains(id)) { mainView()->addDisableInstance(m_islands.value(id)->config()->id().toInt()); m_islands.remove(id); Q_EMIT islandRemoved(id); } } else { if (!m_islands.contains(id)) { for (auto config: mainView()->config()->children(QStringLiteral("widgets"))) { if (config->getValue(QStringLiteral("id")).toString() == id) { mainView()->removeDisableInstance(config->id().toInt()); config->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); if(config->children(QStringLiteral("widgets")).size() != 0) { QList disableInstances; for(auto disabledWidget : mainView()->config()->getValue("disabledWidgets").toStringList()) { for (const auto &widget: config->children(QStringLiteral("widgets"))) { if (widget->getValue(QStringLiteral("id")).toString() == disabledWidget) { disableInstances.append(widget->getValue(QStringLiteral("instanceId")).toInt()); } } } QJsonArray jsonArray; for (int value : disableInstances) { jsonArray.append(value); } config->setValue(QStringLiteral("disabledInstances"), jsonArray); } mainView()->addWidget(id, config->id().toInt()); for (UkuiQuick::Widget* w: mainView()->widgets()) { if (w->id() == id) { if (id == QStringLiteral("org.ukui.dataIsland")) { w->setActions(m_dataIslandActions); } else if (id == QStringLiteral("org.ukui.settingsIsland")) { w->setActions(m_settingsIslandActions); } m_islands.insert(w->id(), dynamic_cast(w)); break; } } break; } } } } } void PanelNext::updateHideState() { if ((m_autoHide || m_needHide) && !m_containsMouse && !mainView()->active()) { if (m_startUp) { setHidden(true); } else { activeHideTimer(); } } else { activeHideTimer(false); setHidden(false); } } void PanelNext::disableWidget(const QString &id, bool disable) { if (disable) { // 禁用 if (m_disabledWidgets.contains(id)) { return; } m_disabledWidgets.append(id); // 卸载全部widget for(auto island : m_islands) { QVector widgets = island->widgets(); QList instances; for (const auto &item: widgets) { if (item->id() == id) { instances.append(item->instanceId()); } } instances.append(island->disableInstances()); island->setDisableInstances(instances); } } else { // 启用 if (m_disabledWidgets.removeAll(id) == 0) { return; } // 重新激活全部widget for(auto island : m_islands) { UkuiQuick::ConfigList children = island->config()->children(QStringLiteral("widgets")); for (const auto &child : children) { const QString widgetId = child->getValue(QStringLiteral("id")).toString(); if (widgetId == id) { island->removeDisableInstance(child->id().toInt()); island->addWidget(widgetId, child->id().toInt()); } } } } } void PanelNext::updateDisableWidget() { //初始化disableWidgets auto mainViewConfig = mainView()->config(); if(!mainViewConfig->getValue(QStringLiteral("disabledWidgets")).isValid()) { mainViewConfig->setValue(QStringLiteral("disabledWidgets"), QStringList()); } m_disabledWidgets = mainViewConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); UkuiQuick::ConfigList islandsConfig = mainViewConfig->children(QStringLiteral("widgets")); for(auto child : islandsConfig) { child->addGroupInfo(QStringLiteral("widgets"), QStringLiteral("instanceId")); if(child->children(QStringLiteral("widgets")).size() == 0) { continue; } QList disableInstances; for(auto disabledWidget : m_disabledWidgets) { for (const auto &widget: child->children(QStringLiteral("widgets"))) { if (widget->getValue(QStringLiteral("id")).toString() == disabledWidget) { disableInstances.append(widget->getValue(QStringLiteral("instanceId")).toInt()); } } } QJsonArray jsonArray; for (int value : disableInstances) { jsonArray.append(value); } child->setValue(QStringLiteral("disabledInstances"), jsonArray); } } void PanelNext::updateLimitSize() { auto container = mainView(); const auto margin = container->margin(); int minSize = mainView()->config()->getValue(QStringLiteral("panelMinimumSize")).toInt(); int maxSize = mainView()->config()->getValue(QStringLiteral("panelMaximumSize")).toInt(); setMaximumHeight(maxSize + (margin->top() + margin->bottom())); setMinimumHeight(minSize + (margin->top() + margin->bottom())); } void PanelNext::initGSettings() { if (QGSettings::isSchemaInstalled(UKUI_PANEL_SETTINGS_ID)) { m_settings = new QGSettings(UKUI_PANEL_SETTINGS_ID, UKUI_PANEL_SETTINGS_PATH, this); setGSettings(QStringLiteral("panelposition"), m_panelPosition); setGSettings(QStringLiteral("panelsize"), m_windowRegion.height()); setGSettings(QStringLiteral("hidepanel"), m_autoHide); setGSettings(QStringLiteral("lockpanel"), m_lockPanel); } } void PanelNext::setGSettings(const QString& key, const QVariant& value) { if (!m_settings) { return; } if (m_settings->keys().contains(key)) { m_settings->set(key, value); } } } // UkuiPanel ukui-panel/panel/src/view/island-drag-helper.h0000664000175000017500000000404515167645100020235 0ustar fengfeng// // Created by iaom on 2024/9/24. // #ifndef ISLAND_DRAG_HELPER_H #define ISLAND_DRAG_HELPER_H #include class QQuickItem; class IslandDragHelper : public QObject { //从顶栏即将拖动到任务栏时,为了实时获取这个岛的布局尺寸,直接加载这个岛但是隐藏内容。Island内部用此属性判断是否是隐藏内容 Q_PROPERTY(bool islandPendingAdd2Panel READ islandPendingAdd2Panel WRITE setIslandPendingAdd2Panel NOTIFY islandPendingAdd2PanelChanged) Q_PROPERTY(bool dragging READ dragging WRITE setDragging NOTIFY draggingChanged) Q_PROPERTY(QString draggingIsland READ draggingIsland WRITE setDraggingIsland NOTIFY draggingIslandChanged) Q_OBJECT public: static IslandDragHelper* self(); //drag //从顶栏拖出 Q_INVOKABLE void IslandDragRemovingFromTopBar(bool removeWhenDrop); //从任务栏拖出 Q_INVOKABLE void IslandDragRemovingFromPanel(bool removeWhenDrop); //drop //从顶栏拖动到任务栏 Q_INVOKABLE void IslandDragRemoveFromTopBar(const QString &island); //从任务栏拖动到顶栏 Q_INVOKABLE void IslandDragRemoveFromPanel(const QString &island); bool islandPendingAdd2Panel() const; void setIslandPendingAdd2Panel(bool islandPendingAdd2Panel); bool dragging() const; void setDragging(bool dragging); QString draggingIsland(); void setDraggingIsland(const QString &draggingIsland); Q_SIGNALS: //拖拽换位,松手 void dragRemoveFromPanel(const QString &island); void dragRemoveFromTopBar(const QString &island); //拖拽换位,但还未松手 void dragRemovingFromPanel(const QString &island, bool removeWhenDrop); void dragRemovingFromTopBar(const QString &island, bool removeWhenDrop); void islandPendingAdd2PanelChanged(); void draggingChanged(); void draggingIslandChanged(); private: IslandDragHelper(QObject *parent = nullptr); bool m_islandPendingAdd2Panel{false}; bool m_dragging{false}; QString m_draggingIsland; }; #endif //ISLAND_DRAG_HELPER_H ukui-panel/panel/src/data-collector.h0000664000175000017500000000274215167645111016522 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef DATACOLLECTOR_H #define DATACOLLECTOR_H #include #include class DataCollector { private: /** * 将panel的位置转化为英文字符串上下左右 上: 1, 下: 0, 左: 2, 右: 3, 如果为其他值,则说明任务栏不存在 * @param pos panel的位置 */ static QString positionToStr(const int &pos); public: /** * 发送panel位置改变事件的数据锚点 * @param pos panel的位置 */ static void setPanelPositionEvent(const int &pos); /** * 发送panel大小改变事件的数据锚点描点 * @param panelSize panel的大小 */ static void setPanelSizeEvent(const int &panelSize); }; #endif // DATACOLLECTOR_H ukui-panel/panel/src/shell.cpp0000664000175000017500000003321115167645111015262 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * iaom */ #include "shell.h" #include "panel.h" #include "panel-next.h" #include #include #include #include #include #include #include "panel-top-bar.h" #include "island-drag-helper.h" #include "panel-gsettings.h" #include "paneladaptor.h" using namespace UkuiPanel; static Shell *s_shell = nullptr; Shell *Shell::self() { if(!s_shell) { s_shell = new Shell; } return s_shell; } Shell::Shell(QObject *parent) : QObject(parent) { qRegisterMetaType(); qmlRegisterSingletonType("org.ukui.panel.shell", 1, 0, "IslandDragHelper", [](QQmlEngine*, QJSEngine*) -> QObject* { return IslandDragHelper::self(); }); m_screenManager = new ScreensManager(this); initRemoteConfig(); initDbus(); m_config = UkuiQuick::ConfigLoader::getConfig(QStringLiteral("panel"), UkuiQuick::ConfigLoader::Local, QStringLiteral("ukui-panel")); if(m_config->getValue(QStringLiteral("currentPanelVersion")).isNull()) { m_config->setValue(QStringLiteral("currentPanelVersion"), Version4); m_currentVersion = Version4; } else { m_currentVersion = static_cast(m_config->getValue(QStringLiteral("currentPanelVersion")).toInt()); } PanelGSettings::instance()->setPanelType(m_currentVersion); if(m_config->contains("showPanelOnAllScreens")) { m_showPanelOnAllScreens = m_config->getValue(QStringLiteral("showPanelOnAllScreens")).toBool(); } else { m_showPanelOnAllScreens = true; m_config->setValue(QStringLiteral("showPanelOnAllScreens"), m_showPanelOnAllScreens); } connect(m_config, &UkuiQuick::Config::configChanged, this, [&](QString key){ if(key == "currentPanelVersion") { if(m_currentVersion != static_cast(m_config->getValue(QStringLiteral("currentPanelVersion")).toInt())) { switchTo(static_cast(m_config->getValue(QStringLiteral("currentPanelVersion")).toInt())); } } else if(key == "showPanelOnAllScreens") { auto value = m_config->getValue(QStringLiteral("showPanelOnAllScreens")).toBool(); if(value == m_showPanelOnAllScreens) { return; } m_showPanelOnAllScreens = value; if (!m_configDataChange) { m_configDataChange = true; auto ev = new QEvent(QEvent::UpdateRequest); QCoreApplication::postEvent(this, ev); } } }); connect(m_screenManager, &ScreensManager::screenAdded, this, [&](Screen *screen){ if(!m_showPanelOnAllScreens) { return; } if(!screen->isValid()) { return; } if(PanelType::Version4 == m_currentVersion) { if(!m_panelsVersion4.contains(screen)) { auto panel = new Panel(screen, QString("panel%1").arg(m_panelsVersion4.size())); connect(m_screenManager, &ScreensManager::primaryScreenChanged, panel, &Panel::primaryScreenChanged); m_panelsVersion4.insert(screen, panel); } } else { if(!m_panelsVersion5.contains(screen)) { m_panelsVersion5.insert(screen, createPanelNext(screen, QString("panel%1").arg(m_panelsVersion5.size()))); m_panelTopBars.insert(screen, createPanelTopBar(screen, QString("panelTopBar%1").arg(m_panelTopBars.size()))); } } }); connect(m_screenManager, &ScreensManager::screenRemoved, this, [&](Screen *screen){ if(m_panelsVersion4.contains(screen)) { delete m_panelsVersion4.take(screen); } if (m_panelsVersion5.contains(screen)) { delete m_panelsVersion5.take(screen); } if (m_panelTopBars.contains(screen)) { delete m_panelTopBars.take(screen); } }); connect(m_screenManager, &ScreensManager::primaryScreenChanged, this, [&](Screen *screen){ if(m_showPanelOnAllScreens) { return; } if(PanelType::Version4 == m_currentVersion) { auto panel = m_panelsVersion4.first(); m_panelsVersion4.clear(); panel->setPanelScreen(screen); m_panelsVersion4.insert(screen, panel); } else { auto panel = m_panelsVersion5.first(); m_panelsVersion5.clear(); panel->setPanelScreen(screen); m_panelsVersion5.insert(screen, panel); auto toolBar = m_panelTopBars.first(); m_panelTopBars.clear(); toolBar->setTopBarScreen(screen); m_panelTopBars.insert(screen, toolBar); } }); new PanelAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/panel"), this); dbus.registerService(QStringLiteral("org.ukui.panel")); } void Shell::start() { switch (m_currentVersion) { case Version4: startVersion4panel(); break; case Version5: startVersion5Panel(); break; } m_started = true; m_remoteConfig->updateMainViewConfig(); } void Shell::initRemoteConfig() { m_remoteConfig = new RemoteConfig(this); QString display = QCoreApplication::instance()->property("display").toString(); QUrl address(QStringLiteral("local:ukui-panel-config-") + QString(qgetenv("USER")) + display); m_qroHost.setHostUrl(address); qDebug() << "Init static remote config object:" << m_qroHost.enableRemoting(m_remoteConfig); qDebug() << "Init dynamic remote config object:" << m_qroHost.enableRemoting(m_remoteConfig,"RemoteConfig"); } void Shell::initDbus() { //dbus const QString statusManagerService = "com.kylin.statusmanager.interface"; QDBusInterface statusManagerDBus(statusManagerService, "/" , statusManagerService, QDBusConnection::sessionBus(), this); if (statusManagerDBus.isValid()) { QDBusReply message = statusManagerDBus.call("get_current_tabletmode"); if (message.isValid()) { m_isTabletMode = message.value(); } } onTabletModeChanged(m_isTabletMode); //平板模式切换信号 QDBusConnection::sessionBus().connect(statusManagerService, "/", statusManagerService, "mode_change_signal", this, SLOT(onTabletModeChanged(bool))); } void Shell::onTabletModeChanged(bool isTabletMode) { m_isTabletMode = isTabletMode; for (const auto &panel : m_panelsVersion4) { panel->setVisible(!m_isTabletMode); } for (const auto &panel : m_panelsVersion5) { panel->setVisible(!m_isTabletMode); } } void Shell::switchTo(Shell::PanelType type) { if(type == m_currentVersion) { return; } if(m_started) { qDeleteAll(m_panelsVersion4); m_panelsVersion4.clear(); qDeleteAll(m_panelsVersion5); m_panelsVersion5.clear(); qDeleteAll(m_panelTopBars); m_panelTopBars.clear(); } m_currentVersion = type; m_config->setValue(QStringLiteral("currentPanelVersion"), m_currentVersion); start(); PanelGSettings::instance()->setPanelType(m_currentVersion); } void Shell::startVersion4panel() { qDebug() << "startVersion4panel!"; Screen *primary = m_screenManager->primaryScreen(); auto panel = new Panel(primary, "panel0"); connect(m_screenManager, &ScreensManager::primaryScreenChanged, panel, &Panel::primaryScreenChanged); m_panelsVersion4.insert(primary, panel); //如果设置为在所有屏幕上显示任务栏再创建副屏的任务栏,否则不创建 if(m_showPanelOnAllScreens) { for(Screen * screen : m_screenManager->screens()) { if(!screen->isValid()) { return; } if(screen != primary) { panel = new Panel(screen, QString("panel%1").arg(m_panelsVersion4.size())); connect(m_screenManager, &ScreensManager::primaryScreenChanged, panel, &Panel::primaryScreenChanged); m_panelsVersion4.insert(screen, panel); } } } } void Shell::startVersion5Panel() { qDebug() << "startVersion5panel!"; Screen *primary = m_screenManager->primaryScreen(); m_panelsVersion5.insert(primary, createPanelNext(primary, "panel0")); m_panelTopBars.insert(primary, createPanelTopBar(primary, "panelTopBar0")); if(m_showPanelOnAllScreens) { for(Screen * screen : m_screenManager->screens()) { if(screen != primary) { m_panelsVersion5.insert(screen, createPanelNext(screen, QString("panel%1").arg(m_panelsVersion5.size()))); m_panelTopBars.insert(screen, createPanelTopBar(screen, QString("panelTopBar%1").arg(m_panelTopBars.size()))); } } } } PanelNext* Shell::createPanelNext(Screen *screen, const QString& id) { auto panel = new PanelNext(screen, id); //island从任务栏移除 connect(panel, &PanelNext::islandRemoved, this, &Shell::islandRemovedFromPanel); //island从顶栏移除,增加到任务栏上 connect(this, &Shell::islandRemovedFromTopBar, panel, &PanelNext::addIsland); //island从任务栏移除,同步给所有任务栏 connect(this, &Shell::islandRemovedFromPanel, panel, &PanelNext::removeIsland); //增加自定义插件 connect(panel, &PanelNext::customWidgetAdded, this, &Shell::customWidgetAdded); connect(this, &Shell::customWidgetAdded, panel, &PanelNext::addCustomWidget); //移除自定义插件 connect(panel, &PanelNext::customWidgetRemoved, this, &Shell::customWidgetRemoved); connect(this, &Shell::customWidgetRemoved, panel, &PanelNext::removeCustomWidget); return panel; } PanelTopBar* Shell::createPanelTopBar(Screen* screen, const QString& id) { auto panelTopBar = new PanelTopBar(screen, id); //island从顶移除 connect(panelTopBar, &PanelTopBar::islandRemoved, this, &Shell::islandRemovedFromTopBar); //island从任务栏移除,添加到顶栏上 connect(this, &Shell::islandRemovedFromPanel, panelTopBar, &PanelTopBar::addIsland); //island从顶栏移除,同步给所有顶栏 connect(this, &Shell::islandRemovedFromTopBar, panelTopBar, &PanelTopBar::removeIsland); return panelTopBar; } Shell::PanelType Shell::currentVersion() { return m_currentVersion; } bool Shell::addCustomWidget(const QString& id) { if(!m_panelsVersion5.isEmpty() && !id.isEmpty()) { return m_panelsVersion5.first()->addCustomWidget(id); } return false; } bool Shell::removeCustomWidget(const QString& id) { if(!m_panelsVersion5.isEmpty() && !id.isEmpty()) { return m_panelsVersion5.first()->removeCustomWidget(id); } return false; } bool Shell::event(QEvent* e) { if (e->type() == QEvent::UpdateRequest) { //是否在所有屏幕上显示任务栏,变为true时 //创建副屏的任务栏 if(m_showPanelOnAllScreens) { for(Screen * screen : m_screenManager->screens()) { if(!screen->isValid()) { continue; } if(m_currentVersion == PanelType::Version4) { if(!m_panelsVersion4.contains(screen)) { auto panel = new Panel(screen, QString("panel%1").arg(m_panelsVersion4.size())); connect(m_screenManager, &ScreensManager::primaryScreenChanged, panel, &Panel::primaryScreenChanged); m_panelsVersion4.insert(screen, panel); } } else { if(!m_panelsVersion5.contains(screen)) { m_panelsVersion5.insert(screen, createPanelNext(screen, QString("panel%1").arg(m_panelsVersion5.size()))); m_panelTopBars.insert(screen, createPanelTopBar(screen, QString("panelTopBar%1").arg(m_panelTopBars.size()))); } } } } else { //是否在所有屏幕上显示任务栏,变为false时 //删除不是主屏任务栏的所有任务栏 for(Screen * screen : m_screenManager->screens()) { if(m_currentVersion == PanelType::Version4) { if(m_panelsVersion4.contains(screen) && screen != m_screenManager->primaryScreen()) { delete m_panelsVersion4.take(screen); } } else { if(m_panelsVersion5.contains(screen) && screen != m_screenManager->primaryScreen()) { delete m_panelsVersion5.take(screen); } if(m_panelTopBars.contains(screen) && screen != m_screenManager->primaryScreen()) { delete m_panelTopBars.take(screen); } } } } m_configDataChange = false; e->accept(); } return QObject::event(e); } ukui-panel/panel/src/remote-config.cpp0000664000175000017500000007223415167645111016721 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "remote-config.h" #include #include #include #include #include RemoteConfig::RemoteConfig(QObject *parent) : RemoteConfigSource(parent) , m_mergeIcons(GeneralConfigDefine::MergeIcons::Never) , m_panelLocation(GeneralConfigDefine::PanelLocation::Bottom) , m_panelSizePolicy(GeneralConfigDefine::PanelSizePolicy::Small) , m_allowCustomSize(false) , m_panelAutoHide(false) , m_panelLock(false) , m_taskBarIconsShowedOn(GeneralConfigDefine::TaskBarIconsShowedOn::AllPanels) , m_panelType(GeneralConfigDefine::PanelType::Version4) , m_showPanelOnAllScreens(true) , m_showSystemTrayOnAllPanels(true) , m_panelLocationNext(GeneralConfigDefine::PanelLocation::Bottom) , m_panelSizePolicyNext(GeneralConfigDefine::PanelSizePolicy::Small) , m_panelAutoHideNext(false) , m_panelLockNext(false) { qRegisterMetaType("GeneralConfigDefine::MergeIcons"); qRegisterMetaType("GeneralConfigDefine::PanelLocation"); qRegisterMetaType("GeneralConfigDefine::PanelSizePolicy"); qRegisterMetaType("GeneralConfigDefine::TaskBarIconsShowedOn"); m_taskManagerConfig = UkuiQuick::ConfigLoader::getConfig("org.ukui.panel.taskManager"); m_systemTrayConfig = UkuiQuick::ConfigLoader::getConfig("org.ukui.systemTray"); m_mergeIcons = m_taskManagerConfig->getValue(QStringLiteral("mergeIcons")).value(); m_trayIconsInhibited = m_systemTrayConfig->getValue(QStringLiteral("trayIconsInhibited")).toStringList(); m_trayIconsCanInhibited = m_systemTrayConfig->getValue(QStringLiteral("trayIconsCanInhibited")).toStringList(); m_taskBarIconsShowedOn = m_taskManagerConfig->getValue(QStringLiteral("taskBarIconsShowedOn")).value(); connect(m_taskManagerConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onTaskManagerConfigChanged); connect(m_systemTrayConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onSystemTrayConfigChanged); m_panelConfig = UkuiQuick::ConfigLoader::getConfig("panel", UkuiQuick::ConfigLoader::Local, "ukui-panel"); m_panelConfig->addGroupInfo(UkuiQuick::Island::viewGroupName(), UkuiQuick::Island::viewGroupKey()); for(auto config : m_panelConfig->children(UkuiQuick::Island::viewGroupName())) { if(config->getValue("id").toString() == "org.ukui.panel") { m_mainViewConfig = config; } else if(config->getValue("id").toString() == "org.ukui.panelNext") { m_mainViewNextConfig = config; } else if(config->getValue("id").toString() == "org.ukui.panelTopBar") { m_mainViewTopBarConfig = config; } } connect(m_panelConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onPanelConfigChanged); m_showPanelOnAllScreens = m_panelConfig->getValue(QStringLiteral("showPanelOnAllScreens")).toBool(); m_panelType = m_panelConfig->getValue(QStringLiteral("currentPanelVersion")).value(); if (m_mainViewConfig) { m_disabledWidgets = m_mainViewConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); m_panelSizePolicy = m_mainViewConfig->getValue(QStringLiteral("panelSizePolicy")).value(); m_allowCustomSize = m_mainViewConfig->contains(QStringLiteral("customPanelSize")); m_panelAutoHide = m_mainViewConfig->getValue(QStringLiteral("panelAutoHide")).toBool(); m_panelLock = m_mainViewConfig->getValue(QStringLiteral("lockPanel")).toBool(); m_panelWidgets = m_mainViewConfig->getValue(QStringLiteral("widgets")).toStringList(); m_showSystemTrayOnAllPanels = m_mainViewConfig->getValue(QStringLiteral("showSystemTrayOnAllPanels")).toBool(); connect(m_mainViewConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onPanelViewConfigChanged, Qt::UniqueConnection); updatePanelLocation(); } if (m_mainViewNextConfig) { m_disabledWidgetsNext = m_mainViewNextConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); m_panelSizePolicyNext = m_mainViewNextConfig->getValue(QStringLiteral("panelSizePolicy")).value(); m_panelAutoHideNext = m_mainViewNextConfig->getValue(QStringLiteral("panelAutoHide")).toBool(); m_panelLockNext = m_mainViewNextConfig->getValue(QStringLiteral("lockPanel")).toBool(); m_panelWidgets = m_mainViewNextConfig->getValue(QStringLiteral("widgets")).toStringList(); connect(m_mainViewNextConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onPanelViewConfigNextChanged, Qt::UniqueConnection); updatePanelLocationNext(); } //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-v11")); onFunctionControlChanged(QStringLiteral("ukui-panel-v11"), false); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-v11"), true); }); } RemoteConfig::~RemoteConfig() { UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-v11")); } GeneralConfigDefine::PanelLocation RemoteConfig::panelLocation() const { if (m_controlPanelLocation) { return static_cast(m_controlConfig.value(QStringLiteral("panelLocation")).toInt()); } return m_panelLocation; } GeneralConfigDefine::PanelSizePolicy RemoteConfig::panelSizePolicy() const { if (m_controlPanelSizePolicy) { return static_cast(m_controlConfig.value(QStringLiteral("panelSizePolicy")).toInt()); } return m_panelSizePolicy; } bool RemoteConfig::allowCustomSize() const { return m_allowCustomSize; } bool RemoteConfig::panelAutoHide() const { if (m_controlPanelAutoHide) { return m_controlConfig.value(QStringLiteral("panelAutoHide")).toBool(); } return m_panelAutoHide; } bool RemoteConfig::panelLock() const { if (m_controlPanelLock) { return m_controlConfig.value(QStringLiteral("panelAutoHide")).toBool(); } return m_panelLock; } void RemoteConfig::setMergeIcons(GeneralConfigDefine::MergeIcons mergeIcons) { if (mergeIcons != m_mergeIcons) { m_mergeIcons = mergeIcons; m_taskManagerConfig->setValue(QStringLiteral("mergeIcons"), mergeIcons); Q_EMIT mergeIconsChanged(m_mergeIcons); } } void RemoteConfig::setPanelLocation(GeneralConfigDefine::PanelLocation panelLocation) { if (m_controlPanelLocation) { qDebug() << "RemoteConfig::setPanelLocation() is not available cause this function is controled!"; return; } if (panelLocation != m_panelLocation) { m_panelLocation = panelLocation; UkuiQuick::Types::Pos pos; switch (m_panelLocation) { default: case GeneralConfigDefine::Bottom: pos = UkuiQuick::Types::Bottom; break; case GeneralConfigDefine::Left: pos = UkuiQuick::Types::Left; break; case GeneralConfigDefine::Top: pos = UkuiQuick::Types::Top; break; case GeneralConfigDefine::Right: pos = UkuiQuick::Types::Right; break; } if(m_mainViewConfig) { m_mainViewConfig->setValue(QStringLiteral("position"), pos); } Q_EMIT panelLocationChanged(m_panelLocation); } } void RemoteConfig::setPanelSizePolicy(GeneralConfigDefine::PanelSizePolicy panelSizePolicy) { if (m_controlPanelSizePolicy) { qDebug() << "RemoteConfig::setPanelSizePolicy() is not available cause this function is controled!"; return; } if (panelSizePolicy != m_panelSizePolicy) { m_panelSizePolicy = panelSizePolicy; if(m_mainViewConfig) { m_mainViewConfig->setValue(QStringLiteral("panelSizePolicy"), panelSizePolicy); } Q_EMIT panelSizePolicyChanged(m_panelSizePolicy); } } void RemoteConfig::setPanelAutoHide(bool panelAutoHide) { if (m_controlPanelAutoHide) { qDebug() << "RemoteConfig::setPanelAutoHide() is not available cause this function is controled!"; return; } if (panelAutoHide != m_panelAutoHide) { m_panelAutoHide = panelAutoHide; if(m_mainViewConfig) { m_mainViewConfig->setValue(QStringLiteral("panelAutoHide"), panelAutoHide); } Q_EMIT panelAutoHideChanged(m_panelAutoHide); } } void RemoteConfig::setPanelLock(bool panelLock) { if (m_controlPanelLock) { qDebug() << "RemoteConfig::setPanelLock() is not available cause this function is controled!"; return; } if (panelLock != m_panelLock) { m_panelLock = panelLock; if(m_mainViewConfig) { m_mainViewConfig->setValue(QStringLiteral("lockPanel"), panelLock); } Q_EMIT panelLockChanged(m_panelLock); } } void RemoteConfig::setPanelWidgets(QStringList panelWidgets) { if (panelWidgets != m_panelWidgets) { m_panelWidgets = panelWidgets; if(m_mainViewConfig) { m_mainViewConfig->setValue(QStringLiteral("widgets"), m_panelWidgets); } Q_EMIT panelWidgetsChanged(m_panelWidgets); } } void RemoteConfig::setTrayIconsInhibited(QStringList trayIconsInhibited) { if (trayIconsInhibited != m_trayIconsInhibited) { m_trayIconsInhibited = trayIconsInhibited; m_systemTrayConfig->setValue(QStringLiteral("trayIconsInhibited"), trayIconsInhibited); Q_EMIT trayIconsInhibitedChanged(m_trayIconsInhibited); } } void RemoteConfig::onPanelViewConfigChanged(const QString &key) { if(!m_mainViewConfig) { return; } if (key == QStringLiteral("disabledWidgets")) { m_disabledWidgets = m_mainViewConfig->getValue(key).toStringList(); Q_EMIT disabledWidgetsChanged(m_disabledWidgets); } else if(key == "panelSizePolicy") { auto value = m_mainViewConfig->getValue(QStringLiteral("panelSizePolicy")).value(); if(value != m_panelSizePolicy) { m_panelSizePolicy = value; Q_EMIT panelSizePolicyChanged(m_panelSizePolicy); } } else if (key == "customPanelSize") { auto allow = m_mainViewConfig->contains(QStringLiteral("customPanelSize")); if (allow != m_allowCustomSize) { m_allowCustomSize = allow; Q_EMIT allowCustomSizeChanged(m_allowCustomSize); } } else if (key == "panelAutoHide") { bool value = m_mainViewConfig->getValue(QStringLiteral("panelAutoHide")).toBool(); if(value != m_panelAutoHide) { m_panelAutoHide = value; Q_EMIT panelAutoHideChanged(m_panelAutoHide); } } else if (key == "lockPanel") { bool value = m_mainViewConfig->getValue(QStringLiteral("lockPanel")).toBool(); if(value != m_panelLock) { m_panelLock = value; Q_EMIT panelLockChanged(m_panelLock); } } else if (key == "widgets") { QStringList value = m_mainViewConfig->getValue(QStringLiteral("widgets")).toStringList(); if(value != m_panelWidgets) { m_panelWidgets = value; Q_EMIT panelWidgetsChanged(m_panelWidgets); } } else if (key == "position") { updatePanelLocation(); Q_EMIT panelLocationChanged(m_panelLocation); } else if (key == "showSystemTrayOnAllPanels") { bool value = m_mainViewConfig->getValue(QStringLiteral("showSystemTrayOnAllPanels")).toBool(); if(value != m_showSystemTrayOnAllPanels) { m_showSystemTrayOnAllPanels = value; Q_EMIT showSystemTrayOnAllPanelsChanged(m_showSystemTrayOnAllPanels); } } } void RemoteConfig::onPanelConfigChanged(const QString &key) { if (key == "currentPanelVersion") { auto value = m_panelConfig->getValue(QStringLiteral("currentPanelVersion")).value(); if(value != m_panelType) { m_panelType = value; Q_EMIT panelTypeChanged(m_panelType); } } else if (key == "showPanelOnAllScreens") { bool value = m_panelConfig->getValue(QStringLiteral("showPanelOnAllScreens")).toBool(); if(value != m_showPanelOnAllScreens) { m_showPanelOnAllScreens = value; Q_EMIT showPanelOnAllScreensChanged(m_showPanelOnAllScreens); } } } void RemoteConfig::onTaskManagerConfigChanged(const QString &key) { if(key == "mergeIcons") { auto value = m_taskManagerConfig->getValue(QStringLiteral("mergeIcons")).value(); if(value != m_mergeIcons) { m_mergeIcons = value; Q_EMIT mergeIconsChanged(m_mergeIcons); } } else if (key == "taskBarIconsShowedOn") { auto value = m_taskManagerConfig->getValue(QStringLiteral("taskBarIconsShowedOn")).value(); if(value != m_taskBarIconsShowedOn) { m_taskBarIconsShowedOn = value; Q_EMIT taskBarIconsShowedOnChanged(m_taskBarIconsShowedOn); } } } void RemoteConfig::onSystemTrayConfigChanged(const QString &key) { if(key == "trayIconsInhibited") { auto value = m_systemTrayConfig->getValue(QStringLiteral("trayIconsInhibited")).toStringList(); if(value != m_trayIconsInhibited) { m_trayIconsInhibited = value; Q_EMIT trayIconsInhibitedChanged(m_trayIconsInhibited); } } if(key == "trayIconsCanInhibited") { auto value = m_systemTrayConfig->getValue(QStringLiteral("trayIconsCanInhibited")).toStringList(); if(value != m_trayIconsCanInhibited) { m_trayIconsCanInhibited = value; Q_EMIT trayIconsCanInhibitedChanged(m_trayIconsCanInhibited); } } } void RemoteConfig::updatePanelLocation() { if(!m_mainViewConfig) { return; } auto pos = m_mainViewConfig->getValue(QStringLiteral("position")).value(); switch (pos) { case UkuiQuick::Types::Left: m_panelLocation = GeneralConfigDefine::PanelLocation::Left; break; case UkuiQuick::Types::Top: m_panelLocation = GeneralConfigDefine::PanelLocation::Top; break; case UkuiQuick::Types::Right: m_panelLocation = GeneralConfigDefine::PanelLocation::Right; break; default: case UkuiQuick::Types::Bottom: m_panelLocation = GeneralConfigDefine::PanelLocation::Bottom; break; } } QStringList RemoteConfig::disabledWidgets() const { if (m_controlDisableWidget) { QStringList disableWidgets; for (QVariant &disableWidget : m_controlConfig.value(QStringLiteral("disableWidgets")).toArray().toVariantList()) { disableWidgets.append(disableWidget.toString()); } return disableWidgets; } return m_disabledWidgets; } void RemoteConfig::disableWidget(const QString &id, bool disable) { if (m_controlDisableWidget) { qDebug() << "RemoteConfig::disableWidget() is not available cause this function is controled!"; return; } if (!m_mainViewConfig) { return; } if (disable) { if (m_disabledWidgets.contains(id)) { return; } m_disabledWidgets.append(id); } else if (m_disabledWidgets.removeAll(id) == 0) { return; } m_mainViewConfig->setValue(QStringLiteral("disabledWidgets"), m_disabledWidgets); } void RemoteConfig::setTaskBarIconsShowedOn(GeneralConfigDefine::TaskBarIconsShowedOn taskBarIconsShowedOn) { if (taskBarIconsShowedOn != m_taskBarIconsShowedOn) { m_taskBarIconsShowedOn = taskBarIconsShowedOn; if(m_taskManagerConfig) { m_taskManagerConfig->setValue(QStringLiteral("taskBarIconsShowedOn"), taskBarIconsShowedOn); } Q_EMIT taskBarIconsShowedOnChanged(m_taskBarIconsShowedOn); } } void RemoteConfig::setPanelType(GeneralConfigDefine::PanelType panelType) { if (panelType != m_panelType) { m_panelType = panelType; Q_EMIT panelTypeChanged(m_panelType); if(m_panelConfig) { m_panelConfig->setValue(QStringLiteral("currentPanelVersion"), m_panelType); } } } void RemoteConfig::setShowPanelOnAllScreens(bool showPanelOnAllScreens) { if (showPanelOnAllScreens != m_showPanelOnAllScreens) { m_showPanelOnAllScreens = showPanelOnAllScreens; if(m_panelConfig) { m_panelConfig->setValue(QStringLiteral("showPanelOnAllScreens"), showPanelOnAllScreens); } Q_EMIT showPanelOnAllScreensChanged(m_showPanelOnAllScreens); } } void RemoteConfig::setShowSystemTrayOnAllPanels(bool showSystemTrayOnAllPanels) { if (showSystemTrayOnAllPanels != m_showSystemTrayOnAllPanels) { m_showSystemTrayOnAllPanels = showSystemTrayOnAllPanels; if(m_mainViewConfig) { m_mainViewConfig->setValue(QStringLiteral("showSystemTrayOnAllPanels"), showSystemTrayOnAllPanels); } Q_EMIT showSystemTrayOnAllPanelsChanged(m_showSystemTrayOnAllPanels); } } void RemoteConfig::setPanelLocationNext(GeneralConfigDefine::PanelLocation panelLocation) { if (panelLocation != m_panelLocationNext) { m_panelLocationNext = panelLocation; UkuiQuick::Types::Pos pos; switch (m_panelLocationNext) { default: case GeneralConfigDefine::Bottom: pos = UkuiQuick::Types::Bottom; break; case GeneralConfigDefine::Left: pos = UkuiQuick::Types::Left; break; case GeneralConfigDefine::Top: pos = UkuiQuick::Types::Top; break; case GeneralConfigDefine::Right: pos = UkuiQuick::Types::Right; break; } if(m_mainViewNextConfig) { m_mainViewNextConfig->setValue(QStringLiteral("position"), pos); } Q_EMIT panelLocationNextChanged(m_panelLocationNext); } } void RemoteConfig::setPanelSizePolicyNext(GeneralConfigDefine::PanelSizePolicy panelSizePolicy) { if (panelSizePolicy != m_panelSizePolicyNext) { m_panelSizePolicyNext = panelSizePolicy; if(m_mainViewNextConfig) { m_mainViewNextConfig->setValue(QStringLiteral("panelSizePolicy"), panelSizePolicy); } Q_EMIT panelSizePolicyNextChanged(m_panelSizePolicyNext); } } void RemoteConfig::setPanelAutoHideNext(bool panelAutoHide) { if (panelAutoHide != m_panelAutoHideNext) { m_panelAutoHideNext = panelAutoHide; if(m_mainViewNextConfig) { m_mainViewNextConfig->setValue(QStringLiteral("panelAutoHide"), panelAutoHide); } Q_EMIT panelAutoHideNextChanged(m_panelAutoHideNext); } } void RemoteConfig::setPanelLockNext(bool panelLock) { if (panelLock != m_panelLockNext) { m_panelLockNext = panelLock; if(m_mainViewNextConfig) { m_mainViewNextConfig->setValue(QStringLiteral("lockPanel"), panelLock); } Q_EMIT panelLockNextChanged(m_panelLockNext); } } void RemoteConfig::onPanelViewConfigNextChanged(const QString &key) { if(!m_mainViewNextConfig) { return; } if (key == QStringLiteral("disabledWidgets")) { m_disabledWidgetsNext = m_mainViewNextConfig->getValue(key).toStringList(); Q_EMIT disabledWidgetsNextChanged(m_disabledWidgetsNext); } else if(key == "panelSizePolicy") { auto value = m_mainViewNextConfig->getValue(QStringLiteral("panelSizePolicy")).value(); if(value != m_panelSizePolicyNext) { m_panelSizePolicyNext = value; Q_EMIT panelSizePolicyNextChanged(m_panelSizePolicyNext); } } else if (key == "panelAutoHide") { bool value = m_mainViewNextConfig->getValue(QStringLiteral("panelAutoHide")).toBool(); if(value != m_panelAutoHideNext) { m_panelAutoHideNext = value; Q_EMIT panelAutoHideNextChanged(m_panelAutoHideNext); } } else if (key == "lockPanel") { bool value = m_mainViewNextConfig->getValue(QStringLiteral("lockPanel")).toBool(); if(value != m_panelLockNext) { m_panelLockNext = value; Q_EMIT panelLockNextChanged(m_panelLockNext); } } else if (key == "widgets") { QStringList value = m_mainViewNextConfig->getValue(QStringLiteral("widgets")).toStringList(); if(value != m_panelWidgetsNext) { m_panelWidgetsNext = value; Q_EMIT panelWidgetsNextChanged(m_panelWidgetsNext); } } else if (key == "position") { updatePanelLocationNext(); Q_EMIT panelLocationNextChanged(m_panelLocationNext); } } void RemoteConfig::updatePanelLocationNext() { if(!m_mainViewNextConfig) { return; } auto pos = m_mainViewNextConfig->getValue(QStringLiteral("position")).value(); switch (pos) { case UkuiQuick::Types::Left: m_panelLocationNext = GeneralConfigDefine::PanelLocation::Left; break; case UkuiQuick::Types::Top: m_panelLocationNext = GeneralConfigDefine::PanelLocation::Top; break; case UkuiQuick::Types::Right: m_panelLocationNext = GeneralConfigDefine::PanelLocation::Right; break; default: case UkuiQuick::Types::Bottom: m_panelLocationNext = GeneralConfigDefine::PanelLocation::Bottom; break; } } void RemoteConfig::disableWidgetNext(const QString &id, bool disable) { if (!m_mainViewNextConfig) { return; } if (disable) { if (m_disabledWidgetsNext.contains(id)) { return; } m_disabledWidgetsNext.append(id); } else if (m_disabledWidgetsNext.removeAll(id) == 0) { return; } m_mainViewNextConfig->setValue(QStringLiteral("disabledWidgets"), m_disabledWidgetsNext); if(!m_mainViewTopBarConfig) { return; } m_mainViewTopBarConfig->setValue(QStringLiteral("disabledWidgets"), m_disabledWidgetsNext); } void RemoteConfig::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-v11")) { return; } m_controlConfig = exit ? QJsonObject() : UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "Remote config function control config:" << m_controlConfig; //panelLocation 0-bottom; 1-left; 2-top; 3-right if (m_controlConfig.contains(QStringLiteral("panelLocation"))) { m_controlPanelLocation = true; Q_EMIT panelLocationChanged(static_cast(m_controlConfig.value(QStringLiteral("panelLocation")).toInt())); } else { m_controlPanelLocation = false; Q_EMIT panelLocationChanged(m_panelLocation); } //panelSizePolicy 0-Small; 1-Medium; 2-Large; 3-Custom if (m_controlConfig.contains(QStringLiteral("panelSizePolicy"))) { m_controlPanelSizePolicy = true; Q_EMIT panelSizePolicyChanged(static_cast(m_controlConfig.value(QStringLiteral("panelSizePolicy")).toInt())); } else { m_controlPanelSizePolicy = false; Q_EMIT panelSizePolicyChanged(m_panelSizePolicy); } //panelAutoHide if (m_controlConfig.contains(QStringLiteral("panelAutoHide"))) { m_controlPanelAutoHide = true; Q_EMIT panelAutoHideChanged(m_controlConfig.value(QStringLiteral("panelAutoHide")).toBool()); } else { m_controlPanelAutoHide = false; Q_EMIT panelAutoHideChanged(m_panelAutoHide); } //panelLock if (m_controlConfig.contains(QStringLiteral("panelLock"))) { m_controlPanelLock = true; Q_EMIT panelLockChanged(m_controlConfig.value(QStringLiteral("panelLock")).toBool()); } else { m_controlPanelLock = false; Q_EMIT panelLockChanged(m_panelLock); } //disableWidgets if (m_controlConfig.contains(QStringLiteral("disableWidgets"))) { m_controlDisableWidget = true; QStringList disableWidgets; for (QVariant &disableWidget : m_controlConfig.value(QStringLiteral("disableWidgets")).toArray().toVariantList()) { disableWidgets.append(disableWidget.toString()); } Q_EMIT disabledWidgetsChanged(disableWidgets); } else { m_controlDisableWidget = false; Q_EMIT disabledWidgetsChanged(m_disabledWidgets); } } void RemoteConfig::setPanelWidgetsNext(QStringList panelWidgets) { if (panelWidgets != m_panelWidgetsNext) { m_panelWidgetsNext = panelWidgets; if(m_mainViewNextConfig) { m_mainViewNextConfig->setValue(QStringLiteral("widgets"), m_panelWidgetsNext); } Q_EMIT panelWidgetsNextChanged(m_panelWidgetsNext); } } void RemoteConfig::updateMainViewConfig() { for(auto config : m_panelConfig->children(UkuiQuick::Island::viewGroupName())) { if(config->getValue("id").toString() == "org.ukui.panel") { if(!m_mainViewConfig) { m_mainViewConfig = config; m_disabledWidgets = m_mainViewConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); Q_EMIT disabledWidgetsChanged(m_disabledWidgets); m_panelSizePolicy = m_mainViewConfig->getValue(QStringLiteral("panelSizePolicy")).value(); Q_EMIT panelSizePolicyChanged(m_panelSizePolicy); m_panelAutoHide = m_mainViewConfig->getValue(QStringLiteral("panelAutoHide")).toBool(); Q_EMIT panelAutoHideChanged(m_panelAutoHide); m_panelLock = m_mainViewConfig->getValue(QStringLiteral("lockPanel")).toBool(); Q_EMIT panelLockChanged(m_panelLock); m_panelWidgets = m_mainViewConfig->getValue(QStringLiteral("widgets")).toStringList(); Q_EMIT panelWidgetsChanged(m_panelWidgets); m_showSystemTrayOnAllPanels = m_mainViewConfig->getValue(QStringLiteral("showSystemTrayOnAllPanels")).toBool(); Q_EMIT showSystemTrayOnAllPanelsChanged(m_showSystemTrayOnAllPanels); connect(m_mainViewConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onPanelViewConfigChanged, Qt::UniqueConnection); updatePanelLocation(); Q_EMIT panelLocationChanged(m_panelLocation); } } else if(config->getValue("id").toString() == "org.ukui.panelNext") { if(!m_mainViewNextConfig) { m_mainViewNextConfig = config; m_disabledWidgetsNext = m_mainViewNextConfig->getValue(QStringLiteral("disabledWidgets")).toStringList(); Q_EMIT disabledWidgetsNextChanged(m_disabledWidgetsNext); m_panelSizePolicyNext = m_mainViewNextConfig->getValue(QStringLiteral("panelSizePolicy")).value(); Q_EMIT panelSizePolicyNextChanged(m_panelSizePolicyNext); m_panelAutoHideNext = m_mainViewNextConfig->getValue(QStringLiteral("panelAutoHide")).toBool(); Q_EMIT panelAutoHideNextChanged(m_panelAutoHideNext); m_panelLockNext = m_mainViewNextConfig->getValue(QStringLiteral("lockPanel")).toBool(); Q_EMIT panelLockNextChanged(m_panelLockNext); m_panelWidgets = m_mainViewNextConfig->getValue(QStringLiteral("widgets")).toStringList(); Q_EMIT panelWidgetsNextChanged(m_panelWidgetsNext); connect(m_mainViewNextConfig, &UkuiQuick::Config::configChanged, this, &RemoteConfig::onPanelViewConfigNextChanged, Qt::UniqueConnection); updatePanelLocationNext(); Q_EMIT panelLocationNextChanged(m_panelLocationNext); } } else if(config->getValue("id").toString() == "org.ukui.panelTopBar") { if(!m_mainViewTopBarConfig) { m_mainViewTopBarConfig = config; } } } } ukui-panel/panel/src/main.cpp0000664000175000017500000000704215167645111015102 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * iaom * */ #include #include #include #include #include #include "qtsingleapplication.h" #include "shell.h" #include "log-utils.h" #include "message-processor.h" void loadTranslation() { const QString dir = PANEL_TRANSLATION_DIR; const QString prefix = "panel_"; const QString locale = QLocale::system().name(); const QString fileName = dir + prefix + locale; qDebug() << "loadTranslation:" << dir << locale << fileName; auto translator = new QTranslator(QCoreApplication::instance()); if (translator->load(fileName)) { QCoreApplication::installTranslator(translator); } else { translator->deleteLater(); } } int main(int argc, char *argv[]) { #ifndef PANEL_DISABLE_LOG_FILE LogUtils::initLogFile("ukui-panel"); qInstallMessageHandler(LogUtils::messageOutput); #endif QCoreApplication::setApplicationName("ukui-panel"); QCoreApplication::setOrganizationName("ukui"); QCoreApplication::setOrganizationDomain("ukui.org"); QCoreApplication::setApplicationVersion("4.1.0.0"); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif QString sessionType(qgetenv("XDG_SESSION_TYPE")); QString displayEnv = (sessionType == "wayland") ? QLatin1String("WAYLAND_DISPLAY") : QLatin1String("DISPLAY"); QString display(qgetenv(displayEnv.toUtf8().data())); QString appid = QString("ukui-panel-%1").arg(display); qDebug() << "ukui-panel start on display:" << display << "displayEnv:" << displayEnv << "sessionType:" << sessionType; if(sessionType == "wayland") { qputenv("QT_WAYLAND_DISABLE_FIXED_POSITIONS", "true"); //qputenv("QT_WAYLAND_SHELL_INTEGRATION", "ukui-shell"); } QtSingleApplication app(appid, argc, argv); if (app.isRunning()) { MessageProcessor processor; if(processor.preprocessMessage(QtSingleApplication::arguments())) { app.sendMessage(QtSingleApplication::arguments().join(" ").toUtf8()); } return QtSingleApplication::exec(); } //no message need process yet. QObject::connect(&app, &QtSingleApplication::messageReceived, &app, [&](const QString &message) { qDebug() << "ukui-panel receive message:" << message; }); // --_-- // QCoreApplication::instance()->setProperty("display", display); QCoreApplication::instance()->setProperty("displayEnv", displayEnv); loadTranslation(); UkuiPanel::Shell::self()->start(); return QtSingleApplication::exec(); } ukui-panel/panel/src/general-config-define.h0000664000175000017500000000356415167645100017736 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_PANEL_GENERALCONFIGDEFINE_H #define UKUI_PANEL_GENERALCONFIGDEFINE_H #include class GeneralConfigDefine { Q_GADGET public: //task manager enum MergeIcons { Always = 0, Never }; //panel enum PanelLocation { Bottom = 0, Left, Top, Right }; enum PanelSizePolicy { Small = 0, Medium, Large, Custom }; enum IslandsForm { Panel = 0, TopBar }; /** * 多屏时,任务栏图标显示在哪个任务栏 枚举值 * 0-所有屏幕,1-主屏和打开了窗口的任务栏 2-只显示在打开了窗口的任务栏 */ enum TaskBarIconsShowedOn { AllPanels = 0, PrimaryScreenPanelAndPanelWhereWindowIsOpen, PanelWhereWindowIsOpen }; enum PanelType { Version4, Version5 }; Q_ENUM(MergeIcons) Q_ENUM(PanelLocation) Q_ENUM(PanelSizePolicy) Q_ENUM(IslandsForm) Q_ENUM(TaskBarIconsShowedOn) Q_ENUM(PanelType) }; #endif //UKUI_PANEL_GENERALCONFIGDEFINE_H ukui-panel/panel/src/shell.h0000664000175000017500000000521215167645111014727 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * iaom */ #ifndef UKUI_PANEL_SHELL_H #define UKUI_PANEL_SHELL_H #include #include #include #include #include "screens-manager.h" class QScreen; namespace UkuiPanel { class Panel; class PanelNext; class PanelTopBar; class Shell : public QObject { Q_OBJECT public: enum PanelType { Version4, Version5 }; static Shell* self(); void start(); void switchTo(PanelType type); PanelType currentVersion(); public Q_SLOTS: bool addCustomWidget(const QString &id); bool removeCustomWidget(const QString &id); Q_SIGNALS: void islandRemovedFromPanel(const QString &id); void islandRemovedFromTopBar(const QString &id); void dragRemovingFromPanel(const QString &id, bool ); void customWidgetAdded(const QString &id, int instanceId = -1); void customWidgetRemoved(const QString &id, int instanceId = -1); private Q_SLOTS: void onTabletModeChanged(bool); protected: bool event(QEvent* e); private: explicit Shell(QObject *parent=nullptr); void initRemoteConfig(); void initDbus(); void startVersion4panel(); void startVersion5Panel(); PanelNext *createPanelNext(Screen *screen, const QString &id); PanelTopBar *createPanelTopBar(Screen *screen, const QString &id); private: bool m_isTabletMode {false}; QMap m_panelsVersion4; QMap m_panelsVersion5; QMap m_panelTopBars; RemoteConfig *m_remoteConfig = nullptr; QRemoteObjectHost m_qroHost; ScreensManager *m_screenManager = nullptr; bool m_started = false; PanelType m_currentVersion; UkuiQuick::Config *m_config = nullptr; //是否在所有屏幕上显示任务栏 bool m_showPanelOnAllScreens = true; bool m_configDataChange = false; }; } // UkuiPanel #endif //UKUI_PANEL_SHELL_H ukui-panel/panel/src/screens-manager.cpp0000664000175000017500000001060115167645100017221 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include #include "screens-manager.h" namespace UkuiPanel { Screen::Screen(QScreen *screen, QObject *parent): QObject(parent), m_screen(screen) { } QRect Screen::geometry() const { return m_screen->geometry(); } QScreen *Screen::internal() { return m_screen; } bool Screen::enable() { return m_enable; } void Screen::setEnable(bool enable) { if(m_enable != enable) { m_enable = enable; Q_EMIT enableChanged(m_enable); } } bool Screen::isValid() { return (m_screen && m_screen->geometry().width() > 0 && m_screen->geometry().height() > 0); } ScreensManager::ScreensManager(QObject *parent) : QObject(parent) { for(auto screen : qApp->screens()) { onScreenAdded(screen); } connect(qApp, &QGuiApplication::screenAdded, this, &ScreensManager::onScreenAdded); connect(qApp, &QGuiApplication::screenRemoved, this, &ScreensManager::onScreenRemoved); connect(qApp, &QGuiApplication::primaryScreenChanged, this, &ScreensManager::onPrimaryScreenChanged); } ScreensManager::~ScreensManager() { qDeleteAll(m_screens); } QList ScreensManager::screens() { QList tmp; for(auto screen : m_screens) { if(screen->enable()) { tmp.append(screen); } } return tmp; } Screen *ScreensManager::primaryScreen() { return m_primaryScreen; } void ScreensManager::onScreenAdded(QScreen *screen) { auto s = new Screen(screen, this); if(screen == qApp->primaryScreen()) { m_primaryScreen = s; Q_EMIT primaryScreenChanged(s); } m_screens.append(s); connect(s->internal(), &QScreen::geometryChanged, this, [&, s](){ checkScreensGeometryStatus(s); }); connect(s, &Screen::enableChanged, this, [&, s](bool enable){ onEnableChanged(s, enable); }); checkScreensGeometryStatus(s); } void ScreensManager::onScreenRemoved(QScreen *screen) { int i = 0; for(; i <= m_screens.size(); ++i) { if(m_screens.at(i)->internal() == screen) { break; } } if(i < m_screens.size()) { auto s = m_screens.takeAt(i); Q_EMIT screenRemoved(s); s->deleteLater(); } } void ScreensManager::onPrimaryScreenChanged(QScreen *screen) { if(m_primaryScreen->internal() != screen) { for(auto s : m_screens) { if(s->internal() == screen) { if(!s->enable()) { s->setEnable(true); } m_primaryScreen = s; Q_EMIT primaryScreenChanged(s); return; } } } } void ScreensManager::onEnableChanged(Screen *screen, bool enable) { if(enable) { Q_EMIT screenAdded(screen); } else { Q_EMIT screenRemoved(screen); } } void ScreensManager::checkScreensGeometryStatus(Screen* screen) { if(screen == nullptr || m_primaryScreen == nullptr) { return; } for(auto s : m_screens) { if(s == nullptr) { continue; } if(s->internal()->geometry() == screen->geometry() && s != screen) { if(s == m_primaryScreen) { screen->setEnable(false); Q_EMIT s->geometryChanged(s->internal()->geometry()); return; } else { s->setEnable(false); Q_EMIT screen->geometryChanged(screen->internal()->geometry()); return; } } else { if(!s->enable()) { s->setEnable(true); } Q_EMIT s->geometryChanged(s->internal()->geometry()); } } } } // UkuiPanel ukui-panel/panel/src/screens-manager.h0000664000175000017500000000411315167645100016667 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_PANEL_SCREENS_MANAGER_H #define UKUI_PANEL_SCREENS_MANAGER_H #include #include namespace UkuiPanel { class ScreensManager; class Screen : public QObject { Q_OBJECT public: explicit Screen(QScreen *screen, QObject *parent = nullptr); Q_DISABLE_COPY(Screen); public: QRect geometry() const; QScreen * internal(); bool enable(); void setEnable(bool enable); bool isValid(); Q_SIGNALS: void geometryChanged(const QRect &geometry); void enableChanged(bool enable); private: QScreen *m_screen = nullptr; bool m_enable = false; }; class ScreensManager : public QObject { Q_OBJECT public: explicit ScreensManager(QObject *parent = nullptr); ~ScreensManager(); QList screens(); Screen * primaryScreen(); Q_SIGNALS: void screenAdded(Screen *); void screenRemoved(Screen *); void primaryScreenChanged(Screen *); private Q_SLOTS: void onScreenAdded(QScreen *screen); void onScreenRemoved(QScreen *screen); void onPrimaryScreenChanged(QScreen *screen); void onEnableChanged(Screen *screen, bool enable); void checkScreensGeometryStatus(Screen *screen); private: Screen *m_primaryScreen = nullptr; QList m_screens; }; } // UkuiPanel #endif //UKUI_PANEL_SCREENS_MANAGER_H ukui-panel/panel/src/panel-gsettings.cpp0000664000175000017500000001107115167645100017255 0ustar fengfeng#include #include #include #include #include #include "panel-gsettings.h" namespace UkuiPanel { static std::once_flag onceFlag; static PanelGSettings* g_instance = nullptr; static GSettings * m_settings = nullptr; static GSettingsSchema * m_schema = nullptr; static const char *m_panelLengthKey = "panellength"; UkuiPanel::PanelGSettings *UkuiPanel::PanelGSettings::instance() { std::call_once(onceFlag, [ & ] { g_instance = new PanelGSettings(); }); return g_instance; } int PanelGSettings::getPanelLength(QString screenName) { if (!m_settings || !m_schema) return -1; if (!isKeysContain(m_panelLengthKey)) return -1; QMap map = getPanelLengthMap(); if (!map.contains(screenName)) { return -1; } return map.value(screenName).toInt(); } void PanelGSettings::setPanelLength(QString screenName, int length) { if (!m_settings || !m_schema) return; if (!isKeysContain(m_panelLengthKey)) return; QMap map = getPanelLengthMap(); map.insert(screenName, QVariant(length)); GVariantBuilder builder; QMapIterator it(map); g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); while (it.hasNext()) { it.next(); GVariant *gvar; QByteArray key = it.key().toUtf8(); if (it.value().canConvert(QVariant::UInt)) { gvar = g_variant_new_uint32(it.value().toUInt()); } g_variant_builder_add (&builder, "{sv}", key.constData(), gvar); } GVariant* result = g_variant_builder_end (&builder); g_settings_set_value(m_settings, m_panelLengthKey, result); } void PanelGSettings::setPanelType(int type) { if (!m_qgSettings || !m_qgSettings->keys().contains(QStringLiteral("paneltype"))) return; m_qgSettings->set(QStringLiteral("paneltype"), QVariant(type)); } void PanelGSettings::setIslandPosition(QString islandId, int islandPosition) { if (!m_qgSettings) return; if ((islandId == "org.ukui.dataIsland") && (m_qgSettings->keys().contains(QStringLiteral("dataislandposition")))) { m_qgSettings->set(QStringLiteral("dataislandposition"), QVariant(islandPosition)); } if ((islandId == "org.ukui.settingsIsland") && (m_qgSettings->keys().contains(QStringLiteral("settingsislandposition")))) { m_qgSettings->set(QStringLiteral("settingsislandposition"), QVariant(islandPosition)); } } void PanelGSettings::setTopBarSize(int size) { if (!m_qgSettings || !m_qgSettings->keys().contains(QStringLiteral("topbarsize"))) return; m_qgSettings->set(QStringLiteral("topbarsize"), QVariant(size)); } UkuiPanel::PanelGSettings::~PanelGSettings() { if (m_settings) { g_object_unref(m_settings); } if (m_schema) { g_settings_schema_unref(m_schema); } g_instance = nullptr; } UkuiPanel::PanelGSettings::PanelGSettings(QObject *parent) : QObject(parent) { GSettingsSchemaSource *source; source = g_settings_schema_source_get_default(); m_schema = g_settings_schema_source_lookup(source, "org.ukui.panel.settings", true); if (!m_schema) { m_settings = nullptr, m_qgSettings = nullptr; return; } m_settings = g_settings_new_with_path("org.ukui.panel.settings", "/org/ukui/panel/settings/"); if (isKeysContain(m_panelLengthKey)) { GVariant *empty_a_sv = g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0); g_settings_set_value(m_settings, m_panelLengthKey, empty_a_sv); } m_qgSettings = new QGSettings("org.ukui.panel.settings", "/org/ukui/panel/settings/", this); } QMap PanelGSettings::getPanelLengthMap() { GVariant *gvalue = g_settings_get_value(m_settings, m_panelLengthKey); GVariantIter iter; QMap map; const gchar *key; size_t str_len; GVariant *val = NULL; g_variant_iter_init (&iter, gvalue); QVariant qvar; while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) { if (g_variant_is_of_type(val, G_VARIANT_TYPE_UINT32)) { qvar = QVariant::fromValue(static_cast(g_variant_get_uint32(val))); map.insert(key, qvar); } } g_variant_unref(gvalue); return map; } bool PanelGSettings::isKeysContain(const char *key) { if (!m_settings || !m_schema) return false; gchar **keys = g_settings_schema_list_keys(m_schema); if (g_strv_contains(keys, key)) { g_strfreev(keys); return true; } else { g_strfreev(keys); return false; } } } // UkuiPanel ukui-panel/panel/src/panel-gsettings.h0000664000175000017500000000131615167645100016723 0ustar fengfeng#ifndef PANELGSETTINGS_H #define PANELGSETTINGS_H #include #include namespace UkuiPanel { class PanelGSettings : public QObject { Q_OBJECT public: static PanelGSettings *instance(); int getPanelLength(QString screenName); void setPanelLength(QString screenName, int length); void setPanelType(int type = 0); void setIslandPosition(QString islandId, int islandPosition); void setTopBarSize(int size); ~PanelGSettings(); private: PanelGSettings(QObject *parent = nullptr); QMap getPanelLengthMap(); bool isKeysContain(const char * key); QGSettings *m_qgSettings = nullptr; }; } // UkuiPanel #endif // PANELGSETTINGS_H ukui-panel/panel/src/message-processor.h0000664000175000017500000000242715167645100017264 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef MESSAGE_PROCESSOR_H #define MESSAGE_PROCESSOR_H #include #include #include class RemoteConfigReplica; class MessageProcessor : public QObject { Q_OBJECT public: explicit MessageProcessor(QObject *parent = nullptr); ~MessageProcessor(); bool preprocessMessage(const QStringList& message); private: static QUrl nodeUrl(); QRemoteObjectNode m_qroNode; RemoteConfigReplica *m_configReplica = nullptr; QCommandLineParser m_parser; }; #endif //MESSAGE_PROCESSOR_H ukui-panel/panel/src/data-collector.cpp0000664000175000017500000001142515167645100017051 0ustar fengfeng/* * Copyright (C) 2025, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "data-collector.h" #include #include class DataCollectWrapper : public QObject { Q_OBJECT public: explicit DataCollectWrapper(QObject *parent = nullptr) : QObject(parent) { } void setPanelPositionEvent(const int &pos) { auto *property = new KCustomProperty; property->key = strdup(QStringLiteral("panelPosition").toLocal8Bit().data()); property->value = strdup(positionToStr(pos).toLocal8Bit().data()); KTrackData *node = kdk_dia_data_init(KEVENTSOURCE_DESKTOP, KEVENT_CLICK); kdk_dia_append_custom_property(node, property, 1); kdk_dia_upload_default(node, strdup(QStringLiteral("adjust_panel_position_event").toLocal8Bit().data()),strdup(QStringLiteral("ukui-panel").toLocal8Bit().data())); kdk_dia_data_free(node); free(property->key); free(property->value); delete property; functiomExecuted(); } void setPanelSizeEvent(const int &panelSize) { KCustomProperty *property = new KCustomProperty; property->key = strdup(QStringLiteral("panelSize").toLocal8Bit().data()); property->value = strdup(QString::number(panelSize).toLocal8Bit().data()); KTrackData *node = kdk_dia_data_init(KEVENTSOURCE_DESKTOP, KEVENT_CLICK); kdk_dia_append_custom_property(node, property, 1); kdk_dia_upload_default(node, strdup(QStringLiteral("adjust_panel_size_event").toLocal8Bit().data()),strdup(QStringLiteral("ukui-panel").toLocal8Bit().data())); kdk_dia_data_free(node); free(property->key); free(property->value); delete property; functiomExecuted(); } static QString positionToStr(const int &pos) { switch (pos) { case 1: return {"Top"}; case 2: return {"Left"}; case 3: return {"Right"}; case 0: return {"Bottom"}; default: ; } return {}; } Q_SIGNALS: void functiomExecuted(); }; class DataCollectorPrivate; static DataCollectorPrivate *g_dataCollectorPrivate = nullptr; static std::once_flag flag; class DataCollectorPrivate : public QThread { Q_OBJECT public: static DataCollectorPrivate *self(); void startRunning(); Q_SIGNALS: void setPanelPositionEvent(const int&pos); void setPanelSizeEvent(const int&panelSize); protected: explicit DataCollectorPrivate(QObject* parent = nullptr); ~DataCollectorPrivate(); void run() override {exec();}; private: QTimer* m_timer = nullptr; DataCollectWrapper *m_wrapper = nullptr; }; DataCollectorPrivate::DataCollectorPrivate(QObject* parent) : QThread() { m_timer = new QTimer(this); m_timer->setSingleShot(true); m_timer->setInterval(1000); m_wrapper = new DataCollectWrapper(); m_wrapper->moveToThread(this); connect(m_timer, &QTimer::timeout, this, &DataCollectorPrivate::quit); connect(this, &DataCollectorPrivate::setPanelSizeEvent, m_wrapper, &DataCollectWrapper::setPanelSizeEvent); connect(this, &DataCollectorPrivate::setPanelPositionEvent, m_wrapper, &DataCollectWrapper::setPanelPositionEvent); } DataCollectorPrivate::~DataCollectorPrivate() { quit(); wait(); if(m_wrapper) { delete m_wrapper; m_wrapper = nullptr; } g_dataCollectorPrivate = nullptr; } DataCollectorPrivate* DataCollectorPrivate::self() { std::call_once(flag, [ & ] { g_dataCollectorPrivate = new DataCollectorPrivate(); }); return g_dataCollectorPrivate; } void DataCollectorPrivate::startRunning() { if (!this->isRunning()) { start(); } m_timer->start(); } void DataCollector::setPanelPositionEvent(const int &pos) { DataCollectorPrivate::self()->startRunning(); DataCollectorPrivate::self()->setPanelPositionEvent(pos); } void DataCollector::setPanelSizeEvent(const int &panelSize) { DataCollectorPrivate::self()->startRunning(); DataCollectorPrivate::self()->setPanelSizeEvent(panelSize); } #include "data-collector.moc" ukui-panel/panel/src/log-utils.h0000664000175000017500000000242215167645100015535 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef LOGUTILS_H #define LOGUTILS_H #include #include class LogUtils { public: static void initLogFile(const QString &fileName); static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); private: static void checkLogFile(); static bool checkFileSize(const QString &fileName); static void clearFile(const QString &fileName); static quint64 m_startUpTime; static QAtomicInt m_logFileId; static QString m_logFileName; }; #endif // LOGUTILS_H ukui-panel/panel/src/remote-config.h0000664000175000017500000001353115167645111016361 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_PANEL_REMOTE_CONFIG_H #define UKUI_PANEL_REMOTE_CONFIG_H #include "rep_remote-config_source.h" #include namespace UkuiQuick { class Config; } class RemoteConfig : public RemoteConfigSource { Q_OBJECT public: explicit RemoteConfig(QObject *parent = nullptr); ~RemoteConfig() override; GeneralConfigDefine::MergeIcons mergeIcons() const override { return m_mergeIcons; } GeneralConfigDefine::PanelLocation panelLocation() const override; GeneralConfigDefine::PanelSizePolicy panelSizePolicy() const override; bool allowCustomSize() const override; bool panelAutoHide() const override; bool panelLock() const override; QStringList panelWidgets() const override { return m_panelWidgets; } QStringList disabledWidgets() const override; QStringList trayIconsInhibited() const override {return m_trayIconsInhibited; } QStringList trayIconsCanInhibited() const override {return m_trayIconsCanInhibited; } GeneralConfigDefine::TaskBarIconsShowedOn taskBarIconsShowedOn() const override { return m_taskBarIconsShowedOn; }; GeneralConfigDefine::PanelType panelType() const override {return m_panelType;} bool showPanelOnAllScreens() const override { return m_showPanelOnAllScreens; } bool showSystemTrayOnAllPanels() const override { return m_showSystemTrayOnAllPanels; } GeneralConfigDefine::PanelLocation panelLocationNext() const override { return m_panelLocationNext; } GeneralConfigDefine::PanelSizePolicy panelSizePolicyNext() const override { return m_panelSizePolicyNext; } bool panelAutoHideNext() const override { return m_panelAutoHideNext; } bool panelLockNext() const override { return m_panelLockNext; } QStringList panelWidgetsNext() const override { return m_panelWidgetsNext; } QStringList disabledWidgetsNext() const override {return m_disabledWidgetsNext; }; void setMergeIcons(GeneralConfigDefine::MergeIcons mergeIcons) override; void setPanelLocation(GeneralConfigDefine::PanelLocation panelLocation) override; void setPanelSizePolicy(GeneralConfigDefine::PanelSizePolicy panelSizePolicy) override; void setPanelAutoHide(bool panelAutoHide) override; void setPanelLock(bool panelLock) override; void setPanelWidgets(QStringList panelWidgets) override; void setTrayIconsInhibited(QStringList trayIconsInhibited) override; void setTaskBarIconsShowedOn(GeneralConfigDefine::TaskBarIconsShowedOn taskBarIconsShowedOn) override; void setPanelType(GeneralConfigDefine::PanelType panelType) override; void setShowPanelOnAllScreens(bool showPanelOnAllScreens) override; void setShowSystemTrayOnAllPanels(bool showSystemTrayOnAllPanels) override; void setPanelLocationNext(GeneralConfigDefine::PanelLocation panelLocation) override; void setPanelSizePolicyNext(GeneralConfigDefine::PanelSizePolicy panelSizePolicy) override; void setPanelAutoHideNext(bool panelAutoHide) override; void setPanelLockNext(bool panelLock) override; void setPanelWidgetsNext(QStringList panelWidgets) override; void updateMainViewConfig(); public Q_SLOTS: void disableWidget(const QString &id, bool disable) override; void disableWidgetNext(const QString &id, bool disable) override; void onFunctionControlChanged(const QString& name, bool exit = false); private: void onPanelConfigChanged(const QString &key); void onPanelViewConfigChanged(const QString &key); void onTaskManagerConfigChanged(const QString &key); void onSystemTrayConfigChanged(const QString &key); void updatePanelLocation(); void onPanelViewConfigNextChanged(const QString &key); void updatePanelLocationNext(); GeneralConfigDefine::MergeIcons m_mergeIcons; GeneralConfigDefine::PanelLocation m_panelLocation; GeneralConfigDefine::PanelSizePolicy m_panelSizePolicy; bool m_allowCustomSize; bool m_panelAutoHide; bool m_panelLock; QStringList m_panelWidgets; QStringList m_disabledWidgets; QStringList m_trayIconsInhibited; QStringList m_trayIconsCanInhibited; GeneralConfigDefine::TaskBarIconsShowedOn m_taskBarIconsShowedOn; GeneralConfigDefine::PanelType m_panelType; bool m_showPanelOnAllScreens; bool m_showSystemTrayOnAllPanels; GeneralConfigDefine::PanelLocation m_panelLocationNext; GeneralConfigDefine::PanelSizePolicy m_panelSizePolicyNext; bool m_panelAutoHideNext; bool m_panelLockNext; QStringList m_panelWidgetsNext; QStringList m_disabledWidgetsNext; UkuiQuick::Config *m_panelConfig = nullptr; UkuiQuick::Config *m_mainViewConfig = nullptr; UkuiQuick::Config *m_mainViewNextConfig = nullptr; UkuiQuick::Config *m_mainViewTopBarConfig = nullptr; UkuiQuick::Config *m_taskManagerConfig = nullptr; UkuiQuick::Config *m_systemTrayConfig = nullptr; //若功能被管控,则接口不可用 bool m_controlPanelLocation = false; bool m_controlPanelSizePolicy = false; bool m_controlPanelAutoHide = false; bool m_controlPanelLock = false; bool m_controlDisableWidget = false; QJsonObject m_controlConfig; }; #endif //UKUI_PANEL_REMOTE_CONFIG_H ukui-panel/panel/src/log-utils.cpp0000664000175000017500000001147315167645111016100 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "log-utils.h" #include #include #include #include #include #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) //T QAtomicInteger::load() const #define LOAD load() #else //T QAtomicInteger::loadRelaxed() const #define LOAD loadRelaxed() #endif #define LOG_FILE_COUNT 2 #define MAX_LOG_FILE_SIZE 4194304 #define MAX_LOG_CHECK_INTERVAL 43200000 quint64 LogUtils::m_startUpTime = 0; QAtomicInt LogUtils::m_logFileId = -1; QString LogUtils::m_logFileName; const static QString LOG_FILE_PATH = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.log/ukui-panel/"; void LogUtils::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { checkLogFile(); QByteArray localMsg = msg.toLocal8Bit(); QByteArray currentDateTime = QDateTime::currentDateTime().toString(Qt::ISODateWithMs).toLocal8Bit(); const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; FILE *log_file = fopen(m_logFileName.arg(m_logFileId.LOAD).toLocal8Bit().constData(), "a+"); switch (type) { case QtDebugMsg: if (!log_file) { break; } fprintf(log_file, "%s:Debug: %s: %s (%s:%u, %s)\n", context.category, currentDateTime.constData(), localMsg.constData(), file, context.line, function); break; case QtInfoMsg: fprintf(log_file? log_file: stdout, "%s:Info: %s: %s (%s:%u, %s)\n", context.category, currentDateTime.constData(), localMsg.constData(), file, context.line, function); break; case QtWarningMsg: fprintf(log_file? log_file: stderr, "%s:Warning: %s: %s (%s:%u, %s)\n", context.category, currentDateTime.constData(), localMsg.constData(), file, context.line, function); break; case QtCriticalMsg: fprintf(log_file? log_file: stderr, "%s:Critical: %s: %s (%s:%u, %s)\n", context.category, currentDateTime.constData(), localMsg.constData(), file, context.line, function); break; case QtFatalMsg: fprintf(log_file? log_file: stderr, "%s:Fatal: %s: %s (%s:%u, %s)\n", context.category, currentDateTime.constData(), localMsg.constData(), file, context.line, function); break; } if (log_file) { fclose(log_file); } } void LogUtils::initLogFile(const QString &fileName) { QDir dir; if (!dir.exists(LOG_FILE_PATH)) { if (!dir.mkpath(LOG_FILE_PATH)) { qWarning() << "Unable to create" << LOG_FILE_PATH; return; } } m_startUpTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); m_logFileName = LOG_FILE_PATH + fileName + "-%0.log"; for (int i = 0; i < LOG_FILE_COUNT; ++i) { auto currentLogFile = m_logFileName.arg(i); if (QFile::exists(currentLogFile)) { if (checkFileSize(currentLogFile)) { m_logFileId = i; break; } } else { QFile file(currentLogFile); file.open(QIODevice::WriteOnly); file.close(); } } if (m_logFileId < 0) { m_logFileId = 0; clearFile(m_logFileName.arg(m_logFileId.loadRelaxed())); } qInfo() << "Current log file:" << m_logFileName.arg(m_logFileId.loadRelaxed()); } void LogUtils::checkLogFile() { quint64 logTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); quint64 spacing = std::max(logTime, m_startUpTime) - std::min(logTime, m_startUpTime); if (spacing <= MAX_LOG_CHECK_INTERVAL && checkFileSize(m_logFileName.arg(m_logFileId.LOAD))) { return; } m_logFileId.fetchAndStoreRelaxed((m_logFileId.LOAD + 1) % LOG_FILE_COUNT); auto currentLogFile = m_logFileName.arg(m_logFileId.LOAD); if (!checkFileSize(currentLogFile)) { clearFile(currentLogFile); } } bool LogUtils::checkFileSize(const QString &fileName) { return QFile(fileName).size() < MAX_LOG_FILE_SIZE; } void LogUtils::clearFile(const QString &fileName) { QFile file(fileName); file.open(QIODevice::WriteOnly); file.write(""); file.flush(); file.close(); } ukui-panel/panel/dbus/0000775000175000017500000000000015167645100013613 5ustar fengfengukui-panel/panel/dbus/org.ukui.panel.xml0000664000175000017500000000110515167645100017173 0ustar fengfeng ukui-panel/panel/translations/0000775000175000017500000000000015167645100015377 5ustar fengfengukui-panel/panel/translations/panel_zh_HK.ts0000664000175000017500000001131515167645100020132 0ustar fengfeng UkuiPanel::Panel Show Desktop 顯示桌面 System Monitor 系統監視器 Auto Hide 自動隱藏 Panel Setting 任務欄設置 Panel Size 頁面大小 Large Medium Small Custom 自訂 Panel Position 任務欄位置 Top 頂部 Bottom 底部 Left Right Lock Panel 鎖定任務欄 Show 顯示 Switch to New Panel UkuiPanel::PanelNext Panel Settings Show Desktop 顯示桌面 System Monitor 系統監視器 Data Island Form Islands Top Bar Settings Island Form Auto Hide 自動隱藏 Lock Panel 鎖定任務欄 Switch to Classical Panel Panel Size 頁面大小 Large Medium Small Custom 自訂 UkuiPanel::PanelTopBar Panel Settings Show Desktop 顯示桌面 System Monitor 系統監視器 Data Island Form Islands Top Bar Settings Island Form Switch to Classical Panel ukui-panel/panel/translations/panel_zh_CN.ts0000664000175000017500000001132015167645100020124 0ustar fengfeng UkuiPanel::Panel Top Bottom Left Right Large 大尺寸 Medium 中尺寸 Small 小尺寸 Custom 自定义 Panel Position 任务栏位置 Panel Size 任务栏尺寸 Lock Panel 锁定任务栏 Auto Hide 自动隐藏任务栏 System Monitor 系统监视器 Show Desktop 显示桌面 Panel Setting 任务栏设置 Show 显示 Switch to New Panel 切换三岛任务栏 UkuiPanel::PanelNext Panel Settings 任务栏设置 Show Desktop 显示桌面 System Monitor 系统监视器 Data Island Form 数据岛形式 Islands 三岛 Top Bar 顶栏 Settings Island Form 配置岛形式 Auto Hide 自动隐藏任务栏 Lock Panel 锁定任务栏 Switch to Classical Panel 切换经典任务栏 Panel Size 任务栏尺寸 Large 大尺寸 Medium 中尺寸 Small 小尺寸 Custom 自定义 UkuiPanel::PanelTopBar Panel Settings 任务栏设置 Show Desktop 显示桌面 System Monitor 系统监视器 Data Island Form 数据岛形式 Islands 三岛 Top Bar 顶栏 Settings Island Form 配置岛形式 Switch to Classical Panel 切换经典任务栏 ukui-panel/panel/translations/panel_es.ts0000664000175000017500000001147015167645100017540 0ustar fengfeng UkuiPanel::Panel Show Desktop Mostrar escritorio System Monitor Auto Hide Panel Setting Panel Size Large Grande Medium Medio Small Pequeño Custom Costumbre Panel Position Top Arriba Bottom Fondo Left Izquierda Right Derecha Lock Panel Show Switch to New Panel UkuiPanel::PanelNext Panel Settings Show Desktop Mostrar escritorio System Monitor Data Island Form Islands Top Bar Settings Island Form Auto Hide Lock Panel Switch to Classical Panel Panel Size Large Grande Medium Medio Small Pequeño Custom Costumbre UkuiPanel::PanelTopBar Panel Settings Show Desktop Mostrar escritorio System Monitor Data Island Form Islands Top Bar Settings Island Form Switch to Classical Panel ukui-panel/panel/translations/panel_kk.ts0000664000175000017500000001253115167645100017535 0ustar fengfeng UkuiPanel::Panel Show Desktop ۇستەل بەتىن كورسەتۋ System Monitor سەستيما كۇزەتۋشى Auto Hide اۆتوماتتى جاسىرۋ Panel Setting تاقتاي تەڭشەۋ Panel Size مىندەتتى ستوننىڭ ۇلكەن-كشىلگى Large ۇلكەن Medium ورتاشا Small كشكەنە Custom ٶزى بەلگٸلەۋ Panel Position تاقتا ورنى Top جابىسقاق Bottom استڭقٸ Left سول Right وڭ جاق Lock Panel مىندەتتى ستونى قۇلپىلاۋ Show كورسەتۋ Switch to New Panel جاڭا تاقتاعا سايكەستىرۋ UkuiPanel::PanelNext Panel Settings تاقتاي تەڭشەۋلەرى Show Desktop ۇستەل بەتىن كورسەتۋ System Monitor سەستيما كۇزەتۋشى Data Island Form ساندىق مالىمەت ارال پىشىنى Islands ارالدار Top Bar ٷستٸن بالداق Settings Island Form ارال كەستەنٸ تەڭشەۋ Auto Hide اۆتوماتتى جاسىرۋ Lock Panel مىندەتتى ستونى قۇلپىلاۋ Switch to Classical Panel كلاسسيك تاقتاعا سايكەستىرۋ Panel Size مىندەتتى ستوننىڭ ۇلكەن-كشىلگى Large ۇلكەن Medium ورتاشا Small كشكەنە Custom ٶزى بەلگٸلەۋ UkuiPanel::PanelTopBar Panel Settings تاقتاي تەڭشەۋلەرى Show Desktop ۇستەل بەتىن كورسەتۋ System Monitor سەستيما كۇزەتۋشى Data Island Form ساندىق مالىمەت ارال پىشىنى Islands ارالدار Top Bar ٷستٸن بالداق Settings Island Form ارال كەستەنٸ تەڭشەۋ Switch to Classical Panel كلاسسيك تاقتاعا سايكەستىرۋ ukui-panel/panel/translations/panel_ky.ts0000664000175000017500000001271315167645100017555 0ustar fengfeng UkuiPanel::Panel Show Desktop شىرە بەتىن كۅرسۅتۉۉ System Monitor ساامالىق كۉزۅتكۉچ Auto Hide اپتوماتتىك جاشىرۇۇ Panel Setting باشقارمالىقتار تەڭشۅۅ Panel Size مىلدەت قۇرۇنۇن چوڭ-كىچىكتىگى Large چوڭ Medium ورتوسۇ Small كىچىك Custom ۅزۉ بەكىتۉۉ Panel Position تاقتا وردۇ Top ۉستۉ Bottom الدى Left سولعو Right وڭ تاراپ Lock Panel مىلدەت ىستونۇن قۇلۇپتوو Show كۅرسۅتۉۉ Switch to New Panel جاڭى تاقتادا الماشتىرۇۇ UkuiPanel::PanelNext Panel Settings باشقارمالىقتار تەڭشەكتەرى Show Desktop شىرە بەتىن كۅرسۅتۉۉ System Monitor ساامالىق كۉزۅتكۉچ Data Island Form ساندۇۇ بايانداما ارال كەبەتەسى ، تۇرپاتى Islands ارالدار Top Bar ۉستۉ بالداق Settings Island Form ارال جادىبالىن تەڭشۅۅ Auto Hide اپتوماتتىك جاشىرۇۇ Lock Panel مىلدەت ىستونۇن قۇلۇپتوو Switch to Classical Panel كىلاسىك تاقتادا الماشتىرۇۇ Panel Size مىلدەت قۇرۇنۇن چوڭ-كىچىكتىگى Large چوڭ Medium ورتوسۇ Small كىچىك Custom ۅزۉ بەكىتۉۉ UkuiPanel::PanelTopBar Panel Settings باشقارمالىقتار تەڭشەكتەرى Show Desktop شىرە بەتىن كۅرسۅتۉۉ System Monitor ساامالىق كۉزۅتكۉچ Data Island Form ساندۇۇ بايانداما ارال كەبەتەسى ، تۇرپاتى Islands ارالدار Top Bar ۉستۉ بالداق Settings Island Form ارال جادىبالىن تەڭشۅۅ Switch to Classical Panel كىلاسىك تاقتادا الماشتىرۇۇ ukui-panel/panel/translations/panel_mn.ts0000664000175000017500000001532315167645100017544 0ustar fengfeng UkuiPanel::Panel Top ᠳᠡᠭᠡᠷ᠎ᠡ Bottom ᠳᠣᠣᠷ᠎ᠠ Left ᠵᠡᠬᠦᠨ Right ᠪᠠᠷᠠᠭᠤᠨ Large ᠲᠣᠮᠣ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Medium ᠳᠤᠮᠳᠠ Small ᠪᠠᠭ᠎ᠠ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Custom ᠦᠪᠡᠷᠳᠡᠬᠡᠨ ᠳᠤᠭᠳᠠᠭᠠᠬᠤ Panel Position ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠤ᠋ᠨ ᠪᠠᠢᠷᠢ Panel Size ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠤ᠋ᠨ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Lock Panel ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠣᠨᠢᠰᠤᠯᠠᠬᠤ Auto Hide ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠠᠦ᠋ᠲ᠋ᠦ᠌ ᠨᠢᠭᠤᠬᠤ System Monitor ᠰᠢᠰᠲ᠋ᠧᠮ᠎ᠦ᠋ᠨ ᠬᠢᠨᠠᠭᠤᠷ Show Desktop ᠱᠢᠷᠡᠭᠡᠨ ᠨᠢᠭᠤᠷ ᠎ᠢ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ᠌ Panel Setting ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠤ᠋ᠨ ᠲᠤᠬᠢᠷᠠᠭᠤᠯᠤᠭ᠎ᠠ Show ᠢᠯᠡᠷᠡᠬᠦ Switch to New Panel ᠭᠤᠷᠪᠠᠨ ᠠᠷᠠᠯ᠎ᠤ᠋ᠨ ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠰᠣᠯᠢᠬᠤ UkuiPanel::PanelNext Panel Settings ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠤ᠋ᠨ ᠲᠤᠬᠢᠷᠠᠭᠤᠯᠤᠭ᠎ᠠ Show Desktop ᠱᠢᠷᠡᠭᠡᠨ ᠨᠢᠭᠤᠷ ᠎ᠢ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ᠌ System Monitor ᠰᠢᠰᠲ᠋ᠧᠮ᠎ᠦ᠋ᠨ ᠬᠢᠨᠠᠭᠤᠷ Data Island Form ᠳ᠋ᠠᠢᠲ᠋ᠠ᠎ᠶ᠋ᠢᠨ ᠠᠷᠠᠯ᠎ᠤ᠋ᠨ ᠬᠡᠯᠪᠡᠷᠢ Islands ᠭᠤᠷᠪᠠᠨ ᠠᠷᠠᠯ Top Bar ᠣᠷᠣᠢ᠎ᠶ᠋ᠢᠨ ᠬᠡᠰᠡᠭ Settings Island Form ᠠᠷᠠᠯ᠎ᠤ᠋ᠨ ᠬᠡᠯᠪᠡᠷᠢ᠎ᠶ᠋ᠢ ᠲᠣᠬᠢᠷᠠᠭᠤᠯᠬᠤ Auto Hide ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠠᠦ᠋ᠲ᠋ᠦ᠌ ᠨᠢᠭᠤᠬᠤ Lock Panel ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠣᠨᠢᠰᠤᠯᠠᠬᠤ Switch to Classical Panel ᠰᠣᠩᠭᠣᠳᠠᠭ ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠰᠣᠯᠢᠬᠤ Panel Size ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠤ᠋ᠨ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Large ᠲᠣᠮᠣ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Medium ᠳᠤᠮᠳᠠ Small ᠪᠠᠭ᠎ᠠ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Custom ᠦᠪᠡᠷᠳᠡᠬᠡᠨ ᠳᠤᠭᠳᠠᠭᠠᠬᠤ UkuiPanel::PanelTopBar Panel Settings ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠤ᠋ᠨ ᠲᠤᠬᠢᠷᠠᠭᠤᠯᠤᠭ᠎ᠠ Show Desktop ᠱᠢᠷᠡᠭᠡᠨ ᠨᠢᠭᠤᠷ ᠎ᠢ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ᠌ System Monitor ᠰᠢᠰᠲ᠋ᠧᠮ᠎ᠦ᠋ᠨ ᠬᠢᠨᠠᠭᠤᠷ Data Island Form ᠳ᠋ᠠᠢᠲ᠋ᠠ᠎ᠶ᠋ᠢᠨ ᠠᠷᠠᠯ᠎ᠤ᠋ᠨ ᠬᠡᠯᠪᠡᠷᠢ Islands ᠭᠤᠷᠪᠠᠨ ᠠᠷᠠᠯ Top Bar ᠣᠷᠣᠢ᠎ᠶ᠋ᠢᠨ ᠬᠡᠰᠡᠭ Settings Island Form ᠠᠷᠠᠯ᠎ᠤ᠋ᠨ ᠬᠡᠯᠪᠡᠷᠢ᠎ᠶ᠋ᠢ ᠲᠣᠬᠢᠷᠠᠭᠤᠯᠬᠤ Switch to Classical Panel ᠰᠣᠩᠭᠣᠳᠠᠭ ᠡᠭᠦᠷᠭᠡ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠷ᠎ᠢ᠋ ᠰᠣᠯᠢᠬᠤ ukui-panel/panel/translations/panel_ug.ts0000664000175000017500000001265715167645100017554 0ustar fengfeng UkuiPanel::Panel Show Desktop ئۈستەل يۈزىنى كۆرسىتىش System Monitor سىستېما كۆزەتكۈچ Auto Hide ئاپتوماتىك يوشۇرۇش Panel Setting تاختاي تەڭشەش Panel Size ۋەزىپە ئىستونىنىڭ چوڭ-كىچىكلىكى Large چوڭ Medium ئوتتۇراھال Small كىچىك Custom ئۆزى بەلگىلەش Panel Position تاختا ئورنى Top چوققىلاش Bottom ئاستىنقى Left سول Right ئوڭ تەرەپ Lock Panel ۋەزىپە ئىستونىنى قۇلۇپلاش Show كۆرسىتىش Switch to New Panel يېڭى تاختىغا ئالماشتۇرۇش UkuiPanel::PanelNext Panel Settings تاختاي تەڭشەكلىرى Show Desktop ئۈستەل يۈزىنى كۆرسىتىش System Monitor سىستېما كۆزەتكۈچ Data Island Form سانلىق مەلۇمات ئارال شەكلى Islands ئاراللار Top Bar ئۈستى بالداق Settings Island Form ئارال جەدۋىلىنى تەڭشەش Auto Hide ئاپتوماتىك يوشۇرۇش Lock Panel ۋەزىپە ئىستونىنى قۇلۇپلاش Switch to Classical Panel كلاسسىك تاختىغا ئالماشتۇرۇش Panel Size ۋەزىپە ئىستونىنىڭ چوڭ-كىچىكلىكى Large چوڭ Medium ئوتتۇراھال Small كىچىك Custom ئۆزى بەلگىلەش UkuiPanel::PanelTopBar Panel Settings تاختاي تەڭشەكلىرى Show Desktop ئۈستەل يۈزىنى كۆرسىتىش System Monitor سىستېما كۆزەتكۈچ Data Island Form سانلىق مەلۇمات ئارال شەكلى Islands ئاراللار Top Bar ئۈستى بالداق Settings Island Form ئارال جەدۋىلىنى تەڭشەش Switch to Classical Panel كلاسسىك تاختىغا ئالماشتۇرۇش ukui-panel/panel/translations/panel_bo_CN.ts0000664000175000017500000001455115167645100020114 0ustar fengfeng UkuiPanel::Panel Show Desktop ཅོག་ཙེའི་ངོས་སུ་མངོན System Monitor རྒྱུད་ཁོངས་སོ་ལྟ་ཆས། Auto Hide འགན་སྡེ་རང་སྦས། Panel Setting འགན་སྡེ་སྒྲིག་འགོད། Panel Size ལས་འགན་སྒྲུབ་སའི་ཆེ་ཆུང་ལེགས་སྒྲིག་བྱེད་པ། Large ཆེ་བ། Medium འབྲིང་རིམ་ཡིན། Small ཆུང་བ། Custom མཚན་ཉིད་རང་འཇོག། Panel Position འགན་སྡེའི་གནས། Top རྩེ་མོ། Bottom ཞབས་ཁུལ། Left གཡོན་ཕྱོགས། Right གཡས་གཡོན། Lock Panel ལས་འགན་གྱི་རེའུ་མིག་གཏན་འཁེལ་བྱས། Show གསལ་པོར་མངོན་པ། Switch to New Panel འགན་སྡེ་གསར་པར་བརྗེ་བ། UkuiPanel::PanelNext Panel Settings འགན་སྡེ་སྒྲིག་འགོད། Show Desktop ཅོག་ཙེའི་ངོས་སུ་མངོན System Monitor རྒྱུད་ཁོངས་སོ་ལྟ་ཆས། Data Island Form གཞི་གྲངས་གླིང་ཕྲན་གྱི་རྣམ་པ། Islands གླིང་གསུམ། Top Bar ཀླད་སྡེ། Settings Island Form སྡེབ་སྒྲིག་གླིང་ཕྲན་གྱི་རྣམ་པ། Auto Hide འགན་སྡེ་རང་སྦས། Lock Panel ལས་འགན་གྱི་རེའུ་མིག་གཏན་འཁེལ་བྱས། Switch to Classical Panel ཚད་ལྡན་འགན་སྡེར་བརྗེ་བ། Panel Size ལས་འགན་སྒྲུབ་སའི་ཆེ་ཆུང་ལེགས་སྒྲིག་བྱེད་པ། Large ཆེ་བ། Medium འབྲིང་རིམ་ཡིན། Small ཆུང་བ། Custom མཚན་ཉིད་རང་འཇོག། UkuiPanel::PanelTopBar Panel Settings འགན་སྡེ་སྒྲིག་འགོད། Show Desktop ཅོག་ཙེའི་ངོས་སུ་མངོན System Monitor རྒྱུད་ཁོངས་སོ་ལྟ་ཆས། Data Island Form གཞི་གྲངས་གླིང་ཕྲན་གྱི་རྣམ་པ། Islands གླིང་གསུམ། Top Bar ཀླད་སྡེ། Settings Island Form སྡེབ་སྒྲིག་གླིང་ཕྲན་གྱི་རྣམ་པ། Switch to Classical Panel ཚད་ལྡན་འགན་སྡེར་བརྗེ་བ། ukui-panel/panel/translations/panel_ru.ts0000664000175000017500000001165715167645100017566 0ustar fengfeng UkuiPanel::Panel Top test Bottom Left Right Large Medium Small Custom Panel Position Panel Size Lock Panel Auto Hide System Monitor Show Desktop Panel Setting Show Switch to New Panel UkuiPanel::PanelNext Panel Settings Show Desktop System Monitor Auto Hide Lock Panel Switch to Classical Panel Panel Size Large Medium Small Custom Data Island Form Islands Top Bar Settings Island Form UkuiPanel::PanelTopBar Panel Settings Show Desktop System Monitor Switch to Classical Panel Data Island Form Islands Top Bar Settings Island Form ukui-panel/panel/translations/panel_fr.ts0000664000175000017500000001150515167645100017537 0ustar fengfeng UkuiPanel::Panel Show Desktop Afficher le bureau System Monitor Auto Hide Panel Setting Panel Size Large Grand Medium Douleur moyenne Small Petit Custom Coutume Panel Position Top Retour au début Bottom Fond Left Gauche Right Droite Lock Panel Show Switch to New Panel UkuiPanel::PanelNext Panel Settings Show Desktop Afficher le bureau System Monitor Data Island Form Islands Top Bar Settings Island Form Auto Hide Lock Panel Switch to Classical Panel Panel Size Large Grand Medium Douleur moyenne Small Petit Custom Coutume UkuiPanel::PanelTopBar Panel Settings Show Desktop Afficher le bureau System Monitor Data Island Form Islands Top Bar Settings Island Form Switch to Classical Panel ukui-panel/panel/translations/panel_de.ts0000664000175000017500000001144415167645100017522 0ustar fengfeng UkuiPanel::Panel Show Desktop Desktop anzeigen System Monitor Auto Hide Panel Setting Panel Size Panel-Größe Large Groß Medium Mittel Small Klein Custom Gewohnheit Panel Position Top Nach oben Bottom Unteres Left Links Right Rechts Lock Panel Bedienfeld sperren Show Switch to New Panel UkuiPanel::PanelNext Panel Settings Show Desktop Desktop anzeigen System Monitor Data Island Form Islands Top Bar Settings Island Form Auto Hide Lock Panel Bedienfeld sperren Switch to Classical Panel Panel Size Panel-Größe Large Groß Medium Mittel Small Klein Custom Gewohnheit UkuiPanel::PanelTopBar Panel Settings Show Desktop Desktop anzeigen System Monitor Data Island Form Islands Top Bar Settings Island Form Switch to Classical Panel ukui-panel/panel/ukcc-plugin/0000775000175000017500000000000015167645111015101 5ustar fengfengukui-panel/panel/ukcc-plugin/panel-ukcc-plugin.h0000664000175000017500000001554215167645111020577 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_PANEL_PANEL_UKCC_PLUGIN_H #define UKUI_PANEL_PANEL_UKCC_PLUGIN_H #include #include #include #include #include #include #include #include #include #include #include #include #include "rep_remote-config_replica.h" class PanelUkccPlugin : public QObject, public CommonInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.ukcc.CommonInterface") Q_INTERFACES(CommonInterface) public: explicit PanelUkccPlugin(QObject *parent = nullptr); ~PanelUkccPlugin(); QString plugini18nName() Q_DECL_OVERRIDE; int pluginTypes() Q_DECL_OVERRIDE; QWidget * pluginUi() Q_DECL_OVERRIDE; const QString name() const Q_DECL_OVERRIDE; QString translationPath() const Q_DECL_OVERRIDE; bool isShowOnHomePage() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; bool isEnable() const Q_DECL_OVERRIDE; //Virtual Keyboard enum VirtualKeyboardPolicy { NeverShow = 0, AlwaysSHow, ShowWhenKeyboardIsConnected }; struct TrayIconInfo { QString id; QString name; QString iconName; TrayIconInfo(const QString& id_, const QString& name_, const QString& iconName_) : id(id_), name(name_), iconName(iconName_) {} }; public Q_SLOTS: void onFunctionControlChanged(const QString& name, bool exit = false); void onTrayIconsCanInhibitedChanged(const QStringList &list); private: void initUI(); QFrame * setLine(QFrame *parent = nullptr); void connectToSource(); void initData(); void sourceStateChanged(QRemoteObjectReplica::State state, QRemoteObjectReplica::State oldState); void updateData(); int virtualKeyboardCurrentIndex(); void initFunctionControl(); QPair compareStringLists(const QStringList& oldList, const QStringList& newList); int getTrayIconIndex(TrayIconInfo info); void removeSystemTrayIcon(const QString &id); QRemoteObjectNode m_qroNode; RemoteConfigReplica *m_configReplica = nullptr; //main page QWidget *m_widget = nullptr; //"panel" QVBoxLayout *m_mainLayout = nullptr; kdk::KLabel *m_titleLabel1 = nullptr; QFrame *m_frame1 = nullptr; QVBoxLayout *m_vLayout1 = nullptr; //panelmode QFrame *m_panelTypeFrame = nullptr; QHBoxLayout *m_panelTypeLayout = nullptr; QLabel *m_panelTypeLabel = nullptr; QButtonGroup *m_panelTypeGroup = nullptr; QPushButton *m_classicType = nullptr; QPushButton *m_threeIslandType = nullptr; QLabel* m_classicTypeLabel = nullptr; QLabel* m_threeIslandTypeLabel = nullptr; QHBoxLayout *m_panelTypeButtonLayout = nullptr; QVBoxLayout *m_classicTypeLayout = nullptr; QVBoxLayout *m_threeIslandTypeLayout = nullptr; //merge icons QFrame *m_mergeIconsFrame = nullptr; QHBoxLayout *m_mergeIconsLayout = nullptr; QLabel *m_mergeIconsLabel = nullptr; QComboBox *m_mergeIcons = nullptr; //panel location QFrame *m_panelLocationFrame = nullptr; QHBoxLayout *m_panelLocationLayout = nullptr; QLabel *m_panelLocationLabel = nullptr; QComboBox *m_panelLocation= nullptr; //panel size QFrame *m_panelSizePolicyFrame = nullptr; QHBoxLayout *m_panelSizePolicyLayout = nullptr; QLabel *m_panelSizePolicyLabel = nullptr; QComboBox *m_panelSizePolicy = nullptr; //panel auto hide QFrame *m_panelAutoHideFrame = nullptr; QHBoxLayout *m_panelAutoHideLayout = nullptr; QLabel *m_panelAutoHideLabel = nullptr; kdk::KSwitchButton *m_panelAutoHide = nullptr; //panel lock QFrame *m_panelLockFrame = nullptr; QHBoxLayout *m_panelLockLayout = nullptr; QLabel *m_panelLockLabel = nullptr; kdk::KSwitchButton *m_panelLock = nullptr; //show panel on all screens QFrame *m_showPanelOnAllScreensFrame = nullptr; QHBoxLayout *m_showPanelOnAllScreensLayout = nullptr; QLabel *m_showPanelOnAllScreensLabel = nullptr; kdk::KSwitchButton *m_showPanelOnAllScreens = nullptr; //show system tray on all panel QFrame *m_showSystemTrayOnAllPanelsFrame = nullptr; QHBoxLayout *m_showSystemTrayOnAllPanelsLayout = nullptr; QLabel *m_showSystemTrayOnAllPanelsLabel = nullptr; kdk::KSwitchButton *m_showSystemTrayOnAllPanels = nullptr; //icons showed on witch panel QFrame *m_iconsShowedOnFrame = nullptr; QHBoxLayout *m_iconsShowedOnLayout = nullptr; QLabel *m_iconsShowedOnLabel = nullptr; QComboBox *m_iconsShowedOn = nullptr; //"widgets showed on panel" kdk::KLabel *m_titleLabel2{}; QFrame *m_frame2{}; QVBoxLayout *m_vLayout2{}; //task view QFrame *m_showTaskViewFrame = nullptr; QHBoxLayout *m_showTaskViewLayout = nullptr; QLabel *m_showTaskViewIconLabel = nullptr; QLabel *m_showTaskViewLabel = nullptr; kdk::KSwitchButton *m_showTaskView = nullptr; //show search QFrame *m_showSearchFrame = nullptr; QHBoxLayout *m_showSearchLayout = nullptr; QLabel *m_showSearchIconLabel = nullptr; QLabel *m_showSearchLabel = nullptr; kdk::KSwitchButton *m_showSearch = nullptr; //"widgets showed on panel" kdk::KLabel *m_titleLabel3{}; QFrame *m_frame3{}; QVBoxLayout *m_vLayout3{}; QStringList m_systemTrayIconId = { "ukui-bluetooth", "Fcitx" }; QList m_systemTrayIconInfo; UkuiQuick::Config *m_systemTrayConfig = nullptr; //Virtual Keyboard QFrame *m_virtualKeyboardFrame = nullptr; QHBoxLayout *m_virtualKeyboardLayout = nullptr; QLabel *m_virtualKeyboardIconLabel = nullptr; QLabel *m_virtualKeyboardLabel = nullptr; QComboBox *m_virtualKeyboardPolicy = nullptr; QGSettings *m_gsetting = nullptr; GeneralConfigDefine::PanelType m_panelType = GeneralConfigDefine::PanelType::Version4; //管控配置 QJsonObject m_controlConfig; bool m_initialized = false; }; #endif //UKUI_PANEL_PANEL_UKCC_PLUGIN_H ukui-panel/panel/ukcc-plugin/translations/0000775000175000017500000000000015167645111017622 5ustar fengfengukui-panel/panel/ukcc-plugin/translations/ky.ts0000664000175000017500000001503315167645100020615 0ustar fengfeng PanelUkccPlugin Panel مىلدەت ىستونۇ /Panel/Panel Merge icons on the taskbar مىلدەت ىستونۇنداعى شارتتۇۇ بەلگىلەردى بىرلەشتىرىپ /Panel/Merge icons on the taskbar Always باشتان ارقاسى Never مۇرداتان Panel location مىلدەت كەتەكچەسى ەكرانداعى وردۇ /Panel/Panel location Bottom الدى Left سولعو Top ۉستۉ Right وڭ تاراپ Panel size باشقارمالىقتار چوڭدۇعۇ /Panel/Panel size Small كىچىك Medium ورتوسۇ Large چوڭ Custom ۅزۉ بەكىتۉۉ Panel auto hide اپتوماتتىك جاشىرىن مىلدەت كەتەكچەسى /Panel/Panel auto hide Panel lock قۇلۇپتوو مىلدەت كەتەكچەسى /Panel/Panel lock Widgets always showed on panel باشتان-ارقاسى كۅرسۅتۉۉ مىلدەت كەتەكچەسى ۉستۉندۆكۉ شارتتۇۇ بەلگى /Panel/Widgets always showed on panel Task view كۅپ مئسسىياسى كۅرۉنۉش Volume كۅلۅمۉ Network تور Power بىيلىك Bluetooth بليۇتۇز Icons showed on system tray پودنوس كۅرسۅتۉۉ ساامالىعى شارتتۇۇ بەلگى /Panel/Icons showed on system tray Panel Appearance باشقارمالىقتار سىرتقى گۅرۉنۉشۉ classic كىلاسىك threeIsland ۉچ ارال Show panel on all screens باردىق ەكرانداردا تاقتانى كۅرسۅتۉۉ /Panel/Show panel on all screens Show system tray area on all panels باردىق تىلكەلەردە ساامالىق قوڭۇز رايونۇن كۅرسۅتۉۉ When existing multiple panels, show window icons on كۅپ باشقارمالىقتار باربولۇۇسۇ بولعوندو ، كۅزۅنۅك زناچوقتور اچىڭ All panels باردىق باشقارمالىقتار Primary screen panel and panel where window is open كۅزۅنۅك ئېچىلغاندىكى نەگىزگى ەكىران تاقتاسى جانا تاقتا Panel where window is open كۅزۅنۅك اچىلعان باشقارمالىقتار Search ىزدۅۅ VPN Fcitx Virtual Keyboard جورۇما كۇنۇپكا تاقتاسى Never Show ۉزگۉلتۉكسۉز كۅرسۅتۉۉ Always Show تۉبۅلۉك كۅرسۅتۉۉ Show When Keyboard Is Connected كۇنۇپكا تاقتاسى جالعانعان ۇچۇردا كۅرسۅتۉۉ SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/zh_CN.ts0000664000175000017500000001315015167645111021173 0ustar fengfeng PanelUkccPlugin Panel 任务栏 /Panel/Panel Merge icons on the taskbar 合并任务栏上的图标 /Panel/Merge icons on the taskbar Always 始终 Never 从不 Panel location 任务栏在屏幕上的位置 /Panel/Panel location Bottom 底部 Left 左侧 Top 顶部 Right 右侧 Panel size 任务栏大小 /Panel/Panel size Small Medium Large Custom 自定义 Panel auto hide 自动隐藏任务栏 /Panel/Panel auto hide Panel lock 锁定任务栏 /Panel/Panel lock Widgets always showed on panel 始终显示在任务栏上的图标 /Panel/Widgets always showed on panel Task view 多任务视图 Volume 声音 Network 网络 Power 电源 Bluetooth 蓝牙 Icons showed on system tray 显示在托盘的系统图标 /Panel/Icons showed on system tray Search 搜索 When existing multiple panels, show window icons on 多个任务栏时,任务栏上的图标显示在 All panels 所有任务栏 Primary screen panel and panel where window is open 主屏任务栏和打开了窗口的任务栏 Panel where window is open 仅显示在打开了窗口的任务栏 Panel Appearance 任务栏外观 classic 经典 threeIsland 三岛 Show panel on all screens 在所有显示器上显示任务栏 /Panel/Show panel on all screens Show system tray area on all panels 在所有任务栏上显示托盘操作区域 Virtual Keyboard 麒麟虚拟键盘 VPN VPN工具 Fcitx 输入法 Never Show 从不显示 Always Show 始终显示 Show When Keyboard Is Connected 未连接键盘时显示 SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/kk.ts0000664000175000017500000001460215167645100020600 0ustar fengfeng PanelUkccPlugin Panel مىندەتتى ستونى /Panel/Panel Merge icons on the taskbar مىندەتتى ستونداعى گرافيىكتەردى بٸرلەستٸرۋ /Panel/Merge icons on the taskbar Always باستان اقىرٸ Never بۇرٸننان Panel location مىندەتتى شارباق ەكٸرانداعٸ ورنى /Panel/Panel location Bottom استڭقٸ Left سول Top جابىسقاق Right وڭ جاق Panel size تاقتاي ۇلكەندىگى /Panel/Panel size Small كشكەنە Medium ورتاشا Large ۇلكەن Custom ٶزى بەلگٸلەۋ Panel auto hide اۆتوماتتى جاسىرىن مىندەتتى شارباق /Panel/Panel auto hide Panel lock قۇلپىلاۋ مىندەتتى شارباق /Panel/Panel lock Widgets always showed on panel باستان-اقىرٸ كورسەتۋ مىندەتتى شارباق ٷستٸندەگٸ اي كۇن /Panel/Widgets always showed on panel Task view كوپ مىندەتتەرىن كورىنۋ Volume كولەمى Network تور Power قۋات Bluetooth بليۇتووت Icons showed on system tray پاتىنوس كورسەتۋ سەستيماسى اي كۇن /Panel/Icons showed on system tray Panel Appearance تاقتاي سىرتقى كورىنۋى classic كلاسسيك threeIsland ٶش ارال Show panel on all screens بارلٸق ەكرانداردا تاقتانٸ كورسەتۋ /Panel/Show panel on all screens Show system tray area on all panels بارلٸق باعانداردا سەستيما قوڭىز رايوننى كورسەتۋ When existing multiple panels, show window icons on كوپ تاقتاي ساقتالعان بولعاندا، كوز بەك سۋرەتتى بەلگىلەرىن ٴٸشڭٸز All panels بارلٸق تاقتالار Primary screen panel and panel where window is open كوز بەك ئېچىلغاندىكى نەگٸزگٸ ەكٸران تاقتاسى ۋا تاقتا Panel where window is open كوز بەك اشىلعان تاقتاي Search ٸزدەۋ VPN Fcitx Virtual Keyboard جاساندى كىنوپكا تاقتاسى Never Show باستان اقٸر كورسەتۋ Always Show ماڭگى كورسەتۋ Show When Keyboard Is Connected كىنوپكا تاقتاسى جالعانعان كەزدە كورسەتۋ SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/ug.ts0000664000175000017500000001472015167645100020607 0ustar fengfeng PanelUkccPlugin Panel ۋەزىپە ئىستونى /Panel/Panel Merge icons on the taskbar ۋەزىپە ئىستونىدىكى سىنبەلگىلەرنى بىرلەشتۈرۈش /Panel/Merge icons on the taskbar Always باشتىن ئاخىر Never ئەزەلدىن Panel location ۋەزىپە ستونى ئېكراندىكى ئورنى /Panel/Panel location Bottom ئاستىنقى Left سول Top چوققىلاش Right ئوڭ تەرەپ Panel size تاختاي چوڭلۇقى /Panel/Panel size Small كىچىك Medium ئوتتۇراھال Large چوڭ Custom ئۆزى بەلگىلەش Panel auto hide ئاپتوماتىك يوشۇرۇن ۋەزىپە ستونى /Panel/Panel auto hide Panel lock قۇلۇپلاش ۋەزىپە ستونى /Panel/Panel lock Widgets always showed on panel باشتىن-ئاخىر كۆرسىتىش ۋەزىپە ستونى ئۈستىدىكى سىنبەلگە /Panel/Widgets always showed on panel Task view كۆپ ۋەزىپىلىك كۆرۈنۈش Volume يۆگەم Network تور Power توك مەنبەسىنى باشقۇرۇش Bluetooth كۆكچىش Icons showed on system tray پەتنۇس كۆرسىتىش سىستېمىسى سىنبەلگە /Panel/Icons showed on system tray Panel Appearance تاختاي سىرتقى كۆرۈنۈشى classic كىلاسسىك threeIsland ئۈچ ئارال Show panel on all screens بارلىق ئېكرانلاردا تاختىنى كۆرسىتىش /Panel/Show panel on all screens Show system tray area on all panels بارلىق تاخمىلاردىكى سىستېما قوندىقىنىڭ رايونىنى كۆرسىتىش When existing multiple panels, show window icons on كۆپ تاختاي مەۋجۇت بولغاندا، كۆزنەك سىنبەلگىلىرىنى ئېچىڭ All panels بارلىق تاختىلار Primary screen panel and panel where window is open كۆزنەك ئېچىلغاندىكى ئاساسىي ئېكران تاختىسى ۋە تاختا Panel where window is open كۆزنەك ئېچىلغان تاختاي Search ئىزدەش VPN Fcitx كىچىك پىنگۋىن خەت كىرگۈزگۈچى Virtual Keyboard مەۋھۇم كۇنۇپكا تاختىسى Never Show ئىزچىل كورسىتىش Always Show مەڭگۈ كۆرسىتىش Show When Keyboard Is Connected كۇنۇپكا تاختىسى ئۇلانغان چاغدا كۆرسىتىش SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/bo_CN.ts0000664000175000017500000001537615167645100021164 0ustar fengfeng PanelUkccPlugin Panel ལས་འགན་སྒྲུབ་གཞི། Merge icons on the taskbar མཉམ་སྒྲིལ་ལས་འགན་སྒྲོམ་སྟེང་གི་རི་མོ། Always ཐོག་མཐའ་བར་གསུམ་དུ་ཟླ་སྒྲིལ། Never གཏན་ནས་བྱེད་མི་ Panel location བརྙན་ཡོལ་སྟེང་གི་འགན་སྡེའི་གནས། Bottom ཞབས་ཁུལ། Left གཡོན་ཕྱོགས། Top རྩེ་མོ། Right གཡས་གཡོན། Panel size འགན་སྡེའི་ཆེ་ཆུང་། Small ཆུང་བ། Medium འབྲིང་རིམ་ཡིན། Large ཆེ་བ། Custom མཚན་ཉིད་རང་འཇོག། Panel auto hide རང་འགུལ་གྱི་འགན་སྡེ་སྦས་བ། Panel lock འགན་སྡེ་དམིགས་འཛིན། Widgets always showed on panel ནམ་ཡང་འགན་སྡེར་འཆར་བའི་རིས་རྟགས། Task view ལས་འགན་མང་བའི་མཐོང་རིས། Volume སྐད་སྒྲ། Network དྲ་རྒྱ། Power སྟོབས་ཤུགས། Bluetooth སོ་སྔོན་པོ། Icons showed on system tray འདེགས་སྡེར་ལ་འཆར་བའི་རྒྱུད་ཁོངས་རིས་རྟགས། Search སྤྱིའི་་བཤེར་འཚོལ། When existing multiple panels, show window icons on འགན་སྡེ་མང་པོ་ཡོད་སྐབས།འགན་སྡེའི་རིས་རྟགས་འཆར། All panels འགན་སྡེ་ཆ་ཚང་། Primary screen panel and panel where window is open བརྙན་ཡོལ་གཙོ་བོའི་འགན་སྡེ་དང་སྒེའུ་ཁུང་ཕྱེ་བའི་འགན་སྡེ། Panel where window is open སྒེའུ་ཁུང་ཕྱེ་བའི་འགན་སྡེ་གཅིག་པར་འཆར་བ། Show panel on all screens འཆར་ཆས་ཚང་མའི་ངོས་ལ་འགན་སྡེ་འཆར་བ། /Panel/Show panel on all screens Show system tray area on all panels འགན་སྡེ་ཚང་མར་འདེགས་སྡེའི་བཀོལ་སྤྱོད་ཁུལ་ཁོངས་འཆར་བ། Panel Appearance འགན་སྡེའི་ཕྱིའི་རྣམ་པ། classic ཚད་ལྡན། threeIsland གླིང་ཕྲན་གསུམ། VPN Fcitx འཇུག་ཐབས། Virtual Keyboard ཆི་ལིན་རྟོགས་བཟོའི་མཐེབ་གཞོང་། Never Show ནམ་ཡང་མི་འཆར། Always Show ནམ་ཡང་འཆར་བ། Show When Keyboard Is Connected མཐེབ་གཞོང་མཐུད་མེད་སྐབས་འཆར་བ། SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/mn.ts0000664000175000017500000001754415167645100020615 0ustar fengfeng PanelUkccPlugin Panel ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ /Panel/Panel Merge icons on the taskbar ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠳᠡᠭᠡᠷᠡᠬᠢ ᠢᠺᠦᠨ ᠵᠢᠷᠤᠭ ᠢ᠋ ᠨᠡᠢᠯᠡᠬᠦᠯᠬᠦ /Panel/Merge icons on the taskbar Always ᠪᠠᠢᠩᠭᠤ Never ᠶᠡᠷᠦ᠎ᠡᠴᠡ ᠦᠭᠡᠢ Panel location ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠤ᠋ᠨ ᠳᠡᠯᠭᠡᠴᠡᠨ ᠳᠡᠬᠡᠷᠡᠬᠢ ᠪᠠᠢᠷᠢᠯᠠᠯ /Panel/Panel location Bottom ᠳᠣᠣᠷ᠎ᠠ Left ᠵᠡᠬᠦᠨ Top ᠳᠡᠭᠡᠷ᠎ᠡ Right ᠪᠠᠷᠠᠭᠤᠨ Panel size ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠤ᠋ᠨ ᠶᠡᠬᠡ ᠪᠠᠭ᠎ᠠ /Panel/Panel size Small ᠪᠠᠭ᠎ᠠ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Medium ᠳᠤᠮᠳᠠ Large ᠲᠣᠮᠣ ᠬᠡᠮᠵᠢᠶ᠎ᠡ Custom ᠦᠪᠡᠷᠳᠡᠬᠡᠨ ᠳᠤᠭᠳᠠᠭᠠᠬᠤ Panel auto hide ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠢ᠋ ᠠᠦ᠋ᠲ᠋ᠣ᠋ ᠪᠡᠷ ᠨᠢᠭᠤᠴᠠᠯᠠᠬᠤ /Panel/Panel auto hide Panel lock ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠢ᠋ ᠣᠨᠢᠰᠤᠯᠠᠬᠤ /Panel/Panel lock Widgets always showed on panel ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠳᠡᠬᠡᠷᠡᠬᠢ ᠢᠺᠦᠨ ᠵᠢᠷᠤᠭ ᠢ᠋ ᠪᠠᠢᠩᠭᠤ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ /Panel/Widgets always showed on panel Task view ᠣᠯᠠᠨ ᠡᠬᠦᠷᠬᠡᠳᠦ ᠬᠠᠷᠠᠭᠠᠨ ᠵᠢᠷᠤᠭ Volume ᠡᠪᠬᠡᠮᠡᠯ Network ᠨᠧᠲ Power ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ Bluetooth ᠯᠠᠨ ᠶᠠ Icons showed on system tray ᠲᠤᠯᠬᠤ ᠳᠠᠪᠠᠭ ᠲᠡᠬᠢ ᠰᠢᠰᠲ᠋ᠧᠮ ᠤ᠋ᠨ ᠢᠺᠦᠨ ᠵᠢᠷᠤᠭ ᠲᠤ᠌ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ /Panel/Icons showed on system tray Panel Appearance ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠤ᠋ᠨ ᠭᠠᠳᠠᠷ ᠦᠵᠡᠮᠵᠢ classic ᠰᠣᠩᠭᠣᠳᠠᠭ threeIsland ᠰᠠᠨ ᠳ᠋ᠤᠤ Show panel on all screens ᠪᠦᠬᠦ ᠢᠯᠡᠷᠡᠬᠦᠷ ᠳᠡᠭᠡᠷ᠎ᠡ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠢ᠋ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ /Panel/Show panel on all screens Show system tray area on all panels ᠪᠦᠬᠦ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠳᠡᠭᠡᠷ᠎ᠡ ᠲᠤᠯᠬᠤ ᠳᠠᠪᠠᠭ ᠤ᠋ᠨ ᠠᠵᠢᠯᠯᠠᠬᠤᠢ ᠵᠢᠨ ᠬᠡᠰᠡᠭ ᠢ᠋ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ When existing multiple panels, show window icons on ᠬᠡᠳᠦ ᠬᠡᠳᠦᠨ ᠡᠬᠦᠷᠬᠡ ᠪᠠᠭᠠᠷ ᠪᠠᠢᠬᠤ ᠦᠶ᠎ᠡ ᠳ᠋ᠤ᠌᠂ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠳᠡᠭᠡᠷᠡᠬᠢ ᠢᠺᠦᠨ ᠵᠢᠷᠤᠭ ᠢ᠋ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ All panels ᠪᠦᠬᠦ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ Primary screen panel and panel where window is open ᠭᠤᠤᠯ ᠳᠡᠯᠭᠡᠴᠡᠨ ᠤ᠋ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠪᠤᠯᠤᠨ ᠨᠡᠬᠡᠬᠡᠭᠰᠡᠨ ᠴᠣᠩᠬᠣᠨ ᠤ᠋ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ Panel where window is open ᠵᠥᠪᠬᠡᠨ ᠨᠡᠬᠡᠬᠡᠭᠰᠡᠨ ᠴᠣᠩᠬᠣᠨ ᠤ᠋ ᠡᠬᠦᠷᠬᠡ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠲᠤ᠌ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ Search ᠪᠦᠬᠦ ᠳᠠᠯ᠎ᠠ ᠪᠡᠷ ᠬᠠᠢᠬᠤ VPN vpn ᠪᠠᠭᠠᠵᠢ Fcitx Virtual Keyboard ᠴᠢᠦ ᠯᠢᠨ ᠬᠡᠢᠰᠪᠦᠷᠢ ᠳᠠᠷᠤᠪᠴᠢ Never Show ᠶᠡᠷᠦ ᠡᠴᠡ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ ᠥᠬᠡᠢ Always Show ᠪᠠᠢᠩᠭᠤ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ Show When Keyboard Is Connected ᠳᠠᠷᠤᠭᠤᠯ ᠤ᠋ᠨ ᠳᠠᠪᠠᠭ ᠲᠤ᠌ ᠵᠠᠯᠭᠠᠭᠰᠠᠨ ᠥᠬᠡᠢ ᠦᠶ᠎ᠡ ᠳ᠋ᠤ᠌ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/zh_Hant.ts0000664000175000017500000001315015167645111021565 0ustar fengfeng PanelUkccPlugin Panel 任務列 /Panel/Panel Merge icons on the taskbar 合併任務列上的圖示 /Panel/Merge icons on the taskbar Always 始終 Never 從不 Panel location 任務欄在螢幕上的位置 /Panel/Panel location Bottom 底部 Left 左側 Top 頂部 Right 右側 Panel size 任務欄大小 /Panel/Panel size Small Medium Large Custom 自訂 Panel auto hide 自動隱藏任務列 /Panel/Panel auto hide Panel lock 鎖定任務列 /Panel/Panel lock Widgets always showed on panel 始終顯示在任務列上的圖示 /Panel/Widgets always showed on panel Task view 多任務檢視 Volume 聲音 Network 網路 Power 電源 Bluetooth 藍牙 Icons showed on system tray 顯示在托盤的系統圖示 /Panel/Icons showed on system tray Search 搜索 When existing multiple panels, show window icons on 多個任務列時,任務列上的圖示顯示在 All panels 所有任務列 Primary screen panel and panel where window is open 主屏任務列和打開了視窗的任務列 Panel where window is open 僅顯示在打開了視窗的任務列 Panel Appearance 任務欄外觀 classic 經典 threeIsland 三島 Show panel on all screens 在所有顯示器上顯示任務列 /Panel/Show panel on all screens Show system tray area on all panels 在所有任務列上顯示托盤操作區域 Virtual Keyboard 麒麟虛擬鍵盤 VPN VPN工具 Fcitx 輸入法 Never Show 從不顯示 Always Show 始終顯示 Show When Keyboard Is Connected 未連接鍵盤時顯示 SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/translations/zh_HK.ts0000664000175000017500000001315015167645111021175 0ustar fengfeng PanelUkccPlugin Panel 任務列 /Panel/Panel Merge icons on the taskbar 合併任務列上的圖示 /Panel/Merge icons on the taskbar Always 始終 Never 從不 Panel location 任務欄在螢幕上的位置 /Panel/Panel location Bottom 底部 Left 左側 Top 頂部 Right 右側 Panel size 任務欄大小 /Panel/Panel size Small Medium Large Custom 自訂 Panel auto hide 自動隱藏任務列 /Panel/Panel auto hide Panel lock 鎖定任務列 /Panel/Panel lock Widgets always showed on panel 始終顯示在任務列上的圖示 /Panel/Widgets always showed on panel Task view 多任務檢視 Volume 聲音 Network 網路 Power 電源 Bluetooth 藍牙 Icons showed on system tray 顯示在托盤的系統圖示 /Panel/Icons showed on system tray Search 搜索 When existing multiple panels, show window icons on 多個任務列時,任務列上的圖示顯示在 All panels 所有任務列 Primary screen panel and panel where window is open 主屏任務列和打開了視窗的任務列 Panel where window is open 僅顯示在打開了視窗的任務列 Panel Appearance 任務欄外觀 classic 經典 threeIsland 三島 Show panel on all screens 在所有顯示器上顯示任務列 /Panel/Show panel on all screens Show system tray area on all panels 在所有任務列上顯示托盤操作區域 Virtual Keyboard 麒麟虛擬鍵盤 VPN VPN工具 Fcitx 輸入法 Never Show 從不顯示 Always Show 始終顯示 Show When Keyboard Is Connected 未連接鍵盤時顯示 SwitchButton Task view 多任务视图 ukui-panel/panel/ukcc-plugin/switch-button.cpp0000664000175000017500000000357515167645111020431 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "switch-button.h" #include SwitchButton::SwitchButton(QWidget *parent, const QString &name, const QString &iconName) : QFrame(parent) { this->setFixedHeight(56); m_layout = new QHBoxLayout(this); m_layout->setContentsMargins(16, 0, 16, 0); m_layout->setSpacing(16); QIcon icon = QIcon::fromTheme(iconName); m_iconLabel = new QLabel(this); m_iconLabel->setPixmap(icon.pixmap(16, 16)); m_iconLabel->setProperty("useIconHighlightEffect", 0x2); m_label = new QLabel(this); m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_label->setText(name); m_button = new kdk::KSwitchButton(this); m_button->setFixedSize(48,24); m_button->setEnabled(false); m_layout->addWidget(m_iconLabel); m_layout->addWidget(m_label); m_layout->addWidget(m_button); connect(m_button, &kdk::KSwitchButton::stateChanged, this, &SwitchButton::stateChanged); } void SwitchButton::setChecked(bool checked) { m_button->setChecked(checked); } void SwitchButton::setEnabled(bool enable) { m_button->setEnabled(enable); } ukui-panel/panel/ukcc-plugin/CMakeLists.txt0000664000175000017500000000457715167645100017654 0ustar fengfengcmake_minimum_required(VERSION 3.14) project(panel-ukcc-plugin) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) set(VERSION_MICRO 0) set(PANEL_UKCC_PLUGIN_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) find_package(PkgConfig REQUIRED) find_package(ukui-quick COMPONENTS framework platform core) set(UKCC_PLUGIN_PC_PKGS kysdk-qtwidgets) foreach(PC_LIB IN ITEMS ${UKCC_PLUGIN_PC_PKGS}) pkg_check_modules(${PC_LIB} REQUIRED ${PC_LIB}) if(${${PC_LIB}_FOUND}) include_directories(${${PC_LIB}_INCLUDE_DIRS}) link_directories(${${PC_LIB}_LIBRARY_DIRS}) list(APPEND UKCC_PLUGIN_EXTERNAL_LIBS PkgConfig::${PC_LIB}) endif() endforeach() file(GLOB UKCC_PLUGIN_TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) qt_create_translation(UKCC_PLUGIN_QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${UKCC_PLUGIN_TS_FILES} OPTIONS -no-obsolete -no-ui-lines) else() qt5_create_translation(UKCC_PLUGIN_QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${UKCC_PLUGIN_TS_FILES}) endif() set(UKCC_PLUGIN_SRC switch-button.cpp switch-button.h panel-ukcc-plugin.cpp panel-ukcc-plugin.h ../src/general-config-define.h ) # qrc文件 set(QRC_FILES resource/res.qrc) if (QT_VERSION_MAJOR EQUAL "5") qt5_generate_repc(UKCC_PLUGIN_SRC ../src/remote-config.rep REPLICA) endif() add_library(panel-ukcc-plugin MODULE ${UKCC_PLUGIN_SRC} ${QRC_FILES} ${UKCC_PLUGIN_QM_FILES} ) if (QT_VERSION_MAJOR EQUAL "6") qt6_add_repc_replicas(panel-ukcc-plugin ../src/remote-config.rep) endif() set(TRANSLATIONS_INSTALL_PATH /usr/share/ukui-panel/panel-ukcc-plugin/translations/) target_compile_definitions(panel-ukcc-plugin PRIVATE VERSION="${PANEL_UKCC_PLUGIN_VERSION}" TRANSLATIONS_INSTALL_PATH="${TRANSLATIONS_INSTALL_PATH}" ) target_link_libraries(panel-ukcc-plugin PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::RemoteObjects ukcc ${UKCC_PLUGIN_PC_PKGS} ukui-quick::framework ukui-quick::platform ukui-quick::core ) install(TARGETS panel-ukcc-plugin DESTINATION /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/ukui-control-center) install(FILES ${UKCC_PLUGIN_TS_FILES} ${UKCC_PLUGIN_QM_FILES} DESTINATION ${TRANSLATIONS_INSTALL_PATH}) ukui-panel/panel/ukcc-plugin/switch-button.h0000664000175000017500000000261615167645100020067 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #ifndef UKUI_PANEL_SWITCH_BUTTON_H #define UKUI_PANEL_SWITCH_BUTTON_H #include #include #include #include class SwitchButton : public QFrame { Q_OBJECT public: explicit SwitchButton(QWidget *parent, const QString &name, const QString &iconName); void setChecked(bool checked); void setEnabled(bool enable); Q_SIGNALS: void stateChanged(bool state); private: QHBoxLayout *m_layout = nullptr; QLabel *m_iconLabel = nullptr; QLabel *m_label = nullptr; kdk::KSwitchButton *m_button = nullptr; }; #endif //UKUI_PANEL_SWITCH_BUTTON_H ukui-panel/panel/ukcc-plugin/panel-ukcc-plugin.cpp0000664000175000017500000013602015167645111021125 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * * Authors: iaom * */ #include "panel-ukcc-plugin.h" #include #include #include #include "general-config-define.h" #include "switch-button.h" #include #include #include #include #define TRAY_ICON_SHOW_POLICY "trayIconShowPolicy" PanelUkccPlugin::PanelUkccPlugin(QObject *parent): QObject(parent) { auto translator = new QTranslator(this); if(!translator->load(TRANSLATIONS_INSTALL_PATH + QLocale::system().name())) { qWarning() << TRANSLATIONS_INSTALL_PATH + QLocale::system().name() << "load failed"; } QApplication::installTranslator(translator); } PanelUkccPlugin::~PanelUkccPlugin() { if (m_gsetting) { delete m_gsetting; m_gsetting = nullptr; } UkuiQuick::FunctionControl::instance()->removeWatch(QStringLiteral("ukui-panel-v11")); } QString PanelUkccPlugin::plugini18nName() { return tr("Panel"); } int PanelUkccPlugin::pluginTypes() { return PERSONALIZED; } QWidget *PanelUkccPlugin::pluginUi() { if (!m_widget) { initFunctionControl(); initUI(); connectToSource(); } return m_widget; } const QString PanelUkccPlugin::name() const { // 不需要翻译,作为key,用于在控制面板激活并显示插件 return "Panel"; } QString PanelUkccPlugin::translationPath() const { return QStringLiteral("/usr/share/ukui-panel/panel-ukcc-plugin/translations/%1.ts");; } bool PanelUkccPlugin::isShowOnHomePage() const { return false; } QIcon PanelUkccPlugin::icon() const { return QIcon::fromTheme("ukui-panel-symbolic"); } bool PanelUkccPlugin::isEnable() const { return true; } void PanelUkccPlugin::connectToSource() { QString displayEnv = (qgetenv("XDG_SESSION_TYPE") == "wayland") ? QLatin1String("WAYLAND_DISPLAY") : QLatin1String("DISPLAY"); QString display(qgetenv(displayEnv.toUtf8().data())); QUrl address(QStringLiteral("local:ukui-panel-config-") + QString(qgetenv("USER")) + display); qDebug() << "panel ukcc plugin connect to source:" << m_qroNode.connectToNode(address); m_configReplica = m_qroNode.acquire(); if (m_configReplica->waitForSource(2000)) { initData(); } connect(m_configReplica, &QRemoteObjectReplica::initialized, this, &PanelUkccPlugin::initData); connect(m_configReplica, &QRemoteObjectReplica::stateChanged, this, &PanelUkccPlugin::sourceStateChanged); } void PanelUkccPlugin::initUI() { m_widget = new QWidget; // main page m_mainLayout = new QVBoxLayout(m_widget); m_mainLayout->setSpacing(8); m_mainLayout->setContentsMargins(0, 0, 0, 0); // panel m_titleLabel1 = new kdk::KLabel(m_widget); m_titleLabel1->setContentsMargins(16, 0, 0, 0); //~ contents_path /Panel/Panel m_titleLabel1->setText(tr("Panel")); m_mainLayout->addWidget(m_titleLabel1); m_frame1 = new QFrame(m_widget); m_frame1->setFrameShape(QFrame::Shape::Box); m_vLayout1 = new QVBoxLayout(m_frame1); m_vLayout1->setContentsMargins(0, 0, 0, 0); m_vLayout1->setSpacing(0); //panel mode m_panelTypeFrame = new QFrame(m_frame1); m_panelTypeFrame->setFixedHeight(147); m_panelTypeLayout = new QHBoxLayout(m_panelTypeFrame); m_panelTypeLayout->setContentsMargins(16, 0, 16, 0); m_panelTypeLabel = new QLabel(m_panelTypeFrame); m_panelTypeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_panelTypeLabel->setText(tr("Panel Appearance")); m_panelTypeGroup = new QButtonGroup(m_panelTypeFrame); m_classicType = new QPushButton(m_panelTypeFrame); m_threeIslandType = new QPushButton(m_panelTypeFrame); m_classicType->setIconSize(QSize(140,90)); m_classicType->setFixedSize(QSize(142,92)); m_classicType->setCheckable(true); m_threeIslandType->setCheckable(true); m_threeIslandType->setIconSize(QSize(140,90)); m_threeIslandType->setFixedSize(QSize(142,92)); m_classicType->setIcon(QIcon(":/classic.png")); m_threeIslandType->setIcon(QIcon(":/island.png")); m_panelTypeGroup->addButton(m_classicType, 0); m_panelTypeGroup->addButton(m_threeIslandType, 1); m_panelTypeGroup->setExclusive(true); QString buttonStyle( "QPushButton{background: palette(window);" "border-color: palette(highlight);" "border-width: 0px;border-style: solid;border-radius: 6px}" "QPushButton:hover{background: palette(window);" "border-color: palette(highlight);" "border-width: 1px;border-style: solid;border-radius: 6px}" "QPushButton:checked{background: palette(window);" "border-color: palette(highlight);" "border-width: 2px;border-style: solid;border-radius: 6px}" "QPushButton:!enabled{background: palette(window);" "border-width: 0px}"); m_classicType->setStyleSheet(buttonStyle); m_classicType->setEnabled(false); m_threeIslandType->setEnabled(false); m_threeIslandType->setStyleSheet(buttonStyle); m_classicTypeLabel = new QLabel(m_panelTypeFrame); m_classicTypeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_classicTypeLabel->setText(tr("classic")); m_classicTypeLabel->setMaximumWidth(140); m_classicTypeLabel->setAlignment(Qt::AlignCenter); m_threeIslandTypeLabel = new QLabel(m_panelTypeFrame); m_threeIslandTypeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_threeIslandTypeLabel->setText(tr("threeIsland")); m_threeIslandTypeLabel->setMaximumWidth(140); m_threeIslandTypeLabel->setAlignment(Qt::AlignCenter); m_classicTypeLayout = new QVBoxLayout(m_panelTypeFrame); m_classicTypeLayout->setContentsMargins(0, 16, 0, 16); m_classicTypeLayout->addWidget(m_classicType); m_classicTypeLayout->addWidget(m_classicTypeLabel); m_threeIslandTypeLayout = new QVBoxLayout(m_panelTypeFrame); m_threeIslandTypeLayout->setContentsMargins(0, 16, 0, 16); m_threeIslandTypeLayout->addWidget(m_threeIslandType); m_threeIslandTypeLayout->addWidget(m_threeIslandTypeLabel); m_panelTypeButtonLayout = new QHBoxLayout(m_panelTypeFrame); m_panelTypeButtonLayout->setContentsMargins(0, 0, 0, 0); m_panelTypeButtonLayout->addLayout(m_classicTypeLayout); m_panelTypeButtonLayout->addLayout(m_threeIslandTypeLayout); m_panelTypeLayout->addWidget(m_panelTypeLabel); m_panelTypeLayout->addLayout(m_panelTypeButtonLayout); m_vLayout1->addWidget(m_panelTypeFrame); m_vLayout1->addWidget(setLine(m_frame1)); //merge icons m_mergeIconsFrame = new QFrame(m_frame1); m_mergeIconsFrame->setFixedHeight(56); m_mergeIconsLayout = new QHBoxLayout(m_mergeIconsFrame); m_mergeIconsLayout->setContentsMargins(16, 0, 16, 0); m_mergeIconsLabel = new QLabel(m_mergeIconsFrame); m_mergeIconsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //~ contents_path /Panel/Merge icons on the taskbar m_mergeIconsLabel->setText(tr("Merge icons on the taskbar")); m_mergeIcons = new QComboBox(m_mergeIconsFrame); m_mergeIcons->setEnabled(false); m_mergeIcons->setMinimumWidth(320); m_mergeIcons->addItem(tr("Always"), GeneralConfigDefine::MergeIcons::Always); m_mergeIcons->addItem(tr("Never"), GeneralConfigDefine::MergeIcons::Never); m_mergeIconsLayout->addWidget(m_mergeIconsLabel); m_mergeIconsLayout->addWidget(m_mergeIcons); m_vLayout1->addWidget(m_mergeIconsFrame); m_vLayout1->addWidget(setLine(m_frame1)); //panel location m_panelLocationFrame = new QFrame(m_frame1); m_panelLocationFrame->setFixedHeight(56); m_panelLocationLayout = new QHBoxLayout(m_panelLocationFrame); m_panelLocationLayout->setContentsMargins(16, 0, 16, 0); m_panelLocationLabel = new QLabel(m_panelLocationFrame); m_panelLocationLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //~ contents_path /Panel/Panel location m_panelLocationLabel->setText(tr("Panel location")); m_panelLocation = new QComboBox(m_panelLocationFrame); m_panelLocation->setEnabled(false); m_panelLocation->setMinimumWidth(320); m_panelLocation->addItem(tr("Bottom"), GeneralConfigDefine::PanelLocation::Bottom); m_panelLocation->addItem(tr("Left"), GeneralConfigDefine::PanelLocation::Left); m_panelLocation->addItem(tr("Top"), GeneralConfigDefine::PanelLocation::Top); m_panelLocation->addItem(tr("Right"), GeneralConfigDefine::PanelLocation::Right); m_panelLocationLayout->addWidget(m_panelLocationLabel); m_panelLocationLayout->addWidget(m_panelLocation); m_vLayout1->addWidget(m_panelLocationFrame); m_vLayout1->addWidget(setLine(m_frame1)); //panel size m_panelSizePolicyFrame = new QFrame(m_frame1); m_panelSizePolicyFrame->setFixedHeight(56); m_panelSizePolicyLayout = new QHBoxLayout(m_panelSizePolicyFrame); m_panelSizePolicyLayout->setContentsMargins(16, 0, 16, 0); m_panelSizePolicyLabel = new QLabel(m_panelSizePolicyFrame); m_panelSizePolicyLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //~ contents_path /Panel/Panel size m_panelSizePolicyLabel->setText(tr("Panel size")); m_panelSizePolicy = new QComboBox(m_panelSizePolicyFrame); m_panelSizePolicy->setEnabled(false); m_panelSizePolicy->setMinimumWidth(320); m_panelSizePolicy->addItem(tr("Small"), GeneralConfigDefine::PanelSizePolicy::Small); m_panelSizePolicy->addItem(tr("Medium"), GeneralConfigDefine::PanelSizePolicy::Medium); m_panelSizePolicy->addItem(tr("Large"), GeneralConfigDefine::PanelSizePolicy::Large); m_panelSizePolicy->addItem(tr("Custom"), GeneralConfigDefine::PanelSizePolicy::Custom); m_panelSizePolicyLayout->addWidget(m_panelSizePolicyLabel); m_panelSizePolicyLayout->addWidget(m_panelSizePolicy); m_vLayout1->addWidget(m_panelSizePolicyFrame); m_vLayout1->addWidget(setLine(m_frame1)); //panel auto hide m_panelAutoHideFrame = new QFrame(m_frame1); m_panelAutoHideFrame->setFixedHeight(56); m_panelAutoHideLayout = new QHBoxLayout(m_panelAutoHideFrame); m_panelAutoHideLayout->setContentsMargins(16, 0, 16, 0); m_panelAutoHideLabel = new QLabel(m_panelAutoHideFrame); m_panelAutoHideLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //~ contents_path /Panel/Panel auto hide m_panelAutoHideLabel->setText(tr("Panel auto hide")); m_panelAutoHide = new kdk::KSwitchButton(m_panelAutoHideFrame); m_panelAutoHide->setFixedSize(48,24); // m_panelAutoHide->setCheckable(false); m_panelAutoHide->setEnabled(false); m_panelAutoHideLayout->addWidget(m_panelAutoHideLabel); m_panelAutoHideLayout->addWidget(m_panelAutoHide); m_vLayout1->addWidget(m_panelAutoHideFrame); m_vLayout1->addWidget(setLine(m_frame1)); //panel lock m_panelLockFrame = new QFrame(m_frame1); m_panelLockFrame->setFixedHeight(56); m_panelLockLayout = new QHBoxLayout(m_panelLockFrame); m_panelLockLayout->setContentsMargins(16, 0, 16, 0); m_panelLockLabel = new QLabel(m_panelLockFrame); m_panelLockLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //~ contents_path /Panel/Panel lock m_panelLockLabel->setText(tr("Panel lock")); m_panelLock = new kdk::KSwitchButton(m_panelLockFrame); m_panelLock->setFixedSize(48,24); // m_panelLock->setCheckable(false); m_panelLock->setEnabled(false); m_panelLockLayout->addWidget(m_panelLockLabel); m_panelLockLayout->addWidget(m_panelLock); m_vLayout1->addWidget(m_panelLockFrame); m_vLayout1->addWidget(setLine(m_frame1)); //show panel on all screens m_showPanelOnAllScreensFrame = new QFrame(m_frame1); m_showPanelOnAllScreensFrame->setFixedHeight(56); m_showPanelOnAllScreensLayout = new QHBoxLayout(m_showPanelOnAllScreensFrame); m_showPanelOnAllScreensLayout->setContentsMargins(16, 0, 16, 0); m_showPanelOnAllScreensLabel = new QLabel(m_showPanelOnAllScreensFrame); m_showPanelOnAllScreensLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //~ contents_path /Panel/Show panel on all screens m_showPanelOnAllScreensLabel->setText(tr("Show panel on all screens")); m_showPanelOnAllScreens = new kdk::KSwitchButton(m_showPanelOnAllScreensFrame); m_showPanelOnAllScreens->setFixedSize(48,24); m_showPanelOnAllScreens->setEnabled(false); m_showPanelOnAllScreensLayout->addWidget(m_showPanelOnAllScreensLabel); m_showPanelOnAllScreensLayout->addWidget(m_showPanelOnAllScreens); m_vLayout1->addWidget(m_showPanelOnAllScreensFrame); m_vLayout1->addWidget(setLine(m_frame1)); //show system tray on all panel m_showSystemTrayOnAllPanelsFrame = new QFrame(m_frame1); m_showSystemTrayOnAllPanelsFrame->setFixedHeight(56); m_showSystemTrayOnAllPanelsLayout = new QHBoxLayout(m_showSystemTrayOnAllPanelsFrame); m_showSystemTrayOnAllPanelsLayout->setContentsMargins(16, 0, 16, 0); m_showSystemTrayOnAllPanelsLabel = new QLabel(m_showSystemTrayOnAllPanelsFrame); m_showSystemTrayOnAllPanelsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_showSystemTrayOnAllPanelsLabel->setText(tr("Show system tray area on all panels ")); m_showSystemTrayOnAllPanels = new kdk::KSwitchButton(m_showSystemTrayOnAllPanelsFrame); m_showSystemTrayOnAllPanels->setFixedSize(48,24); m_showSystemTrayOnAllPanels->setEnabled(false); m_showSystemTrayOnAllPanelsLayout->addWidget(m_showSystemTrayOnAllPanelsLabel); m_showSystemTrayOnAllPanelsLayout->addWidget(m_showSystemTrayOnAllPanels); m_vLayout1->addWidget(m_showSystemTrayOnAllPanelsFrame); m_vLayout1->addWidget(setLine(m_frame1)); //taskmanager icons showed on m_iconsShowedOnFrame = new QFrame(m_frame1); m_iconsShowedOnFrame->setFixedHeight(56); m_iconsShowedOnLayout = new QHBoxLayout(m_iconsShowedOnFrame); m_iconsShowedOnLayout->setContentsMargins(16, 0, 16, 0); m_iconsShowedOnLabel = new kdk::KLabel(m_iconsShowedOnFrame); m_iconsShowedOnLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_iconsShowedOnLabel->setMinimumWidth(200); m_iconsShowedOnLabel->setText(tr("When existing multiple panels, show window icons on")); m_iconsShowedOn = new QComboBox(m_iconsShowedOnFrame); m_iconsShowedOn->setEnabled(false); m_iconsShowedOn->setMinimumWidth(320); m_iconsShowedOn->addItem(tr("All panels"), GeneralConfigDefine::TaskBarIconsShowedOn::AllPanels); m_iconsShowedOn->addItem(tr("Primary screen panel and panel where window is open"), GeneralConfigDefine::TaskBarIconsShowedOn::PrimaryScreenPanelAndPanelWhereWindowIsOpen); m_iconsShowedOn->addItem(tr("Panel where window is open"), GeneralConfigDefine::TaskBarIconsShowedOn::PanelWhereWindowIsOpen); m_iconsShowedOnLayout->addWidget(m_iconsShowedOnLabel); m_iconsShowedOnLayout->addWidget(m_iconsShowedOn); m_vLayout1->addWidget(m_iconsShowedOnFrame); m_vLayout1->addWidget(setLine(m_frame1)); m_mainLayout->addWidget(m_frame1); m_mainLayout->addSpacerItem(new QSpacerItem(40, 40, QSizePolicy::Fixed)); //widgets showed on panel m_titleLabel2 = new kdk::KLabel(m_widget); m_titleLabel2->setContentsMargins(16, 0, 0, 0); //~ contents_path /Panel/Widgets always showed on panel m_titleLabel2->setText(tr("Widgets always showed on panel")); m_mainLayout->addWidget(m_titleLabel2); m_frame2 = new QFrame(m_widget); m_frame2->setFrameShape(QFrame::Box); m_vLayout2 = new QVBoxLayout(m_frame2); m_vLayout2->setContentsMargins(0, 0, 0, 0); m_vLayout2->setSpacing(0); //task view m_showTaskViewFrame = new QFrame(m_frame2); m_showTaskViewFrame->setFixedHeight(56); m_showTaskViewLayout = new QHBoxLayout(m_showTaskViewFrame); m_showTaskViewLayout->setContentsMargins(16, 0, 16, 0); m_showTaskViewLayout->setSpacing(16); m_showTaskViewIconLabel = new QLabel(m_showTaskViewFrame); m_showTaskViewIconLabel->setPixmap(QIcon::fromTheme("ukui-taskview-black-symbolic").pixmap(32, 32)); m_showTaskViewIconLabel->setProperty("useIconHighlightEffect", 0x2); m_showTaskViewLabel = new QLabel(m_showTaskViewFrame); m_showTaskViewLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_showTaskViewLabel->setText(tr("Task view")); m_showTaskView = new kdk::KSwitchButton(m_showTaskViewFrame); m_showTaskView->setFixedSize(48,24); // m_showTaskView->setCheckable(false); m_showTaskView->setEnabled(false); m_showTaskViewLayout->addWidget(m_showTaskViewIconLabel); m_showTaskViewLayout->addWidget(m_showTaskViewLabel); m_showTaskViewLayout->addWidget(m_showTaskView); m_vLayout2->addWidget(m_showTaskViewFrame); m_vLayout2->addWidget(setLine(m_frame2)); //show search m_showSearchFrame = new QFrame(m_frame2); m_showSearchFrame->setFixedHeight(56); m_showSearchLayout = new QHBoxLayout(m_showSearchFrame); m_showSearchLayout->setContentsMargins(16, 0, 16, 0); m_showSearchLayout->setSpacing(16); m_showSearchIconLabel = new QLabel(m_showTaskViewFrame); m_showSearchIconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(32, 32)); m_showSearchIconLabel->setProperty("useIconHighlightEffect", 0x2); m_showSearchLabel = new QLabel(m_showSearchFrame); m_showSearchLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_showSearchLabel->setText(tr("Search")); m_showSearch = new kdk::KSwitchButton(m_showSearchFrame); m_showSearch->setFixedSize(48,24); m_showSearch->setEnabled(false); m_showSearchLayout->addWidget(m_showSearchIconLabel); m_showSearchLayout->addWidget(m_showSearchLabel); m_showSearchLayout->addWidget(m_showSearch); m_vLayout2->addWidget(m_showSearchFrame); m_mainLayout->addWidget(m_frame2); m_mainLayout->addSpacerItem(new QSpacerItem(40, 40, QSizePolicy::Fixed)); //Icons showed on system tray m_titleLabel3 = new kdk::KLabel(m_widget); m_titleLabel3->setContentsMargins(16, 0, 0, 0); //~ contents_path /Panel/Icons showed on system tray m_titleLabel3->setText(tr("Icons showed on system tray")); m_mainLayout->addWidget(m_titleLabel3); m_frame3 = new QFrame(m_widget); // m_frame3->setFixedHeight(56); m_frame3->setFrameShape(QFrame::Box); m_vLayout3 = new QVBoxLayout(m_frame3); m_vLayout3->setContentsMargins(0, 0, 0, 0); m_vLayout3->setSpacing(0); m_systemTrayIconInfo.append(TrayIconInfo("ukui-bluetooth", tr("Bluetooth"), "bluetooth-symbolic")); m_systemTrayIconInfo.append(TrayIconInfo("Fcitx", tr("Fcitx"), "input-keyboard-symbolic")); //Virtual Keyboard m_virtualKeyboardFrame = new QFrame(m_frame3); m_virtualKeyboardFrame->setFixedHeight(56); m_virtualKeyboardLayout = new QHBoxLayout(m_virtualKeyboardFrame); m_virtualKeyboardLayout->setContentsMargins(16, 0, 16, 0); m_virtualKeyboardLayout->setSpacing(16); m_virtualKeyboardIconLabel = new QLabel(m_virtualKeyboardFrame); m_virtualKeyboardIconLabel->setPixmap(QIcon::fromTheme("preferences-desktop-keyboard-symbolic").pixmap(16, 16)); m_virtualKeyboardIconLabel->setProperty("useIconHighlightEffect", 0x2); m_virtualKeyboardLabel = new QLabel(m_virtualKeyboardFrame); m_virtualKeyboardLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_virtualKeyboardLabel->setText(tr("Virtual Keyboard")); m_virtualKeyboardPolicy = new QComboBox(m_virtualKeyboardFrame); m_virtualKeyboardPolicy->setEnabled(false); m_virtualKeyboardPolicy->setMinimumWidth(320); m_virtualKeyboardPolicy->addItem(tr("Never Show")); m_virtualKeyboardPolicy->addItem(tr("Always Show")); m_virtualKeyboardPolicy->addItem(tr("Show When Keyboard Is Connected")); m_virtualKeyboardLayout->addWidget(m_virtualKeyboardIconLabel); m_virtualKeyboardLayout->addWidget(m_virtualKeyboardLabel); m_virtualKeyboardLayout->addWidget(m_virtualKeyboardPolicy); m_vLayout3->addWidget(m_virtualKeyboardFrame); m_vLayout3->addWidget(setLine(m_frame3)); m_mainLayout->addWidget(m_frame3); m_mainLayout->addStretch(); } QFrame *PanelUkccPlugin::setLine(QFrame *parent) { auto line = new QFrame(parent); line->setFixedHeight(1); line->setLineWidth(0); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); return line; } void PanelUkccPlugin::initData() { if(m_configReplica->panelType() == GeneralConfigDefine::PanelType::Version4) { m_classicType->setChecked(true); } else if(m_configReplica->panelType() == GeneralConfigDefine::PanelType::Version5) { m_threeIslandType->setChecked(true); } m_panelType = m_configReplica->panelType(); m_threeIslandType->setEnabled(true); m_mergeIcons->setCurrentIndex(m_configReplica->mergeIcons()); m_mergeIcons->setEnabled(m_panelType == GeneralConfigDefine::PanelType::Version4); if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelLocation->setCurrentIndex(m_configReplica->panelLocation()); } else { m_panelLocation->setCurrentIndex(m_configReplica->panelLocationNext()); } m_panelLocation->setEnabled(!m_configReplica->panelLock() && m_panelType == GeneralConfigDefine::PanelType::Version4); auto refreshSizePolicyItems = [this](bool allow) { auto model = qobject_cast(m_panelSizePolicy->model()); if (model) { QStandardItem* item = model->item(3); if (item) { item->setFlags(allow ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled); } } }; if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelSizePolicy->setCurrentIndex(m_configReplica->panelSizePolicy()); refreshSizePolicyItems(m_configReplica->allowCustomSize()); } else { m_panelSizePolicy->setCurrentIndex(m_configReplica->panelSizePolicyNext()); } m_panelSizePolicy->setEnabled(!m_configReplica->panelLock()); if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelAutoHide->setChecked(m_configReplica->panelAutoHide()); } else { m_panelAutoHide->setChecked(m_configReplica->panelAutoHideNext()); } m_panelAutoHide->setEnabled(true); if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelLock->setChecked(m_configReplica->panelLock()); } else { m_panelLock->setChecked(m_configReplica->panelLockNext()); } m_panelLock->setEnabled(true); m_iconsShowedOn->setCurrentIndex(m_configReplica->taskBarIconsShowedOn()); //show panel on all screens m_showPanelOnAllScreens->setChecked(m_configReplica->showPanelOnAllScreens()); m_showPanelOnAllScreens->setEnabled(true); m_iconsShowedOn->setEnabled(m_configReplica->showPanelOnAllScreens()); m_showSystemTrayOnAllPanels->setChecked(m_configReplica->showSystemTrayOnAllPanels()); m_showSystemTrayOnAllPanels->setEnabled(m_configReplica->panelType() == GeneralConfigDefine::PanelType::Version4 && m_configReplica->showPanelOnAllScreens()); if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_showTaskView->setChecked(!m_configReplica->disabledWidgets().contains(QStringLiteral("org.ukui.panel.taskView"))); } else { m_showTaskView->setChecked(!m_configReplica->disabledWidgetsNext().contains(QStringLiteral("org.ukui.panel.taskView"))); } m_showTaskView->setEnabled(true); //是否始终显示搜索 if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_showSearch->setChecked(!m_configReplica->disabledWidgets().contains(QStringLiteral("org.ukui.panel.search"))); } else { m_showSearch->setChecked(!m_configReplica->disabledWidgetsNext().contains(QStringLiteral("org.ukui.panel.search"))); } m_showSearch->setEnabled(true); QStringList trayIconList = m_configReplica->trayIconsCanInhibited(); if (m_systemTrayIconId != trayIconList) m_systemTrayIconId = trayIconList; int index = 0; for(const TrayIconInfo &trayIconInfo : m_systemTrayIconInfo) { if (!m_systemTrayIconId.contains(trayIconInfo.id)) { continue; } auto button = new SwitchButton(m_frame3, trayIconInfo.name, trayIconInfo.iconName); button->setObjectName(trayIconInfo.id); button->setEnabled(true); button->setChecked(!m_configReplica->trayIconsInhibited().contains(trayIconInfo.id)); m_vLayout3->insertWidget(2 * index, button); m_vLayout3->insertWidget(2 * index + 1, setLine(m_frame3)); ++index; if (!m_initialized) { connect(button, &SwitchButton::stateChanged, this, [&, button](bool show) { QStringList icons = m_configReplica->trayIconsInhibited(); if (!show && !icons.contains(button->objectName())) { m_configReplica->setTrayIconsInhibited(icons << button->objectName()); } else if (show && icons.contains(button->objectName())) { icons.removeAll(button->objectName()); m_configReplica->setTrayIconsInhibited(icons); } }); } } //Virtual Keyboard const QByteArray id("org.ukui.virtualkeyboard"); if (QGSettings::isSchemaInstalled(id)) { m_gsetting = new QGSettings(id); if (m_gsetting->keys().contains(TRAY_ICON_SHOW_POLICY)) { //若旧配置中已经禁用虚拟键盘,需要取消禁用 QStringList icons = m_configReplica->trayIconsInhibited(); if (icons.contains("kylin-virtual-keyboard")) { icons.removeAll("kylin-virtual-keyboard"); m_configReplica->setTrayIconsInhibited(icons); } m_virtualKeyboardPolicy->setEnabled(true); m_virtualKeyboardPolicy->setCurrentIndex(virtualKeyboardCurrentIndex()); if (!m_initialized) { connect(m_virtualKeyboardPolicy, QOverload::of(&QComboBox::currentIndexChanged), this, [&](int index) { switch (index) { case VirtualKeyboardPolicy::NeverShow: m_gsetting->set(TRAY_ICON_SHOW_POLICY, "NeverShow"); break; case VirtualKeyboardPolicy::AlwaysSHow: m_gsetting->set(TRAY_ICON_SHOW_POLICY, "AlwaysShow"); break; case VirtualKeyboardPolicy::ShowWhenKeyboardIsConnected: m_gsetting->set(TRAY_ICON_SHOW_POLICY, "ShowWhenKeyboardIsConnected"); break; default: break; } }); connect(m_gsetting, &QGSettings::changed, this, [&](const QString&key) { if (key == TRAY_ICON_SHOW_POLICY) { m_virtualKeyboardPolicy->setCurrentIndex(virtualKeyboardCurrentIndex()); } }); } } } //初始化功能管控配置 onFunctionControlChanged(QStringLiteral("ukui-panel-v11"), false); if (m_controlConfig.contains(QStringLiteral("panelLocation"))) { m_panelLocation->blockSignals(true); m_panelLocation->setCurrentIndex(m_configReplica->panelLocation()); m_panelLocation->blockSignals(false); } if (m_controlConfig.contains(QStringLiteral("panelSizePolicy"))) { m_panelSizePolicy->blockSignals(true); m_panelSizePolicy->setCurrentIndex(m_configReplica->panelSizePolicy()); m_panelSizePolicy->blockSignals(false); } if (m_controlConfig.contains(QStringLiteral("panelAutoHide"))) { m_panelAutoHide->blockSignals(true); m_panelAutoHide->setChecked(m_configReplica->panelAutoHide()); m_panelAutoHide->blockSignals(false); } if (m_controlConfig.contains(QStringLiteral("panelLock"))) { m_panelLock->blockSignals(true); m_panelLock->setChecked(m_configReplica->panelLock()); m_panelLock->blockSignals(false); } if (!m_initialized) { connect(m_configReplica, &RemoteConfigReplica::panelTypeChanged, this, [&](GeneralConfigDefine::PanelType panelType) { m_panelType = panelType; if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_classicType->setChecked(true); } else if(m_panelType == GeneralConfigDefine::PanelType::Version5) { m_threeIslandType->setChecked(true); } updateData(); }); connect(m_classicType, &QPushButton::clicked, this, [&] { if(m_panelType != GeneralConfigDefine::PanelType::Version4) { m_panelType = GeneralConfigDefine::PanelType::Version4; m_configReplica->setPanelType(GeneralConfigDefine::PanelType::Version4); } }); m_classicType->setEnabled(true); connect(m_threeIslandType, &QPushButton::clicked, this, [&] { if(m_panelType != GeneralConfigDefine::PanelType::Version5) { m_panelType = GeneralConfigDefine::PanelType::Version5; m_configReplica->setPanelType(GeneralConfigDefine::PanelType::Version5); } }); connect(m_mergeIcons, QOverload::of(&QComboBox::currentIndexChanged), this, [&](int index){ m_configReplica->setMergeIcons(static_cast(index)); }); connect(m_configReplica, &RemoteConfigReplica::mergeIconsChanged, m_mergeIcons, &QComboBox::setCurrentIndex); connect(m_panelLocation, QOverload::of(&QComboBox::currentIndexChanged), this, [&](int index){ if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_configReplica->setPanelLocation(static_cast(index)); } else { m_configReplica->setPanelLocationNext(static_cast(index)); } }); connect(m_configReplica, &RemoteConfigReplica::panelLocationChanged, m_panelLocation, &QComboBox::setCurrentIndex); connect(m_configReplica, &RemoteConfigReplica::panelLocationNextChanged, m_panelLocation, &QComboBox::setCurrentIndex); connect(m_panelSizePolicy, QOverload::of(&QComboBox::currentIndexChanged), this, [&](int index){ if (m_panelType == GeneralConfigDefine::PanelType::Version4) { m_configReplica->setPanelSizePolicy(static_cast(index)); } else { m_configReplica->setPanelSizePolicyNext(static_cast(index)); } }); connect(m_configReplica, &RemoteConfigReplica::panelSizePolicyChanged, m_panelSizePolicy, [&](GeneralConfigDefine::PanelSizePolicy panelSize){ if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelSizePolicy->setCurrentIndex(panelSize); } }); connect(m_configReplica, &RemoteConfigReplica::allowCustomSizeChanged, m_panelSizePolicy, [this, refreshSizePolicyItems](bool allowCustomSize) { refreshSizePolicyItems(allowCustomSize); }); connect(m_configReplica, &RemoteConfigReplica::panelSizePolicyNextChanged, m_panelSizePolicy, [&](GeneralConfigDefine::PanelSizePolicy panelSize) { if(m_panelType == GeneralConfigDefine::PanelType::Version5) { m_panelSizePolicy->setCurrentIndex(panelSize); } }); connect(m_panelAutoHide, &kdk::KSwitchButton::stateChanged, m_configReplica, [&](bool state) { if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_configReplica->setPanelAutoHide(state); } else { m_configReplica->setPanelAutoHideNext(state); } }); connect(m_configReplica, &RemoteConfigReplica::panelAutoHideChanged, m_panelAutoHide, [&](bool autoHide) { if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelAutoHide->setChecked(autoHide); } }); connect(m_configReplica, &RemoteConfigReplica::panelAutoHideNextChanged, m_panelAutoHide, [&](bool autoHide) { if(m_panelType == GeneralConfigDefine::PanelType::Version5) { m_panelAutoHide->setChecked(autoHide); } }); connect(m_panelLock, &kdk::KSwitchButton::stateChanged, m_configReplica, [&](bool state) { if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_configReplica->setPanelLock(state); } else { m_configReplica->setPanelLockNext(state); } }); connect(m_configReplica, &RemoteConfigReplica::panelLockChanged, m_panelLock, [&](bool panelLock) { if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelLock->setChecked(panelLock); if (!m_controlConfig.contains(QStringLiteral("panelLocation"))) { m_panelLocation->setEnabled(!panelLock); } if (!m_controlConfig.contains(QStringLiteral("panelSizePolicy"))) { m_panelSizePolicy->setEnabled(!panelLock); } } }); connect(m_configReplica, &RemoteConfigReplica::panelLockNextChanged, m_panelLock, [&](bool panelLock) { if(m_panelType == GeneralConfigDefine::PanelType::Version5) { m_panelLock->setChecked(panelLock); m_panelSizePolicy->setEnabled(!panelLock); } }); connect(m_iconsShowedOn, QOverload::of(&QComboBox::currentIndexChanged), this, [&](int index){ m_configReplica->setTaskBarIconsShowedOn(static_cast(index)); }); connect(m_configReplica, &RemoteConfigReplica::taskBarIconsShowedOnChanged, m_iconsShowedOn, &QComboBox::setCurrentIndex); connect(m_showPanelOnAllScreens, &kdk::KSwitchButton::stateChanged, m_configReplica, &RemoteConfigReplica::setShowPanelOnAllScreens); connect(m_configReplica, &RemoteConfigReplica::showPanelOnAllScreensChanged, this, [&](bool showPanelOnAllScreens) { m_showPanelOnAllScreens->setChecked(showPanelOnAllScreens); //不在所有屏幕显示任务栏时,将任务栏图标选项设置为在主屏和打开了窗口的任务栏显示 if(!showPanelOnAllScreens) { if(m_iconsShowedOn->currentIndex() == GeneralConfigDefine::TaskBarIconsShowedOn::PanelWhereWindowIsOpen) { m_iconsShowedOn->setCurrentIndex(GeneralConfigDefine::TaskBarIconsShowedOn::AllPanels); } } m_iconsShowedOn->setEnabled(showPanelOnAllScreens); m_showSystemTrayOnAllPanels->setEnabled(showPanelOnAllScreens); }); connect(m_showSystemTrayOnAllPanels, &kdk::KSwitchButton::stateChanged, m_configReplica, &RemoteConfigReplica::setShowSystemTrayOnAllPanels); connect(m_configReplica, &RemoteConfigReplica::showSystemTrayOnAllPanelsChanged, m_showSystemTrayOnAllPanels, &kdk::KSwitchButton::setChecked); connect(m_configReplica, &RemoteConfigReplica::disabledWidgetsChanged, m_showTaskView, [this](const QStringList&list) { if (m_panelType == GeneralConfigDefine::PanelType::Version4) { m_showTaskView->setChecked(!list.contains(QStringLiteral("org.ukui.panel.taskView"))); } }); connect(m_configReplica, &RemoteConfigReplica::disabledWidgetsNextChanged, m_showTaskView, [this](const QStringList&list) { if (m_panelType == GeneralConfigDefine::PanelType::Version5) { m_showTaskView->setChecked(!list.contains(QStringLiteral("org.ukui.panel.taskView"))); } }); connect(m_showTaskView, &kdk::KSwitchButton::stateChanged, this, [&](bool show) { if (m_panelType == GeneralConfigDefine::PanelType::Version4) { m_configReplica->disableWidget(QStringLiteral("org.ukui.panel.taskView"), !show); } else { m_configReplica->disableWidgetNext(QStringLiteral("org.ukui.panel.taskView"), !show); } }); connect(m_configReplica, &RemoteConfigReplica::disabledWidgetsChanged, m_showSearch, [this](const QStringList&list) { if (m_panelType == GeneralConfigDefine::PanelType::Version4) { m_showSearch->setChecked(!list.contains(QStringLiteral("org.ukui.panel.search"))); } }); connect(m_configReplica, &RemoteConfigReplica::disabledWidgetsNextChanged, m_showSearch, [this](const QStringList&list) { if (m_panelType == GeneralConfigDefine::PanelType::Version5) { m_showSearch->setChecked(!list.contains(QStringLiteral("org.ukui.panel.search"))); } }); connect(m_showSearch, &kdk::KSwitchButton::stateChanged, this, [&](bool show) { if (m_panelType == GeneralConfigDefine::PanelType::Version4) { m_configReplica->disableWidget(QStringLiteral("org.ukui.panel.search"), !show); } else { m_configReplica->disableWidgetNext(QStringLiteral("org.ukui.panel.search"), !show); } }); connect(m_configReplica, &RemoteConfigReplica::trayIconsCanInhibitedChanged, this, [this](const QStringList&list) { onTrayIconsCanInhibitedChanged(list); }); } m_initialized = true; } void PanelUkccPlugin::sourceStateChanged(QRemoteObjectReplica::State state, QRemoteObjectReplica::State oldState) { qDebug() << "PanelUkccPlugin sourceStateChanged" << state; if(state == QRemoteObjectReplica::State::Suspect && oldState == QRemoteObjectReplica::State::Valid) { qWarning() << "Error occurs after remote object initialized"; m_mergeIcons->setEnabled(false); m_panelLocation->setEnabled(false); m_panelSizePolicy->setEnabled(false); m_panelAutoHide->setEnabled(false); m_panelLock->setEnabled(false); m_showTaskView->setEnabled(false); m_showPanelOnAllScreens->setEnabled(false); m_showSystemTrayOnAllPanels->setEnabled(false); m_iconsShowedOn->setEnabled(false); m_threeIslandType->setChecked(false); m_threeIslandType->setEnabled(false); m_classicType->setChecked(false); m_classicType->setEnabled(false); m_showSearch->setEnabled(false); QStringList trayIconList = m_systemTrayIconId; for(const QString &id : trayIconList) { removeSystemTrayIcon(id); } } } void PanelUkccPlugin::updateData() { if(m_panelType == GeneralConfigDefine::PanelType::Version4) { m_panelSizePolicy->setCurrentIndex(m_configReplica->panelSizePolicy()); m_panelLocation->setCurrentIndex(m_configReplica->panelLocation()); m_panelAutoHide->setChecked(m_configReplica->panelAutoHide()); m_panelLock->setChecked(m_configReplica->panelLock()); m_panelSizePolicy->setEnabled(!m_configReplica->panelLock()); m_showTaskView->setChecked(!m_configReplica->disabledWidgets().contains(QStringLiteral("org.ukui.panel.taskView"))); m_showSearch->setChecked(!m_configReplica->disabledWidgets().contains(QStringLiteral("org.ukui.panel.search"))); } else { m_panelSizePolicy->setCurrentIndex(m_configReplica->panelSizePolicyNext()); m_panelLocation->setCurrentIndex(m_configReplica->panelLocationNext()); m_panelAutoHide->setChecked(m_configReplica->panelAutoHideNext()); m_panelLock->setChecked(m_configReplica->panelLockNext()); m_panelSizePolicy->setEnabled(!m_configReplica->panelLockNext()); m_showTaskView->setChecked(!m_configReplica->disabledWidgetsNext().contains(QStringLiteral("org.ukui.panel.taskView"))); m_showSearch->setChecked(!m_configReplica->disabledWidgetsNext().contains(QStringLiteral("org.ukui.panel.search"))); m_mergeIcons->setCurrentIndex(GeneralConfigDefine::MergeIcons::Always); } m_mergeIcons->setEnabled(m_panelType == GeneralConfigDefine::PanelType::Version4); m_showSystemTrayOnAllPanels->setEnabled(m_panelType == GeneralConfigDefine::PanelType::Version4); m_panelLocation->setEnabled(!m_configReplica->panelLock() && m_panelType == GeneralConfigDefine::PanelType::Version4); } int PanelUkccPlugin::virtualKeyboardCurrentIndex() { if (m_gsetting && m_gsetting->keys().contains(TRAY_ICON_SHOW_POLICY)) { QString policy = m_gsetting->get(TRAY_ICON_SHOW_POLICY).toString(); if (policy == "NeverShow") return VirtualKeyboardPolicy::NeverShow; if (policy == "AlwaysShow") return VirtualKeyboardPolicy::AlwaysSHow; if (policy == "ShowWhenKeyboardIsConnected") return VirtualKeyboardPolicy::ShowWhenKeyboardIsConnected; } return VirtualKeyboardPolicy::AlwaysSHow; } void PanelUkccPlugin::initFunctionControl() { //管控配置 UkuiQuick::FunctionControl::instance()->addWatch(QStringLiteral("ukui-panel-v11")); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlChanged, this, [this](const QString &name) { onFunctionControlChanged(name, false); }); connect(UkuiQuick::FunctionControl::instance(), &UkuiQuick::FunctionControl::functionControlExit, this, [this]() { onFunctionControlChanged(QStringLiteral("ukui-panel-v11"), true); }); } void PanelUkccPlugin::onFunctionControlChanged(const QString &name, bool exit) { if (name != QStringLiteral("ukui-panel-v11")) { return; } m_controlConfig = exit ? QJsonObject() : UkuiQuick::FunctionControl::instance()->functionControlObject(name).value(name).toObject(); qDebug() << "Panel ukcc plugin function control config:" << m_controlConfig; //panelLocation if (m_controlConfig.contains(QStringLiteral("panelLocation"))) { m_panelLocation->setEnabled(false); } else { m_panelLocation->setEnabled(!m_configReplica->panelLock()); } //panelSizePolicy if (m_controlConfig.contains(QStringLiteral("panelSizePolicy"))) { m_panelSizePolicy->setEnabled(false); } else { m_panelSizePolicy->setEnabled(!m_configReplica->panelLock()); } //panelAutoHide if (m_controlConfig.contains(QStringLiteral("panelAutoHide"))) { m_panelAutoHide->setEnabled(false); } else { m_panelAutoHide->setEnabled(true); } //panelLock if (m_controlConfig.contains(QStringLiteral("panelLock"))) { m_panelLock->setEnabled(false); } else { m_panelLock->setEnabled(true); } //disableWidgets if (m_controlConfig.contains(QStringLiteral("disableWidgets"))) { QStringList disableWidgets; for (QVariant &disableWidget : m_controlConfig.value(QStringLiteral("disableWidgets")).toArray().toVariantList()) { disableWidgets.append(disableWidget.toString()); } m_showTaskView->setEnabled(!disableWidgets.contains(QStringLiteral("org.ukui.panel.taskView"))); m_showSearch->setEnabled(!disableWidgets.contains(QStringLiteral("org.ukui.panel.search"))); } else { m_showTaskView->setEnabled(true); m_showSearch->setEnabled(true); } } void PanelUkccPlugin::onTrayIconsCanInhibitedChanged(const QStringList &trayIconList) { QPair diff = compareStringLists(m_systemTrayIconId, trayIconList); if (!diff.first.isEmpty()) { //added for (const QString &addedId : diff.first) { for (const TrayIconInfo &trayIconInfo : m_systemTrayIconInfo) { if (trayIconInfo.id == addedId && !m_systemTrayIconId.contains(addedId)) { m_systemTrayIconId.append(trayIconInfo.id); auto button = new SwitchButton(m_frame3, trayIconInfo.name, trayIconInfo.iconName); button->setObjectName(trayIconInfo.id); button->setChecked(!m_configReplica->trayIconsInhibited().contains(trayIconInfo.id)); connect(button, &SwitchButton::stateChanged, this, [&, button](bool show){ QStringList icons = m_configReplica->trayIconsInhibited(); if(!show && !icons.contains(button->objectName())) { m_configReplica->setTrayIconsInhibited(icons << button->objectName()); } else if (show && icons.contains(button->objectName())) { icons.removeAll(button->objectName()); m_configReplica->setTrayIconsInhibited(icons); } }); button->setEnabled(true); //每添加一个butonn还要添加一条分割线,索引需要乘2 m_vLayout3->insertWidget(2 * getTrayIconIndex(trayIconInfo), button); m_vLayout3->insertWidget(2 * getTrayIconIndex(trayIconInfo) + 1, setLine(m_frame3)); } } } } if (!diff.second.isEmpty()) { //removed for (const QString &removedId : diff.second) { removeSystemTrayIcon(removedId); } } } QPair PanelUkccPlugin::compareStringLists(const QStringList &oldList, const QStringList &newList) { QSet oldSet = QSet(oldList.begin(), oldList.end()); QSet newSet = QSet(newList.begin(), newList.end()); QSet addedSet = newSet - oldSet; QSet removedSet = oldSet - newSet; return qMakePair(addedSet.values(), removedSet.values()); } int PanelUkccPlugin::getTrayIconIndex(TrayIconInfo info) { int index; for (index = 0; index < m_systemTrayIconInfo.size(); ++index) { if (m_systemTrayIconInfo[index].id == info.id) break; } if (index > m_systemTrayIconId.size() - 1) index = m_systemTrayIconId.size() - 1; return index; } void PanelUkccPlugin::removeSystemTrayIcon(const QString &id) { if (m_systemTrayIconId.contains(id)) { m_systemTrayIconId.removeAll(id); auto button = m_frame3->findChild(id, Qt::FindDirectChildrenOnly); QLayoutItem *line = m_vLayout3->itemAt(m_vLayout3->indexOf(button) + 1); m_vLayout3->removeItem(line); m_vLayout3->removeWidget(button); delete line; delete button; } } ukui-panel/panel/ukcc-plugin/resource/0000775000175000017500000000000015167645100016726 5ustar fengfengukui-panel/panel/ukcc-plugin/resource/island.png0000664000175000017500000003110515167645100020706 0ustar fengfengPNG  IHDRZj sRGBsBIT|d IDATxK,ɑyDdfU׽vnh 064iQ3\qfъfZLf$-hִ1!m3= xy^Up-"*3o0SYy]όT׀ 3?z;n!uTFmUEDm{Qنн1a 8:z|@j¡=҃5ev_$6w_'?{πˀ[1_e>] KꉶBxOTЫԹL*5;b]Eo{L^q{7G([FhvAf.HϽ1BO^h>Z||\Q kϯUu0%_K.t˶ZiOP8xCurLD.a%B36 QODhz~ B]Bsڻ@KvXkI H!=U=vtr ftF_'=]1TmK.-~ǣCztEף>dE(G^PӘedjG9ud oiGMpEz+Qu7Lk#}f W<_[]F =YצEzlcgk׷{ֹ]Ϋ^aɴrjjebg=%d -ڤ!ۍ~\͕&ak˫0#ր2$MX0 1ڻ=ƫ{TUMnizl_f7y>5>?q,O,˧' r1*}KEPV]nl_KZuc ͂qq]=뫃;M5ȺFTdXdž:uzvijG`>^*O\/J;ޫO|:0V#諸o6WuoW;೵Άڷwۋqc$ `>R ҷz}Xe,bߵo!"l<G>_xmut8 !1<Ө{iƤ?l|۳L0}K}|Xct1ۏ{̤]8l1 v%o{ݵߎ|9>Z_>,↓`;W͕reo-w}K>i]?clH11=%l{ l3XƸn/ntMu~ڍ[ưݾ17c:%fGs׽tOm큼qpqWوࡎ=0*|l]ql8:ck-t?dƈ'#/=9Qz% tNj Ht[6~{: ]z*ރu nqNb-[$Uty 11&YWU6+o,)kj=x̐퍞&Ҷ3BtM]1&Nh(B ]/!m)'Prց͙>tז 1MOXUڢqK({;M\njAlLc.7 N:D7zG1v}Ǹ.8%e˦8兙cyz -ux$R Dsxǵq=G]{qHa4vHnctkt:MR6z~;VPkjej̎ij0(kbE;}՛|{Y~mr&4@i$ X_ koʊIN+t[܊-VZXI^+4{CqNZN@/ְcVϵ;;YXiҰ2XA`uhϡ̶>8Sa%/\=eWᷱ/6Wl5pIdz-tCuEZե51`IOrJ*O:5Nۮk?Jr-I .چBVx[cd_tx5U?~UqT]=: W' *9kd-kcՖv}Fc]ᨺ1lo״ AwghK ^aBʸ6l&"5ܸ1v $kyLWtf=U}, 9Y<>%~ԑՙcpB::5 'RYB=aʎ:eꌂC{I;w嶎]n }vW[Ew9z1_ً|:zGv2zO>8ۏ8k9YWI1ECɬQɩ{1nu7pyىG(2?v}x|y9/ /ne]DLo1UYs,+d1!xO5/)a8#;_nκ+GXTl -^.WF<ܖȗnOɔ&Qgßs'wy0s<0v4ڛv=Xy9UVIlnÎ-T{(\FGk6&81 'w[wr)קScAb S,GߠF01>Y/%T53ٻjcK[IXa~ ]YQx:[hm'[Wtȧ1"$[l~ݭc]fHCIlT[#Uma0$ o=LOXd$~bCB=Ku/>nM-qd+=aUu?gg%o?8cb-hqG>a{ܹuWo9;Ĝa.2 2)+4/,CChHDs}}FХG%c-FBM#Z(ezlƻ~B^Ar2Ǟ^^i6\ 覧5ŚG{]_*Wp;/edD"lkjE6fE&X;@+Dc!*^KSBI>d/Ak̲4 T RW0.@zFΙN:,ǟΉeaʀTZ70XāƈEP9]_D҆X __:#0 u\{3:BdΥ:uP+@T%Q,(P' N l&4b؟ˆ0b$TqdoFljbL9͙LlB5G)~W8EUcs44Sm֡ bf?TsϵoB>;<<+L+ncպBmR {Gs|q6XbM/j NYʓ2p #Bvk)r;#V Pt0h3V6I`Q.'#dFh%GeD x_{R7dmbpGqp@SVH ֒O bMHa"O'4tt6%S?yro],+O^˻_~'{+G>zq[+U#.т:>bňPgP,m%-G*p37LQ^n)r3/ycBֶ뀳"!B&)do ~,$TQ:$x"1=1`󴓭! %f1,G( C :J]6x`XV52ك7 nZ!bˊXtB(L',E>D "x6FHį~ś{tޫw2,xGo,|+yC7*՜|pbH4 ;PkTRJ ΤMrT(NEק {:GG5Yb X4j::1fd*DbӠMk1Q.}-WSXj14 1: O:Uj<#obĺIMn"G 4!ՒZ!>Sp>EDi0c䰿~7bG%^8Ƽr3ۿ+',n# uofUO.4ɂӋ'i=tܲʹ+80~Sf!7`^{ EwC7\.14b"20X u dΰ4?clY."g츴L Ȣ,2tA%gA,j  j2 &\ʈ L~m,&4ZU>$o J$/Ǩhi/cĠN曱p|Cp~'O| W^;8[2q#x&x~UWe%ڐB>27<;)Z)hόI&"XbKKF43L Hȭ}Ly(#YBk\s+C]"d9vȭ#yFY\8Y*-vi$Q5hϞ&wܧ`-2|1>&!FB~aQ&^e9%OeBԀ{iil*"Qus"Yβh2n $K)1 &GLftvGC.TEMXaMF$*X5p , q`(4A@]z*ڤلݣ@R $xxxAh*g/YS&c En3ut ue} F0"X14M`('.Rܫa(Gyzȭˀ3ݣ􁛇Se0V؟8\RD6ꃒI65Y]cRbT*hk+)h2EM!f9 BDbPy|SЯl>@u"L bIX놦UQQ&Ide?_R0׿ Y9l4`clPXd9˘{"a;noe(+ɒ'e/#a]T,z1:6b֦ȝCH#ϯkوU s%0E44^Eٟfm5=ed)|$Zi*h)A ܾF@|^#{$ G#P5א@M=56;M,)_XiYIqk 2bn\''94śh Bأ=kQ9r*㨋|t3p7>$o`o嗯@ 9%ѷ_-"`$“%c=k쬤t)ňja e)Kr^,EfJbJ u&ѥS!MWyb'x&`"DcMoO$ORbi*L&6<(L{[p$0Ĕ.-F, 4̮QܸFq0cK/$T6'o3ylroJpe*Uf%7ɾisE'R,t4`LS\CnLJyyIvCb+8FSjIl-O<\6/&0Mʻu.]l /%(KBftMw2b^M*S{&`ߐ!6PV!֞Ԩ(H) ;${k$d$D>ÃHY@Uݯ5d;7:-+ޣ9'x/} H:Zjz`~SY$ .i4xCVyj_X6F8qj\8ܰ) MR틆"@ bXOyƋ':PG(dXkVPHŜ0_"%jobӍ! >%NBKEf$zM<_(l563iA^dLp;isep]-U. [O_W omk];wSמYْĘ6|)4q"ְ\xWP>-yvQd >P,KpcbĔeݭ<: )RmAh#QR!\ݬL2xd,ӢHEA"ceh&ԁ!R)5d0sF#Ԟa5f$^O/%N _0;R<«r_:5M6[,`2ůe&w 4yT2ѱx 93?/H1y=b )r5{\e5_viw1} @A c-8KX$ԙd$#I+aV}ZȓL'bKـ_)UHX0FkqELr#\x"tx|D' !s̱2ol]r~oHB!]_' ,%yJZcV3-RMuX:`SW!<)̦n\-g v~nZd]Rm_:P0!U9gM4]k(f9T]KEIT{K%'fȞrZ<{ +/L [zX<`c0{ >8񑠒'4ˈ&C}&b哷e fV,yV6mSTXa^$!Ĕ[l9l#SU&:䳰:E6xE`>*kړΨwmmm`P7틕QR^kg?yrVƯs2+|>׿IjK^4KBA2$.du{wjOn!EtzRA8e-nNIOtͯq6O:G{k/ħi*;QM{Ur2ho4hNpHBR' +A龻~ \i\#a=|N-#]_.-|ŧ+X>"lUC·_އ>&vU$ᵗoK7uy` 돎>ݽ(B$.OgVבd=ݽ'~aلo<^IVKS''[oNh6)>FnM_)Mfŵ#p/:$U===4:5ٶ ]&,W)>7>u-MxI(Bc eF+ GɪHhRQk%$- :٦p? lNO㾶-ç[Vo鬆tX7 Ei[+cof=Bװj-~_Vp>*>@g]ŁwB@X:!\ufp[":*UG2,?203bH/4Nm<v [p;Cۄ4[]v*9ɭbmSnlvEFw:5-}1L JۗiYVm 30*.BmzJpG&Q+>[ụ~(TR;<$ˣzos)Jқ̮;͆-k-FѶ>q~zI7> BҴՌp}m#p>1C:G_.>vkMrwWdd~|joGѾ?z۵ʮ{W+ ǧ[9/|<|\/ }V8\Ow{~]q L|')"|=]V>o:7"A USˁV5<(ON mfxV>;}̰H wl;.s+?>|+oN;`GG`0쟄&{ljDE )Lˇ~&αKKgenEK7D2| /aWIENDB`ukui-panel/panel/ukcc-plugin/resource/res.qrc0000664000175000017500000000017215167645100020226 0ustar fengfeng classic.png island.png ukui-panel/panel/ukcc-plugin/resource/classic.png0000664000175000017500000003146015167645100021061 0ustar fengfengPNG  IHDRZj sRGBsBIT|d IDATxݓeGr˪:{{z ,~i.% [bТ=Y#EgY!3L)HܥvW~ 0`C{X.(bpSuZh˟k![+%#71o,kThzJ_OR{TpTȴ6Ei}8ƞ=\g N߽:pn5vozW^sg^Hƻl˾q}I;Vh?=OƪcU}{,t\.*O* sђ2h|ϋ礪{ɤ壾^Flc轓'ྼ{x`>>{xcbexd9ɤ^c[;{A(` KڱۃL2 XEwWG ΗᓍѦwW^$v.Ļ;¾<7{_];-/sٍ3541~^nmZLq۞M7s.\(&߻.>6u1N~r| xN` =/Kc3 M81k&>5 `8}o\VvQؿEI2Ƅ'/=9Qz+K46 h;c~: ]F* nуuF ]ٴg'\q=*i<ˬ}8MO-eQcV4cueс3x'nh(B L]/[CRNFm ݕVm;`=SH٘:iGhPvZ)uûN[Ƌ9̥*윋`Ct$7nLeNggwyk]4mEI|M1sGzW྇.u!5 ԍ[Cޞð-Nҙ y>|:K̵}ѽ}Enf^/^㣛S&ިyG5"Ҭ*sjͬ!d(_=|T#z޶;sۅOPe_42zl[.מw՟JMA2r{:ɞ[5w{٦p${UI {ہE ȝfx/l;pZee_K5ؒ;㥑+}nI䋷flN (3>so;qSeG@5p9Ksux/~F|ްK25hxUQ\DU*aMKmM˂dV inM_ڍQ B.>?0v>۶&2:n{ #?pv<43l6 +Os{UW _QMUoXX~x5ߐ5%F En BpD,Z0"_92|TGvAf6v qiҞLٶ ߝTnoAto x-2}7FbxNmé;оèsՏ-=ɏ?bt @4ºl'1G+n-rДPgAn@#9w۲yU0904]D.Bvpg41ZG׎Q>i<,1m7x_r0.jd{Rq2:]Z'qRӣ?i=fu^r'Yha@>VUKY=WjhO<(h1#uxPg/y|7=d @h0$;U.r9 jpoZ,*dD!.=nS' c]LTޘ+1ʲλWxa1dniʃ-=8A3Sv/;t"- 1R}ȓ+ X"AcÏd&׮ss+Y10cωaC,\?W*f>j9nb@ٔHAPh WsqXQc|L23 ˸L]ly(]($w2tqo!Xi 'be<®,8gg%14`r8ˣzCn<+7 ^ \a U|bh!HT4$"o #xXm"Ds(F%bq|0[ߣPW<_aO7n4ݶy1дHϘ_㭲!~޲+f$鬩=Sf1=z񪐖ҝ&XewsB "1yɫ:~mA(Wl"hTAbB25QOԈ0Cg X;LBf98QUHs*611#'Ɯ}f g#g<3Ğm.rim6Az9ɀG> hwV̓{O> maXn0y~y|?ok <`JŚ+LY *$DlLb#UC\0yH)ֈ=V¬@C"`b4 ?+a>C`-FZkOtOKQ3 ֲ#h2+xLϞLK BwQڎlm!ٶU ~k*H{fjNIɣ%F п"'D(Vw1Ƿ?w*- CCDMsጰހ(x?C|1a/a2;6/}:=f.Ҷ2&%:G2$  f]H6/GbP(n6@]jb^MMDcVh2mz]<=G`f3Ǹ7n"7O;GnFLZU,Fh,H@`,4X>=#ܯ9g5&Պsz5F篓wG#G?GyH_g \v(nK /Y|G|9a2GhDL2KC􊱆o|_έC7 b@gEZ+!f Lݠ kLe6J4d9E}@EJ;B\VZ,! QhS'+xM KͲ?<=淮GGpP 5tM^17jEu)nSsx$|^`-̫Z+ܪ=_"S5re?+rV^_/\xZZ<}?}$j !x@TGjLb(3֗/.⌴JE0]1bfkb09V 4\`ZP9 Cbrb|DRX!5zp?_T~ 19Xu< Up7)BnihklY6lHyǯW?_UP7(a{O&f 1.\P沣};_}!b`g3BT8t (֠&(.Dkwo8;52y{Xz|A"q1[GsԹV.j$%2LZA=1:w X!`3 UE<\0;XSNs&9s,Qgw*R+ZȺLQ骁1-6P 13F7ޤ8Jog<8!'_{WN0oauC/s7cuKLߜဧ}KTFyd ߴgI^ Sfynfڈq)`hfF9 J8ֵgZ\&14b"20Y u dΰ1=t\D4>3iqK u4d*PK4 1CEqYNU5P *4dgMF>' dhUGyn\DprHg9F d ܺ'Ǭ?+9o?;q<|!sgf3={opѯcb]+\rpBժժN̘dh"Um/.&ĺd3 aP4AQ/Gh 7+1s2 $4 . .yr.8H[cʃ4p&Z!zZ4R4k~b֒e9WVwr'Ϲ_%.7ۜ~tg?e~}[|h9k1uIu2 #!D˚{)%TT 1Yfɭ2˄yƢH(ssWg, ˓RIDATYB$sx#?- f{7st|O<< [w?pr`>ȬkMUfª f"kjLd &Vk2_7 !bYQd?BVPeA sRJO27%iBAlN#J )CT9599ͦpC~8K>3NEA<8zOV-7u Kz{:Wp% %G6t'moۑBԕ=2l1-n,sˁSNe+3,sX 6eeյn`#OWˆbyZx<9ohBb|& g '0J Hv R heD5lMsb|5 !bƍ/ߡ}]TJr6EF|0uCn qU"M Tp02cv)71Dm oRPѲ4>]%k ThuITrMޒE&;K'7k!{SU޼•?{_!7Dh9ul÷nܾ7B_Οg# io6oxtou>bU bp@c$!3a&\)7 #GkOTR^9q0΍Yk0K CLIN$Ud-;L,Z7.4>t)ց ƦڣQC xMQѐ k 1lʊ=^CZN)Kx|V}VRt!׈" ;71 YN6ϸ "*ǔy8"|tpanzuMIAAo\ղeI=(D#xc(dGj^?RtuƺR9b5SXms3)1el]iEZ?!P`V]5"Dop'ցxbi&H4tP i@M$+QjbSaȃtEA\ϟu`ňacW)|񕤙ՍV7n^P nyɛ_U$}o_jzIM+f>Ib㤛l7o]C|,K%N{; M &X~sɒozչ|P7YnRޭs-rec@jV.uI<gmch-fmU)ڣu 4S5xdD"4 F}FA%]@LXW,C^#!3H$!1e]CyA`g3f&q ŵClY!!՛<~uVW MA%~>I ]r8zipCzXBe2d(`<+ARx)Qp̬* |ab-+ gf1)*to"E^A@ l[2ОtG3lhgGX=|"ݛ9CݒDa^mJO 3_ ␣G&^ˊ&`gJ{̉iH wXVH0"%|KZڄP{B=6}ꐲla1yNЧhīpXBRimizޣ.~叒z HibG:jmi=w7 I4JٷtONF:$85a5.$A3 w m?c yN{}XL2bPլ1e?*[`դM艇I7.h n9f>K1&4*,a2 /ĖMX:Gٺ۲v[netS؄R6<Y>p,wYx?D'?F•w@t<ڮ2%~߇kCA~wnYi1}w:J4.zÔ^RB>q'/{g_ʼnn4o%Btڨ{!E/<2Cm N잍s[Qx ͯZlRoݽ@нBdn zi6]S io9%fG|Z(6w<#!TnAH@=/d;!Qo V-Uu g=ލ;Bj =²Wˌ>Y#K',j!IS2 D#A,G6teb&w'1 5ok;iUAXXH$bP lc#!:A\.޿+2zx!#^4eMc c1ČFTҶWuv&|ZsTh7֓exfI2`7fS埬H)D""Y]x:PANEL_DISABLE_LOG_FILE>) target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:QT_QML_DEBUG>) set(PANEL_TRANSLATION_DIR "/usr/share/ukui-panel/translations/") add_compile_definitions(PANEL_TRANSLATION_DIR="${PANEL_TRANSLATION_DIR}") target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::RemoteObjects KF${QT_VERSION_MAJOR}::WindowSystem qtsingleapplication ${UKUI_PANEL_EXTERNAL_LIBS} ukui-quick::framework ukui-quick::core ukui-quick::platform ${GLIB_LIBRARIES} ) add_subdirectory(ukcc-plugin) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "/usr/bin") install(FILES ${QM_FILES} DESTINATION "${PANEL_TRANSLATION_DIR}") install(FILES ukui-panel.desktop DESTINATION /etc/xdg/autostart) install(FILES data/org.ukui.panel.settings.gschema.xml DESTINATION "/usr/share/glib-2.0/schemas") if(BUILD_TEST) add_subdirectory(autotest) endif() ukui-panel/panel/autotest/0000775000175000017500000000000015167645100014526 5ustar fengfengukui-panel/panel/autotest/CMakeLists.txt0000664000175000017500000000110215167645100017260 0ustar fengfengset(CMAKE_AUTOMOC on) find_package(QT NAMES Qt6 Qt5 COMPONENTS Test Gui REQUIRED) find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} CONFIG REQUIRED Test Gui) remove_definitions(-DQT_NO_CAST_FROM_ASCII) include_directories(..) add_executable(screenManagerTest screen-manager-test.cpp ../src/screens-manager.cpp) target_link_libraries(screenManagerTest PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Test Qt${QT_VERSION_MAJOR}::Gui ) add_test(screenManagerTest ${CMAKE_BINARY_DIR}/autotests/screenManagerTest) ukui-panel/panel/autotest/screen-manager-test.h0000664000175000017500000000171615167645100020550 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #ifndef SCREEN_MANAGER_TEST_H #define SCREEN_MANAGER_TEST_H #include class ScreenManagerTest : public QObject { Q_OBJECT private Q_SLOTS: void testPrimaryScreen(); }; #endif //SCREEN_MANAGER_TEST_H ukui-panel/panel/autotest/screen-manager-test.cpp0000664000175000017500000000207115167645100021076 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ #include "screen-manager-test.h" #include #include #include "screens-manager.h" void ScreenManagerTest::testPrimaryScreen() { auto primaryScreen = UkuiPanel::ScreensManager().primaryScreen(); QCOMPARE(primaryScreen->internal(), QGuiApplication::primaryScreen()); } QTEST_MAIN(ScreenManagerTest)ukui-panel/panel/qml/0000775000175000017500000000000015167645100013447 5ustar fengfengukui-panel/panel/qml/IslandDragControlRod.qml0000664000175000017500000001006615167645100020203 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.quick.container 1.0 import org.ukui.panel.shell 1.0 MouseArea { id: root width: height * 16 / 56 //默认比例 hoverEnabled: true property Item targetIsland: null property string container: "panel" property bool dragToPanel: true Drag.dragType: Drag.Automatic Drag.supportedActions: Qt.CopyAction drag.target: root Drag.mimeData: { "Id": targetIsland.WidgetContainer.id } ContentWindow { id: islandDropArea screen: targetIsland.WidgetContainer.screen position: Types.Bottom useAvailableGeometry: false flags: Qt.Window | Qt.WindowDoesNotAcceptFocus | Qt.FramelessWindowHint windowType: WindowType.SystemWindow visible: root.Drag.active enableBlurEffect: false DropArea { id: dropArea width: targetIsland.WidgetContainer.screen.size.width height: targetIsland.WidgetContainer.screen.size.height onPositionChanged: (dragEvent) =>{ root.dragToPanel = dragEvent.y > height / 2; if(root.container === "panel") { IslandDragHelper.IslandDragRemovingFromPanel(!dragToPanel); } else if(root.container === "topBar") { IslandDragHelper.IslandDragRemovingFromTopBar(dragToPanel); } } } } onPressed: { Drag.hotSpot = mapToItem(targetIsland, mouse.x, mouse.y) dragImageSource.sourceItem = targetIsland; dragImageSource.grabToImage(function (result) { Drag.imageSource = result.url; dragImageSource.sourceItem = null; }); } drag.onActiveChanged: { if(drag.active) { backgroundBase.visible = false; IslandDragHelper.draggingIsland = root.targetIsland.WidgetContainer.id; Drag.active = drag.active; IslandDragHelper.dragging = drag.active; } else { Drag.active = drag.active; IslandDragHelper.dragging = drag.active; if(root.container === "panel" &&!root.dragToPanel ) { IslandDragHelper.IslandDragRemoveFromPanel(root.targetIsland.WidgetContainer.id); } else if(root.container === "topBar" && root.dragToPanel) { IslandDragHelper.IslandDragRemoveFromTopBar(root.targetIsland.WidgetContainer.id); } IslandDragHelper.draggingIsland = ""; } } onContainsMouseChanged: { backgroundBase.visible = containsMouse } Component.onCompleted: { backgroundBase.visible = containsMouse? !drag.active : false; } ShaderEffectSource { id: dragImageSource width: targetIsland.width height: targetIsland.height sourceItem: null visible: false; } DtThemeBackground { id: backgroundBase anchors.fill: parent backgroundColor: GlobalTheme.windowActive useStyleTransparency: false Icon { id: iconBase anchors.centerIn: parent rotation: 90 mode: Icon.AutoHighlight source: "open-menu-symbolic" width: parent.width * 0.75 height: parent.width * 0.75 } } } ukui-panel/panel/qml/org.ukui.panelNext/0000775000175000017500000000000015167645100017147 5ustar fengfengukui-panel/panel/qml/org.ukui.panelNext/ui/0000775000175000017500000000000015167645100017564 5ustar fengfengukui-panel/panel/qml/org.ukui.panelNext/ui/MainContainer.qml0000664000175000017500000002266715167645100023043 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQml 2.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.impl 1.0 as Panel import org.ukui.panel.shell 1.0 WidgetContainerItem { id: containerItem property int orientation: WidgetContainer.orientation property bool isHorizontal: orientation === Types.Horizontal onParentChanged: { anchors.fill = parent } Item { id: backGround anchors.horizontalCenter: parent.horizontalCenter height: parent.height - anchors.topMargin - anchors.bottomMargin anchors { leftMargin: containerItem.WidgetContainer.margin.left topMargin: containerItem.WidgetContainer.margin.top rightMargin: containerItem.WidgetContainer.margin.right bottomMargin: containerItem.WidgetContainer.margin.bottom } Binding on width { value: { if(mainLayout.fillWidth) { return parent.width - containerItem.WidgetContainer.margin.left - containerItem.WidgetContainer.margin.right } else { return Math.max(1, (mainLayout.dataIslandWidth + mainLayout.settingsIslandWidth + mainLayout.appIslandWidth + mainLayout.columnSpacing * (repeater.count - 1))) } } delayed: true; } MouseArea { x: mainLayout.x; y: mainLayout.y width: mainLayout.width; height: mainLayout.height hoverEnabled: panelNext.enableCustomSize enabled: !panelNext.lockPanel property bool resizing: false onResizingChanged: { if (!resizing) { panelNext.endResizeCustomPanelSize(); } } onPositionChanged: (event) => { if (!pressed) { // 悬浮状态,切换鼠标样式 if (containsMouse) { let cursor = (event.y < 2) ? "SizeVerCursor" : ""; panelNext.changeCursor(cursor); } } } onReleased: { panelNext.changeCursor(""); resizing = false; } onExited: { if (!pressed) { panelNext.changeCursor(""); } resizing = false; } onPressed: (event) => { let cursor = (event.y < 2) ? "SizeVerCursor" : ""; if ((cursor !== "") && panelNext.enableCustomSize) { resizing = true; panelNext.startResizeCustomPanelSize(Qt.TopEdge); } } } GridLayout { id: mainLayout property int dataIslandWidth: 0 property int settingsIslandWidth: 0 property int appIslandWidth: 0 property bool fillWidth: false property double ratio: 1 Binding { target: mainLayout property: "ratio" value: Math.max(Math.min(backGround.height / WidgetContainer.config.panelDefaultSize, 1.43), 0.85) delayed: true } Component.onCompleted: { fillWidth = Qt.binding(function () { for (var i = 0; i < repeater.count; i++) { if (repeater.itemAt(i).Layout.fillWidth) { return true; } } return false }); } z: 10 anchors.fill: parent anchors { leftMargin: 0 topMargin: 4 * ratio rightMargin: 0 bottomMargin: 4 * ratio } rows: containerItem.isHorizontal ? 1 : repeater.count columns: containerItem.isHorizontal ? repeater.count : 1 rowSpacing: 8 * ratio columnSpacing: 8 * ratio Repeater { id: repeater model: Panel.WidgetSortModel { widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } onWidthChanged: { blurRegionHelper.requestUpdate() panelNext.setPanelLength(width) } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true property int index: model.index property Item widgetItem: model.widgetItem property double ratio: mainLayout.ratio property string containerType: "panel" property string type: "" Layout.fillWidth: widgetItem.fillWidth Layout.fillHeight: true Layout.minimumHeight: backGround.height; Layout.maximumHeight: backGround.height; Layout.minimumWidth : widgetItem.WidgetContainer.config.minimumWidth * ratio Layout.maximumWidth : (widgetItem.WidgetContainer.config.type === "app") ? (containerItem.width - mainLayout.settingsIslandWidth - mainLayout.dataIslandWidth - mainLayout.columnSpacing * (repeater.count -1)) : widgetItem.WidgetContainer.config.maximumWidth * ratio Layout.preferredHeight: mainLayout.height Layout.preferredWidth: { const type = widgetItem.WidgetContainer.config.type if(type === "data") { return mainLayout.dataIslandWidth; } else if(type === "settings") { return mainLayout.settingsIslandWidth } else { return mainLayout.appIslandWidth; } } onWidgetItemChanged: { type = widgetItem.WidgetContainer.config.type if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = Qt.binding(function () {return widgetParent}) if(type === "data") { mainLayout.dataIslandWidth = Qt.binding(function () {return widgetItem.widgetsWidth;}); } if(type === "settings") { mainLayout.settingsIslandWidth = Qt.binding(function () {return widgetItem.widgetsWidth;}) } if(type === "app") { mainLayout.appIslandWidth = Qt.binding(function () { return widgetItem.Layout.preferredWidth; }) } } } Component.onDestruction: { if(type === "data") { mainLayout.dataIslandWidth = 0; } if(type === "settings") { mainLayout.settingsIslandWidth = 0; } } opacity: { if (IslandDragHelper.draggingIsland === widgetItem.WidgetContainer.id && IslandDragHelper.dragging && !IslandDragHelper.islandPendingAdd2Panel) { blurRegionHelper.removeItem(widgetParent); return 0; } else { blurRegionHelper.addItem(widgetParent, GlobalTheme.kRadiusWindow * ratio); return 1; } } Component.onCompleted: { blurRegionHelper.addItem(widgetParent, GlobalTheme.kRadiusWindow * ratio); widgetParent.onRatioChanged.connect(function () {blurRegionHelper.addItem(widgetParent, GlobalTheme.kRadiusWindow * ratio);}) } onXChanged: { blurRegionHelper.requestUpdate(widgetParent) } onYChanged: { blurRegionHelper.requestUpdate(widgetParent) } onWidthChanged: { blurRegionHelper.requestUpdate(widgetParent) } onHeightChanged: { blurRegionHelper.requestUpdate(widgetParent) } } } } } ukui-panel/panel/qml/org.ukui.panelNext/metadata.json0000664000175000017500000000114015167645100021616 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.panelNext", "Icon": "ukui-panel", "Name": "ukui-panel", "Name[zh_CN]": "任务栏面板", "Tooltip": "Common taskbar panel", "Tooltip[zh_CN]": "普通任务栏面板", "Description": "Common taskbar panel", "Description[zh_CN]": "普通任务栏面板", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "WidgetType": "Container", "Contents": { "Main": "ui/MainContainer.qml" } } ukui-panel/panel/qml/org.ukui.dataIsland/0000775000175000017500000000000015167645100017255 5ustar fengfengukui-panel/panel/qml/org.ukui.dataIsland/ui/0000775000175000017500000000000015167645111017674 5ustar fengfengukui-panel/panel/qml/org.ukui.dataIsland/ui/DataIsland.qml0000664000175000017500000001222315167645111022413 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQml 2.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.impl 1.0 as Panel import org.ukui.panel.shell 1.0 import Qt5Compat.GraphicalEffects import "../../" WidgetContainerItem { id: containerItem property bool isHorizontal: WidgetContainer.orientation === Types.Horizontal property int widgetsWidth : controlRod.width + mainLayout.childrenRect.width + mainLayout.anchors.leftMargin + mainLayout.anchors.rightMargin property int widgetsHeight: mainLayout.height property double ratio: parent.ratio ? parent.ratio : 1 property bool isMiniLayout: isHorizontal && (height <= 36) property bool fillWidth: false property string containerType: parent.containerType Component.onCompleted: { fillWidth = Qt.binding(function (){ for (var i = 0; i < repeater.count; i++) { if(repeater.itemAt(i).Layout.fillWidth) { return true; } } return false }); } WidgetContainer.active: IslandDragHelper.dragging; DtThemeBackground { id: backGround property double ratio: containerItem.ratio Binding on width { value: parent.width delayed: true; } height: parent.height borderColor: GlobalTheme.buttonTextActive borderAlpha: 0.25 border.width: containerItem.containerType === "panel"? 1 : 0 radius: containerItem.containerType === "panel" ? GlobalTheme.kRadiusWindow * ratio : 0 layer.enabled: true; layer.effect: OpacityMask { maskSource: Rectangle { width: backGround.width height: backGround.height; radius: backGround.radius; } } IslandDragControlRod { id: controlRod height: parent.height anchors.left: parent.left anchors.top: parent.top targetIsland: containerItem container: containerItem.containerType } GridLayout { id: mainLayout z: 10 height: parent.height anchors.left: controlRod.right anchors { leftMargin: 0 topMargin: 0 rightMargin: 16 * backGround.ratio bottomMargin: 0 } rows: containerItem.isHorizontal ? 1 : repeater.count columns: containerItem.isHorizontal ? repeater.count : 1 rowSpacing: isMiniLayout ? 8 * backGround.ratio : 16 * backGround.ratio columnSpacing: isMiniLayout ? 8 * backGround.ratio : 16 * backGround.ratio opacity: controlRod.Drag.active ? 0 : IslandDragHelper.dragging && IslandDragHelper.draggingIsland === WidgetContainer.id ? 0 : 1 Repeater { id: repeater model: Panel.WidgetSortModel { // TODO: use config widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true property double ratio: backGround.ratio property int index: model.index property Item widgetItem: model.widgetItem Layout.fillWidth: widgetItem.Layout.fillWidth Layout.fillHeight: widgetItem.Layout.fillHeight Layout.minimumWidth: widgetItem.Layout.minimumWidth Layout.minimumHeight: widgetItem.Layout.minimumHeight Layout.maximumWidth: widgetItem.Layout.maximumWidth Layout.maximumHeight: widgetItem.Layout.maximumHeight Layout.preferredWidth: widgetItem.Layout.preferredWidth Layout.preferredHeight: mainLayout.height Layout.alignment: Qt.AlignLeft onWidgetItemChanged: { if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = widgetParent } } } } } } ukui-panel/panel/qml/org.ukui.dataIsland/metadata.json0000664000175000017500000000105615167645100021732 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.dataIsland", "Icon": "ukui-panel", "Name": "ukui-panel", "Name[zh_CN]": "数据岛", "Tooltip": "Data island", "Tooltip[zh_CN]": "数据岛", "Description": "Data island", "Description[zh_CN]": "数据岛", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "WidgetType": "Container", "Contents": { "Main": "ui/DataIsland.qml" } } ukui-panel/panel/qml/org.ukui.settingsIsland/0000775000175000017500000000000015167645100020204 5ustar fengfengukui-panel/panel/qml/org.ukui.settingsIsland/ui/0000775000175000017500000000000015167645111020623 5ustar fengfengukui-panel/panel/qml/org.ukui.settingsIsland/ui/SettingsIsland.qml0000664000175000017500000001327015167645111024274 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.impl 1.0 as Panel import org.ukui.panel.shell 1.0 import Qt5Compat.GraphicalEffects import "../../" WidgetContainerItem { id: containerItem property int orientation: WidgetContainer.orientation property bool isHorizontal: orientation === Types.Horizontal property bool fillWidth: false property double ratio: parent.ratio ? parent.ratio : 1 property bool isMiniLayout: isHorizontal && (height <= 36) property int widgetsWidth : controlRod.width + mainLayout.childrenRect.width + mainLayout.anchors.leftMargin + mainLayout.anchors.rightMargin property int widgetsHeight: mainLayout.height property string containerType: parent.containerType property int trayAreaMaxLength: containerItem.WidgetContainer.screen === null ? 0 : containerItem.WidgetContainer.screen.size.width * 0.27 property int systemTrayLength: Math.max(0, trayAreaMaxLength - calendarLength) property int calendarLength: 0 Component.onCompleted: { fillWidth = Qt.binding(function (){ for (var i = 0; i < repeater.count; i++) { if(repeater.itemAt(i).Layout.fillWidth) { return true; } } return false }); } WidgetContainer.active: IslandDragHelper.dragging; DtThemeBackground { id: backGround Binding on width { value: parent.width delayed: true; } height: parent.height borderColor: GlobalTheme.buttonTextActive borderAlpha: 0.25 border.width: containerItem.containerType === "panel"? 1 : 0 radius: containerItem.containerType === "panel" ? GlobalTheme.kRadiusWindow * ratio: 0 layer.enabled: true; layer.effect: OpacityMask { maskSource: Rectangle { width: backGround.width height: backGround.height; radius: backGround.radius; } } IslandDragControlRod { id: controlRod height: parent.height anchors.right: parent.right anchors.top: parent.top targetIsland: containerItem container: containerItem.containerType } GridLayout { id: mainLayout z: 10 // anchors.fill: parent height: parent.height anchors { leftMargin: 8 * ratio topMargin: 0 rightMargin: 0 bottomMargin: 0 } anchors.right: controlRod.left rows: containerItem.isHorizontal ? 1 : repeater.count columns: containerItem.isHorizontal ? repeater.count : 1 rowSpacing: isMiniLayout ? 6 * ratio : 4 * ratio columnSpacing: isMiniLayout ? 6 * ratio : 4 * ratio opacity: controlRod.Drag.active ? 0 : IslandDragHelper.dragging && IslandDragHelper.draggingIsland === WidgetContainer.id ? 0 : 1 Repeater { id: repeater model: Panel.WidgetSortModel { // TODO: use config widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true property double ratio: containerItem.ratio property int index: model.index property Item widgetItem: model.widgetItem property string itemId: widgetItem.Widget.id Layout.fillWidth: widgetItem.Layout.fillWidth Layout.fillHeight: widgetItem.Layout.fillHeight Layout.minimumWidth: widgetItem.Layout.minimumWidth Layout.minimumHeight: widgetItem.Layout.minimumHeight Layout.preferredWidth: widgetItem.Layout.preferredWidth Layout.preferredHeight: widgetItem.Layout.preferredHeight Layout.maximumWidth: itemId === "org.ukui.systemTray" ? containerItem.systemTrayLength : widgetItem.Layout.maximumWidth Layout.maximumHeight: widgetItem.Layout.maximumHeight; onWidgetItemChanged: { if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = widgetParent } if (itemId === "org.ukui.panel.calendar") { containerItem.calendarLength = Qt.binding(function(){ return width; }) } } } } } } ukui-panel/panel/qml/org.ukui.settingsIsland/metadata.json0000664000175000017500000000107615167645100022663 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.settingsIsland", "Icon": "ukui-panel", "Name": "ukui-panel", "Name[zh_CN]": "配置岛", "Tooltip": "Settings island", "Tooltip[zh_CN]": "配置岛", "Description": "Settings island", "Description[zh_CN]": "配置岛", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "WidgetType": "Container", "Contents": { "Main": "ui/SettingsIsland.qml" } } ukui-panel/panel/qml/org.ukui.panelTopBar/0000775000175000017500000000000015167645100017420 5ustar fengfengukui-panel/panel/qml/org.ukui.panelTopBar/ui/0000775000175000017500000000000015167645100020035 5ustar fengfengukui-panel/panel/qml/org.ukui.panelTopBar/ui/PanelTopBarContainer.qml0000664000175000017500000001035015167645100024561 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.impl 1.0 as Panel WidgetContainerItem { id: containerItem property int orientation: WidgetContainer.orientation property bool isHorizontal: orientation === Types.Horizontal onParentChanged: { anchors.fill = parent } Item { id: backGround anchors.fill: parent anchors { leftMargin: containerItem.WidgetContainer.margin.left topMargin: containerItem.WidgetContainer.margin.top rightMargin: containerItem.WidgetContainer.margin.right bottomMargin: containerItem.WidgetContainer.margin.bottom } RowLayout { id: mainLayout z: 10 anchors.fill: parent property int settingsIslandWidth: (repeater.count === 1) ? mainLayout.width : mainLayout.width * 0.6 property int dataIslandWidth: (repeater.count === 1) ? mainLayout.width : mainLayout.width * 0.4 spacing: 0 Repeater { id: repeater model: Panel.WidgetSortModel { widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true property int index: model.index property Item widgetItem: model.widgetItem property double ratio: 1 property string containerType: "topBar" Layout.fillWidth: true Layout.fillHeight: true Layout.minimumHeight: mainLayout.height Layout.maximumHeight: mainLayout.height Layout.minimumWidth: { const type = widgetItem.WidgetContainer.id if(type === "org.ukui.dataIsland") { return mainLayout.dataIslandWidth; } else if (type === "org.ukui.settingsIsland") { return mainLayout.settingsIslandWidth; } } Layout.maximumWidth: { const type = widgetItem.WidgetContainer.id if(type === "org.ukui.dataIsland") { return mainLayout.dataIslandWidth; } else if (type === "org.ukui.settingsIsland") { return mainLayout.settingsIslandWidth; } } Layout.preferredHeight: mainLayout.height Layout.preferredWidth: { const type = widgetItem.WidgetContainer.id if(type === "org.ukui.dataIsland") { return mainLayout.dataIslandWidth; } else if (type === "org.ukui.settingsIsland"){ return mainLayout.settingsIslandWidth; } } onWidgetItemChanged: { if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = Qt.binding(function () {return widgetParent}) } } } } } } ukui-panel/panel/qml/org.ukui.panelTopBar/metadata.json0000664000175000017500000000111715167645100022073 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.panelTopBar", "Icon": "ukui-panel", "Name": "ukui-panel", "Name[zh_CN]": "任务栏顶栏", "Tooltip": "Panel top bar", "Tooltip[zh_CN]": "任务栏顶栏", "Description": "Panel top bar", "Description[zh_CN]": "任务栏顶栏", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "WidgetType": "Container", "Contents": { "Main": "ui/PanelTopBarContainer.qml" } } ukui-panel/panel/qml/org.ukui.appIsland/0000775000175000017500000000000015167645100017124 5ustar fengfengukui-panel/panel/qml/org.ukui.appIsland/ui/0000775000175000017500000000000015167645100017541 5ustar fengfengukui-panel/panel/qml/org.ukui.appIsland/ui/ApplicationsIsland.qml0000664000175000017500000001571515167645100024046 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: iaom * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.impl 1.0 as Panel WidgetContainerItem { id: containerItem property int orientation: WidgetContainer.orientation property bool isHorizontal: orientation === Types.Horizontal property bool fillWidth: false property double ratio: parent.ratio ? parent.ratio : 1 Layout.preferredWidth: backGround.width Layout.maximumWidth: parent.Layout.maximumWidth Layout.onMaximumWidthChanged: { mainLayout.updateTaskManagerMaxLength(); } Component.onCompleted: { fillWidth = Qt.binding(function (){ for (var i = 0; i < repeater.count; i++) { if(repeater.itemAt(i).Layout.fillWidth) { return true; } } return false }); } DtThemeBackground { id: backGround property double ratio: containerItem.ratio Binding on width { value: { if (containerItem.fillWidth) { return containerItem.width } else { return Math.min(mainLayout.width + flickView.anchors.leftMargin + flickView.anchors.rightMargin, containerItem.Layout.maximumWidth) } } delayed: true; } height: parent.height borderColor: GlobalTheme.buttonTextActive borderAlpha: 0.25 border.width: 1 radius: ratio * GlobalTheme.kRadiusWindow MouseArea { anchors.fill: parent enabled: flickView.contentWidth > flickView.width onWheel: (wheel) => { flickView.flick(wheel.angleDelta.y * 10, 0); } } Flickable { id: flickView z: 10 anchors.fill: parent anchors { leftMargin: 12 * backGround.ratio topMargin: 0 rightMargin: 12 * backGround.ratio bottomMargin: 0 } contentWidth: mainLayout.width contentHeight: backGround.height boundsBehavior: Flickable.StopAtBounds boundsMovement: Flickable.StopAtBounds GridLayout { id: mainLayout height: backGround.height rows: containerItem.isHorizontal ? 1 : repeater.count columns: containerItem.isHorizontal ? repeater.count : 1 rowSpacing: 4 * backGround.ratio columnSpacing: 4 * backGround.ratio property int taskManagerMaxLength: containerItem.Layout.maximumWidth property var otherPluginsWidth: {"": 0} function otherPluginsTotalWidth() { let sum = 0; for (var key in mainLayout.otherPluginsWidth) { var width = mainLayout.otherPluginsWidth[key]; if (typeof width === 'number') { sum += width; } } return sum; } function updateTaskManagerMaxLength() { let spacing = mainLayout.rowSpacing * repeater.count + flickView.anchors.leftMargin + flickView.anchors.rightMargin; taskManagerMaxLength = Math.max(0, (containerItem.Layout.maximumWidth - spacing - otherPluginsTotalWidth())); } Repeater { id: repeater model: Panel.WidgetSortModel { // TODO: use config widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true Component.onDestruction: { if (itemId !== "org.ukui.panel.taskManager" && widgetItem.Widget.instanceId > -1) { let instanceId = widgetItem.Widget.instanceId; let success = delete mainLayout.otherPluginsWidth[instanceId]; if (!success) { mainLayout.otherPluginsWidth[instanceId] = 0; } mainLayout.updateTaskManagerMaxLength(); } } property int index: model.index property double ratio: backGround.ratio property Item widgetItem: model.widgetItem property string itemId: widgetItem.Widget.id property bool isIslandMode: true Layout.fillWidth: widgetItem.Layout.fillWidth Layout.fillHeight: widgetItem.Layout.fillHeight Layout.minimumWidth: widgetItem.Layout.minimumWidth Layout.minimumHeight: widgetItem.Layout.minimumHeight Layout.maximumWidth: (itemId === "org.ukui.panel.taskManager") ? Math.max(widgetItem.Layout.minimumWidth, mainLayout.taskManagerMaxLength) : widgetItem.Layout.maximumWidth Layout.maximumHeight: widgetItem.Layout.maximumHeight Layout.preferredWidth: widgetItem.Layout.preferredWidth Layout.preferredHeight: widgetItem.Layout.preferredHeight onWidthChanged: { if (itemId !== "org.ukui.panel.taskManager" && widgetItem.Widget.instanceId > -1) { mainLayout.otherPluginsWidth[widgetItem.Widget.instanceId] = width; mainLayout.updateTaskManagerMaxLength(); } } onWidgetItemChanged: { if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = widgetParent } } } } } } ukui-panel/panel/qml/org.ukui.appIsland/metadata.json0000664000175000017500000000111015167645100021570 0ustar fengfeng{ "Authors": [ { "Name": "iaom", "Email": "zhangpengfei@kylinos.cn" } ], "Id": "org.ukui.appIsland", "Icon": "ukui-panel", "Name": "ukui-panel", "Name[zh_CN]": "应用岛", "Tooltip": "Applications island", "Tooltip[zh_CN]": "应用岛", "Description": "Applications island", "Description[zh_CN]": "任务栏岛", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "WidgetType": "Container", "Contents": { "Main": "ui/ApplicationsIsland.qml" } } ukui-panel/panel/qml/qml.qrc0000664000175000017500000000146115167645100014751 0ustar fengfeng IslandDragControlRod.qml org.ukui.panel/metadata.json org.ukui.panel/ui/Container.qml org.ukui.panelNext/metadata.json org.ukui.panelNext/ui/MainContainer.qml org.ukui.dataIsland/metadata.json org.ukui.dataIsland/ui/DataIsland.qml org.ukui.appIsland/metadata.json org.ukui.appIsland/ui/ApplicationsIsland.qml org.ukui.settingsIsland/metadata.json org.ukui.settingsIsland/ui/SettingsIsland.qml org.ukui.panelTopBar/ui/PanelTopBarContainer.qml org.ukui.panelTopBar/metadata.json ukui-panel/panel/qml/org.ukui.panel/0000775000175000017500000000000015167645100016310 5ustar fengfengukui-panel/panel/qml/org.ukui.panel/ui/0000775000175000017500000000000015167645111016727 5ustar fengfengukui-panel/panel/qml/org.ukui.panel/ui/Container.qml0000664000175000017500000005336315167645111021376 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: hxf * */ import QtQuick 2.15 import QtQuick.Layouts 1.15 import org.ukui.quick.widgets 1.0 import org.ukui.quick.container 1.0 import org.ukui.quick.items 1.0 import org.ukui.quick.platform 1.0 import org.ukui.panel.impl 1.0 as Panel WidgetContainerItem { id: containerItem Accessible.description: "This is a widget container of ukui-panel" Accessible.name: "ukui-panel widget container" property int orientation: WidgetContainer.orientation property bool isHorizontal: orientation === Types.Horizontal LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true property int trayAreaMaxLength: containerItem.WidgetContainer.screen === null ? 0 : isHorizontal ? panelBase.width * 0.382 : panelBase.height * 0.382 property int calendarLength: 0 property int showDesktopLength: 0 property int systemTrayLength: Math.max(0, trayAreaMaxLength - mainLayout.nonTrayPluginsTotalLengthFrom1) property int appViewSpacing: 8 * ratio property int configSpacing: 0 property double ratio: Math.max(Math.min(panelSize / WidgetContainer.config.panelDefaultSize, 2), 1) property int panelSize: 0 onParentChanged: { anchors.fill = parent } Binding { target: containerItem property: "panelSize" value: isHorizontal ? containerItem.height : containerItem.width delayed: true } ContentWindow { id: panelPosIndicator screen: containerItem.WidgetContainer.screen position: Types.Bottom flags: Qt.Window | Qt.WindowDoesNotAcceptFocus | Qt.FramelessWindowHint windowType: WindowType.SystemWindow property bool hideIndicator: false property bool isHorizontal: (position === Types.BottomCenter || position === Types.TopCenter) property int newPanelPos: Types.Center enableBlurEffect: !hideIndicator DtThemeBackground { Accessible.description: "This is a position indicator window of ukui-panel" Accessible.name: "ukui-panel position indicator" radius: containerItem.WidgetContainer.radius backgroundColor: GlobalTheme.brightTextActive opacity: panelPosIndicator.hideIndicator ? 0 : 0.3 width: { if (panelPosIndicator.isHorizontal) { return containerItem.WidgetContainer.screen.availableGeometry.width - 6; } return containerItem.isHorizontal ? containerItem.height : containerItem.width; } height: { if (panelPosIndicator.isHorizontal) { return containerItem.isHorizontal ? containerItem.height : containerItem.width; } return containerItem.WidgetContainer.screen.availableGeometry.height - 6; } } } DtThemeBackground { id: panelBase anchors.fill: parent anchors { leftMargin: containerItem.WidgetContainer.margin.left topMargin: containerItem.WidgetContainer.margin.top rightMargin: containerItem.WidgetContainer.margin.right bottomMargin: containerItem.WidgetContainer.margin.bottom } border.width: 0 radius: containerItem.WidgetContainer.radius MouseArea { anchors.fill: parent hoverEnabled: panel.enableCustomSize enabled: !panel.lockPanel propagateComposedEvents: true property point startPoint: "-1, -1" property bool isResize: false property real screenAngle: 0 property point prePoint: Qt.point(-1, -1) property bool resizing: false // 计算夹角度数,对边b, 邻边a function getAngle(b, a) { return Math.atan(b / a) * 180 / Math.PI; } onResizingChanged: { if (!resizing) { panel.endResizeCustomPanelSize(); } } onClicked: (mouse) => { if (mouse.button === Qt.RightButton && Panel.disableContextMenu) { mouse.accepted = true; } mouse.accepted = false; } onExited: { if (!pressed) { panel.changeCursor(""); resizing = false; } } onReleased: { panel.changeCursor(""); let visible = panelPosIndicator.visible; panelPosIndicator.hide(); if (visible && !panel.lockPanel && (panelPosIndicator.newPanelPos !== containerItem.WidgetContainer.position)) { panel.changePanelPos(panelPosIndicator.newPanelPos); } resizing = false; } // 计算按下点在本地坐标中出发何种操作 function checkPointOpt(point) { switch (containerItem.WidgetContainer.position) { case Types.Left: return (point.x > (width - 4)) ? "resizeHor" : ""; case Types.Top: return (point.y > (height - 4)) ? "resizeVec" : ""; case Types.Right: return (point.x < 4) ? "resizeHor" : ""; case Types.Bottom: return (point.y < 4) ? "resizeVec" : ""; default: break } return ""; } onPressed: (event) => { let localPos = Qt.point(event.x, event.y); // 按下的起始点 startPoint = mapToGlobal(localPos); prePoint = mapToGlobal(localPos); let opt = checkPointOpt(localPos); isResize = (opt !== ""); let screenSize = containerItem.WidgetContainer.screen.size; // 屏幕对角线夹角与右边的夹角,右上角和右下角相同 screenAngle = getAngle(screenSize.width/2, screenSize.height/2); if (!isResize) { if (panel.lockPanel) { event.accepted = false; } } else { let edge; switch (containerItem.WidgetContainer.position) { case Types.Left: edge = Qt.RightEdge; break; case Types.Right: edge = Qt.LeftEdge; break; case Types.Top: edge = Qt.BottomEdge; break; case Types.Bottom: edge = Qt.TopEdge; break; default: return; } resizing = true; panel.startResizeCustomPanelSize(edge); } } onPositionChanged: (event) => { let localPos = Qt.point(event.x, event.y); if (!pressed) { // 悬浮状态,切换鼠标样式 if (containsMouse) { panel.changeCursor(checkPointOpt(localPos)); } return; } let globalPos = mapToGlobal(localPos); if (!isResize) { // 拖拽换位功能 if (Math.abs(startPoint.x - globalPos.x) < 20 || Math.abs(startPoint.y - globalPos.y) < 20) { panelPosIndicator.newPanelPos = containerItem.WidgetContainer.position; panelPosIndicator.hideIndicator = true; return; } // move // 切换鼠标样式 panel.changeCursor("move"); let screenRect = containerItem.WidgetContainer.screen.geometry; let b = globalPos.x - screenRect.x; let a1 = globalPos.y - screenRect.y; let a2 = screenRect.y + screenRect.height - globalPos.y; if (b < 0 || b > screenRect.width) { return; } if (a1 < 0 || a1 > screenRect.height) { return; } if (a2 < 0 || a2 > screenRect.height) { return; } let angleTop = getAngle(b, a1); let angleBottom = getAngle(b, a2); let pos; if (angleTop <= screenAngle && angleBottom < screenAngle) { pos = Types.LeftCenter; panelPosIndicator.newPanelPos = Types.Left; } else if (angleTop > screenAngle && angleBottom <= screenAngle) { pos = Types.TopCenter; panelPosIndicator.newPanelPos = Types.Top; } else if (angleTop >= screenAngle && angleBottom > screenAngle) { pos = Types.RightCenter; panelPosIndicator.newPanelPos = Types.Right; } else if (angleTop < screenAngle && angleBottom >= screenAngle) { pos = Types.BottomCenter; panelPosIndicator.newPanelPos = Types.Bottom; } else { return; } if (panelPosIndicator.newPanelPos === containerItem.WidgetContainer.position) { // TODO: wlcom环境调用hide会导致mouseArea的pressed变为false // panelPosIndicator.hide(); panelPosIndicator.hideIndicator = true; } else { panelPosIndicator.hideIndicator = false; panelPosIndicator.show(); panelPosIndicator.position = pos; } } prePoint = mapToGlobal(localPos); } } GridLayout { id: mainLayout z: 10 anchors.fill: parent anchors { leftMargin: containerItem.WidgetContainer.padding.left topMargin: containerItem.WidgetContainer.padding.top rightMargin: containerItem.WidgetContainer.padding.right bottomMargin: containerItem.WidgetContainer.padding.bottom } rows: containerItem.isHorizontal ? 1 : children.length columns: containerItem.isHorizontal ? children.length : 1 rowSpacing: appViewSpacing columnSpacing: appViewSpacing // 为了计算taskManager最大长度 property var otherPluginsLength: {"": 0} // 全部区域的widget,除taskManager外,对应的instanceId和长度 property int otherPluginsTotalLength: 0 // 全部区域除taskManager外,其他插件的长度 // 为了计算托盘最大长度 property var otherPluginsLengthFrom1: {"": 0} // layoutIndex为1的widget,除托盘外,对应的instanceId和长度 property int nonTrayPluginsTotalLengthFrom1: 0 // 右侧区域(layoutIndex为1)除托盘外,其他插件的长度 function computePluginsLength(widgetsLength) { let otherPluginsTotalLength = 0; for (var key in widgetsLength) { var length = widgetsLength[key]; if (typeof length === 'number') { otherPluginsTotalLength += length; } } return otherPluginsTotalLength; } /** * panel左侧 / 上侧 * appView: 包括 org.ukui.menu.starter/org.ukui.panel.search/org.ukui.panel.separator/org.ukui.panel.taskManager/org.ukui.panel.taskView插件 * layoutIndex: 0 */ GridLayout { id: appView z: 5 Layout.fillWidth: !containerItem.isHorizontal Layout.fillHeight: containerItem.isHorizontal Layout.maximumWidth: containerItem.isHorizontal ? (mainLayout.width - configView.width - appViewSpacing) : mainLayout.width Layout.maximumHeight: containerItem.isHorizontal ? mainLayout.height : (mainLayout.height - configView.height - appViewSpacing) Layout.alignment: containerItem.isHorizontal ? Qt.AlignLeft : Qt.AlignTop Layout.leftMargin: containerItem.isHorizontal ? appViewSpacing : 0 Layout.topMargin: containerItem.isHorizontal ? 0 : appViewSpacing rows: containerItem.isHorizontal ? 1 : appRepeater.count columns: containerItem.isHorizontal ? appRepeater.count : 1 rowSpacing: appViewSpacing columnSpacing: appViewSpacing Repeater { id: appRepeater model: Panel.WidgetSortModel { // TODO: use config layoutIndex: 0 widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } } /** * panel右侧 / 下侧 * configView: 包括org.ukui.systemTray\org.ukui.panel.calendar\org.ukui.panel.showDesktop插件 * layoutIndex: 1 */ GridLayout { id: configView z: 5 Layout.fillWidth: !containerItem.isHorizontal Layout.fillHeight: containerItem.isHorizontal Layout.alignment: containerItem.isHorizontal ? Qt.AlignRight : Qt.AlignBottom rows: containerItem.isHorizontal ? 1 : configRepeater.count columns: containerItem.isHorizontal ? configRepeater.count : 1 rowSpacing: configSpacing columnSpacing: configSpacing Repeater { id: configRepeater model: Panel.WidgetSortModel { // TODO: use config layoutIndex: 1 widgetOrder: containerItem.WidgetContainer.config.widgetsOrder sourceModel: containerItem.widgetItemModel } delegate: widgetLoaderComponent } } } Component { id: widgetLoaderComponent Item { id: widgetParent clip: true property double ratio: containerItem.ratio property int index: model.index property Item widgetItem: model.widgetItem property string itemId: widgetItem.Widget.id Layout.fillWidth: widgetItem && widgetItem.Layout.fillWidth Layout.fillHeight: widgetItem && widgetItem.Layout.fillHeight Layout.minimumWidth: widgetItem.Layout.minimumWidth Layout.minimumHeight: widgetItem.Layout.minimumHeight Layout.preferredWidth: widgetItem.Layout.preferredWidth Layout.preferredHeight: widgetItem.Layout.preferredHeight Layout.maximumWidth: { if (itemId === "org.ukui.panel.taskManager" && isHorizontal) { return mainLayout.width - mainLayout.otherPluginsTotalLength; } if (itemId === "org.ukui.systemTray" && isHorizontal) { return Math.max(Layout.minimumWidth, containerItem.systemTrayLength); } return widgetItem.Layout.maximumWidth ? widgetItem.Layout.maximumWidth : mainLayout.width; } Layout.maximumHeight: { if (itemId === "org.ukui.panel.taskManager" && !isHorizontal) { return mainLayout.height - mainLayout.otherPluginsTotalLength; } if (itemId === "org.ukui.systemTray" && !isHorizontal) { return Math.max(Layout.minimumHeight, containerItem.systemTrayLength); } return widgetItem.Layout.maximumHeight ? widgetItem.Layout.maximumHeight : mainLayout.height; } onWidthChanged: { if (isHorizontal) { if (itemId !== "org.ukui.panel.taskManager") { mainLayout.otherPluginsLength[widgetItem.Widget.instanceId] = width; if (widgetLayoutIndex === 1 && itemId !== "org.ukui.systemTray") { mainLayout.otherPluginsLengthFrom1[widgetItem.Widget.instanceId] = width; mainLayout.nonTrayPluginsTotalLengthFrom1 = mainLayout.computePluginsLength(mainLayout.otherPluginsLengthFrom1) + configSpacing * (configRepeater.count - 1); } // 需要加上appView、configView间距和mainLayout间距 mainLayout.otherPluginsTotalLength = mainLayout.computePluginsLength(mainLayout.otherPluginsLength) + (appViewSpacing * appRepeater.count + configSpacing * (configRepeater.count - 1) + appView.Layout.leftMargin); } } } onHeightChanged: { if (!isHorizontal) { if (itemId !== "org.ukui.panel.taskManager") { mainLayout.otherPluginsLength[widgetItem.Widget.instanceId] = height; if (widgetLayoutIndex === 1 && itemId !== "org.ukui.systemTray") { mainLayout.otherPluginsLengthFrom1[widgetItem.Widget.instanceId] = height; mainLayout.nonTrayPluginsTotalLengthFrom1 = mainLayout.computePluginsLength(mainLayout.otherPluginsLengthFrom1) + configSpacing * (configRepeater.count - 1); } // 需要加上appView、configView间距和mainLayout间距 mainLayout.otherPluginsTotalLength = mainLayout.computePluginsLength(mainLayout.otherPluginsLength) + (appViewSpacing * appRepeater.count + configSpacing * (configRepeater.count - 1) + appView.Layout.topMargin); } } } Component.onDestruction: { if (itemId !== "org.ukui.panel.taskManager") { mainLayout.otherPluginsLength[widgetItem.Widget.instanceId] = 0; if (widgetLayoutIndex === 1 && itemId !== "org.ukui.systemTray") { mainLayout.otherPluginsLengthFrom1[widgetItem.Widget.instanceId] = 0; mainLayout.nonTrayPluginsTotalLengthFrom1 = mainLayout.computePluginsLength(mainLayout.otherPluginsLengthFrom1) + configSpacing * (configRepeater.count - 1); } // 需要加上appView、configView间距和mainLayout间距 mainLayout.otherPluginsTotalLength = mainLayout.computePluginsLength(mainLayout.otherPluginsLength) + (appViewSpacing * appRepeater.count + configSpacing * (configRepeater.count - 1) + appViewSpacing); } } onWidgetItemChanged: { if (widgetItem) { widgetItem.parent = widgetParent widgetItem.anchors.fill = widgetParent if (itemId === "org.ukui.panel.calendar") { containerItem.calendarLength = Qt.binding(function(){ return containerItem.isHorizontal ? width : height; }) } if (itemId === "org.ukui.panel.showDesktop") { containerItem.showDesktopLength = Qt.binding(function(){ return containerItem.isHorizontal ? width : height; }) } } } } } } MouseArea { id: fcMouseArea anchors.fill: parent acceptedButtons: { let button = Qt.NoButton; if (panel.disableMouseLeftButton) { button |= Qt.LeftButton } if (panel.disableMouseRightButton) { button |= Qt.RightButton } return button; } enabled: panel.disableMouseLeftButton || panel.disableMouseRightButton || panel.disableContextMenu } } ukui-panel/panel/qml/org.ukui.panel/metadata.json0000664000175000017500000000112315167645100020760 0ustar fengfeng{ "Authors": [ { "Name": "hxf", "Email": "hewenfei@kylinos.cn" } ], "Id": "org.ukui.panel", "Icon": "ukui-panel", "Name": "ukui-panel", "Name[zh_CN]": "任务栏面板", "Tooltip": "Common taskbar panel", "Tooltip[zh_CN]": "普通任务栏面板", "Description": "Common taskbar panel", "Description[zh_CN]": "普通任务栏面板", "Version": "1.0", "Website": "https://ukui.org", "BugReport": "https://gitee.com/openkylin/ukui-panel/issues", "ShowIn": "Panel", "WidgetType": "Container", "Contents": { "Main": "ui/Container.qml" } } ukui-panel/panel/ukui-panel.desktop0000664000175000017500000000073315167645100016326 0ustar fengfeng[Desktop Entry] Name=ukui-panel Name[zh_CN]=任务栏 Name[zh_HK]=任務列 Name[bo_CN]=ལས་འགན་གྱི་ལན་ཀན་ Name[mn_MN]=ᠬᠠᠪᠲᠠᠰᠤ Name[ug_CN]=ۋەزىپە ئىستونى Name[kk_KZ]=مىندەتتى ستونى Name[ky_KG]=مىلدەت ىستونۇ comment=Panel Comment[zh_CN]=任务栏 Exec=ukui-panel Terminal=false Type=Application Icon=panel X-UKUI-AutoRestart=true OnlyShowIn=UKUI; NoDisplay=true X-UKUI-Autostart-Phase=Panel ukui-panel/panel/3rd-parties/0000775000175000017500000000000015167645100015013 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/0000775000175000017500000000000015167645100021065 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/src/0000775000175000017500000000000015167645100021654 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/src/qtlocalpeer.h0000664000175000017500000000144515167645100024344 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #ifndef QTLOCALPEER_H #define QTLOCALPEER_H #include #include #include #include "qtlockedfile.h" class QtLocalPeer : public QObject { Q_OBJECT public: QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); bool isClient(); bool sendMessage(const QString &message, int timeout); QString applicationId() const { return id; } Q_SIGNALS: void messageReceived(const QString &message); protected Q_SLOTS: void receiveConnection(); protected: QString id; QString socketName; QLocalServer* server; QtLP_Private::QtLockedFile lockFile; private: static const char* ack; }; #endif // QTLOCALPEER_H ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtsingleapplication.pri0000664000175000017500000000111015167645100026433 0ustar fengfenginclude(../common.pri) INCLUDEPATH += $$PWD DEPENDPATH += $$PWD QT *= network greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets qtsingleapplication-uselib:!qtsingleapplication-buildlib { LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME } else { SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h } win32 { contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT } ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtlockedfile.cpp0000664000175000017500000001020215167645100025021 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include "qtlockedfile.h" /*! \class QtLockedFile \brief The QtLockedFile class extends QFile with advisory locking functions. A file may be locked in read or write mode. Multiple instances of \e QtLockedFile, created in multiple processes running on the same machine, may have a file locked in read mode. Exactly one instance may have it locked in write mode. A read and a write lock cannot exist simultaneously on the same file. The file locks are advisory. This means that nothing prevents another process from manipulating a locked file using QFile or file system functions offered by the OS. Serialization is only guaranteed if all processes that access the file use QLockedFile. Also, while holding a lock on a file, a process must not open the same file again (through any API), or locks can be unexpectedly lost. The lock provided by an instance of \e QtLockedFile is released whenever the program terminates. This is true even when the program crashes and no destructors are called. */ /*! \enum QtLockedFile::LockMode This enum describes the available lock modes. \value ReadLock A read lock. \value WriteLock A write lock. \value NoLock Neither a read lock nor a write lock. */ /*! Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way as \e QFile::QFile(). \sa QFile::QFile() */ QtLockedFile::QtLockedFile() : QFile() { #ifdef Q_OS_WIN wmutex = 0; rmutex = 0; #endif m_lock_mode = NoLock; } /*! Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in the same way as \e QFile::QFile(const QString&). \sa QFile::QFile() */ QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { #ifdef Q_OS_WIN wmutex = 0; rmutex = 0; #endif m_lock_mode = NoLock; } /*! Opens the file in OpenMode \a mode. This is identical to QFile::open(), with the one exception that the Truncate mode flag is disallowed. Truncation would conflict with the advisory file locking, since the file would be modified before the write lock is obtained. If truncation is required, use resize(0) after obtaining the write lock. Returns true if successful; otherwise false. \sa QFile::open(), QFile::resize() */ bool QtLockedFile::open(OpenMode mode) { if (mode & QIODevice::Truncate) { qWarning("QtLockedFile::open(): Truncate mode not allowed."); return false; } return QFile::open(mode); } /*! Returns \e true if this object has a in read or write lock; otherwise returns \e false. \sa lockMode() */ bool QtLockedFile::isLocked() const { return m_lock_mode != NoLock; } /*! Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock. \sa isLocked() */ QtLockedFile::LockMode QtLockedFile::lockMode() const { return m_lock_mode; } /*! \fn bool QtLockedFile::lock(LockMode mode, bool block = true) Obtains a lock of type \a mode. The file must be opened before it can be locked. If \a block is true, this function will block until the lock is aquired. If \a block is false, this function returns \e false immediately if the lock cannot be aquired. If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock is first released and then a new lock is obtained. This function returns \e true if, after it executes, the file is locked by this object, and \e false otherwise. \sa unlock(), isLocked(), lockMode() */ /*! \fn bool QtLockedFile::unlock() Releases a lock. If the object has no lock, this function returns immediately. This function returns \e true if, after it executes, the file is not locked by this object, and \e false otherwise. \sa lock(), isLocked(), lockMode() */ /*! \fn QtLockedFile::~QtLockedFile() Destroys the \e QtLockedFile object. If any locks were held, they are released. */ ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtlockedfile.h0000664000175000017500000000254715167645100024503 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #ifndef QTLOCKEDFILE_H #define QTLOCKEDFILE_H #include #ifdef Q_OS_WIN #include #endif #if defined(Q_OS_WIN) # if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) # define QT_QTLOCKEDFILE_EXPORT # elif defined(QT_QTLOCKEDFILE_IMPORT) # if defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # endif # define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) # elif defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) # endif #else # define QT_QTLOCKEDFILE_EXPORT #endif namespace QtLP_Private { class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: enum LockMode { NoLock = 0, ReadLock, WriteLock }; QtLockedFile(); QtLockedFile(const QString &name); ~QtLockedFile(); bool open(OpenMode mode); bool lock(LockMode mode, bool block = true); bool unlock(); bool isLocked() const; LockMode lockMode() const; private: #ifdef Q_OS_WIN Qt::HANDLE wmutex; Qt::HANDLE rmutex; QVector rmutexes; QString mutexname; Qt::HANDLE getMutexHandle(int idx, bool doCreate); bool waitMutex(Qt::HANDLE mutex, bool doBlock); #endif LockMode m_lock_mode; }; } #endif ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.h0000664000175000017500000000126515167645100026754 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #ifndef QTSINGLECOREAPPLICATION_H #define QTSINGLECOREAPPLICATION_H #include class QtLocalPeer; class QtSingleCoreApplication : public QCoreApplication { Q_OBJECT public: QtSingleCoreApplication(int &argc, char **argv); QtSingleCoreApplication(const QString &id, int &argc, char **argv); bool isRunning(); QString id() const; public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); Q_SIGNALS: void messageReceived(const QString &message); private: QtLocalPeer* peer; }; #endif // QTSINGLECOREAPPLICATION_H ukui-panel/panel/3rd-parties/qtsingleapplication/src/QtLockedFile0000664000175000017500000000003215167645100024100 0ustar fengfeng#include "qtlockedfile.h" ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtlockedfile_unix.cpp0000664000175000017500000000305415167645100026073 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include #include #include #include #include "qtlockedfile.h" bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; int cmd = block ? F_SETLKW : F_SETLK; int ret = fcntl(handle(), cmd, &fl); if (ret == -1) { if (errno != EINTR && errno != EAGAIN) qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_UNLCK; int ret = fcntl(handle(), F_SETLKW, &fl); if (ret == -1) { qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = NoLock; return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); } ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtsingleapplication.cpp0000664000175000017500000002325015167645100026434 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include "qtsingleapplication.h" #include "qtlocalpeer.h" #include /*! \class QtSingleApplication qtsingleapplication.h \brief The QtSingleApplication class provides an API to detect and communicate with running instances of an application. This class allows you to create applications where only one instance should be running at a time. I.e., if the user tries to launch another instance, the already running instance will be activated instead. Another usecase is a client-server system, where the first started instance will assume the role of server, and the later instances will act as clients of that server. By default, the full path of the executable file is used to determine whether two processes are instances of the same application. You can also provide an explicit identifier string that will be compared instead. The application should create the QtSingleApplication object early in the startup phase, and call isRunning() to find out if another instance of this application is already running. If isRunning() returns false, it means that no other instance is running, and this instance has assumed the role as the running instance. In this case, the application should continue with the initialization of the application user interface before entering the event loop with exec(), as normal. The messageReceived() signal will be emitted when the running application receives messages from another instance of the same application. When a message is received it might be helpful to the user to raise the application so that it becomes visible. To facilitate this, QtSingleApplication provides the setActivationWindow() function and the activateWindow() slot. If isRunning() returns true, another instance is already running. It may be alerted to the fact that another instance has started by using the sendMessage() function. Also data such as startup parameters (e.g. the name of the file the user wanted this new instance to open) can be passed to the running instance with this function. Then, the application should terminate (or enter client mode). If isRunning() returns true, but sendMessage() fails, that is an indication that the running instance is frozen. Here's an example that shows how to convert an existing application to use QtSingleApplication. It is very simple and does not make use of all QtSingleApplication's functionality (see the examples for that). \code // Original int main(int argc, char **argv) { QApplication app(argc, argv); MyMainWidget mmw; mmw.show(); return app.exec(); } // Single instance int main(int argc, char **argv) { QtSingleApplication app(argc, argv); if (app.isRunning()) return !app.sendMessage(someDataString); MyMainWidget mmw; app.setActivationWindow(&mmw); mmw.show(); return app.exec(); } \endcode Once this QtSingleApplication instance is destroyed (normally when the process exits or crashes), when the user next attempts to run the application this instance will not, of course, be encountered. The next instance to call isRunning() or sendMessage() will assume the role as the new running instance. For console (non-GUI) applications, QtSingleCoreApplication may be used instead of this class, to avoid the dependency on the QtGui library. \sa QtSingleCoreApplication */ void QtSingleApplication::sysInit(const QString &appId) { actWin = 0; peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); } /*! Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc, \a argv, and \a GUIenabled are passed on to the QAppliation constructor. If you are creating a console application (i.e. setting \a GUIenabled to false), you may consider using QtSingleCoreApplication instead. */ QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) : QApplication(argc, argv, GUIenabled) { sysInit(); } /*! Creates a QtSingleApplication object with the application identifier \a appId. \a argc and \a argv are passed on to the QAppliation constructor. */ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) : QApplication(argc, argv) { sysInit(appId); } #if QT_VERSION < 0x050000 /*! Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc, \a argv, and \a type are passed on to the QAppliation constructor. */ QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) : QApplication(argc, argv, type) { sysInit(); } # if defined(Q_WS_X11) /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, visual, cmap) { sysInit(); } /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a argv, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, argc, argv, visual, cmap) { sysInit(); } /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be \a appId. \a dpy, \a argc, \a argv, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, argc, argv, visual, cmap) { sysInit(appId); } # endif // Q_WS_X11 #endif // QT_VERSION < 0x050000 /*! Returns true if another instance of this application is running; otherwise false. This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session). \sa sendMessage() */ bool QtSingleApplication::isRunning() { return peer->isClient(); } /*! Tries to send the text \a message to the currently running instance. The QtSingleApplication object in the running instance will emit the messageReceived() signal when it receives the message. This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within \a timeout milliseconds, this function return false. \sa isRunning(), messageReceived() */ bool QtSingleApplication::sendMessage(const QString &message, int timeout) { return peer->sendMessage(message, timeout); } /*! Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application. */ QString QtSingleApplication::id() const { return peer->applicationId(); } /*! Sets the activation window of this application to \a aw. The activation window is the widget that will be activated by activateWindow(). This is typically the application's main window. If \a activateOnMessage is true (the default), the window will be activated automatically every time a message is received, just prior to the messageReceived() signal being emitted. \sa activateWindow(), messageReceived() */ void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) { actWin = aw; if (activateOnMessage) connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); else disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); } /*! Returns the applications activation window if one has been set by calling setActivationWindow(), otherwise returns 0. \sa setActivationWindow() */ QWidget* QtSingleApplication::activationWindow() const { return actWin; } /*! De-minimizes, raises, and activates this application's activation window. This function does nothing if no activation window has been set. This is a convenience function to show the user that this application instance has been activated when he has tried to start another instance. This function should typically be called in response to the messageReceived() signal. By default, that will happen automatically, if an activation window has been set. \sa setActivationWindow(), messageReceived(), initialize() */ void QtSingleApplication::activateWindow() { if (actWin) { actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); } } /*! \fn void QtSingleApplication::messageReceived(const QString& message) This signal is emitted when the current instance receives a \a message from another instance of this application. \sa sendMessage(), setActivationWindow(), activateWindow() */ /*! \fn void QtSingleApplication::initialize(bool dummy = true) \obsolete */ ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtlocalpeer.cpp0000664000175000017500000001174515167645100024703 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include "qtlocalpeer.h" #include #include #include #include #if defined(Q_OS_WIN) #include #include typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); static PProcessIdToSessionId pProcessIdToSessionId = 0; #endif #if defined(Q_OS_UNIX) #include #include #include #endif namespace QtLP_Private { #include "qtlockedfile.cpp" #if defined(Q_OS_WIN) #include "qtlockedfile_win.cpp" #else #include "qtlockedfile_unix.cpp" #endif } const char* QtLocalPeer::ack = "ack"; QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) : QObject(parent), id(appId) { QString prefix = id; if (id.isEmpty()) { id = QCoreApplication::applicationFilePath(); #if defined(Q_OS_WIN) id = id.toLower(); #endif prefix = id.section(QLatin1Char('/'), -1); } prefix.remove(QRegularExpression("[^a-zA-Z]")); prefix.truncate(6); QByteArray idc = id.toUtf8(); quint16 idNum = qChecksum(idc.constData(), idc.size()); socketName = QLatin1String("qtsingleapp-") + prefix + QLatin1Char('-') + QString::number(idNum, 16); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { QLibrary lib("kernel32"); pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); } if (pProcessIdToSessionId) { DWORD sessionId = 0; pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); socketName += QLatin1Char('-') + QString::number(sessionId, 16); } #else socketName += QLatin1Char('-') + QString::number(::getuid(), 16); #endif server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); } bool QtLocalPeer::isClient() { if (lockFile.isLocked()) return false; if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) return true; bool res = server->listen(socketName); #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) // ### Workaround if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); res = server->listen(socketName); } #endif if (!res) qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); return false; } bool QtLocalPeer::sendMessage(const QString &message, int timeout) { if (!isClient()) return false; QLocalSocket socket; bool connOk = false; for(int i = 0; i < 2; i++) { // Try twice, in case the other instance is just starting up socket.connectToServer(socketName); connOk = socket.waitForConnected(timeout/2); if (connOk || i) break; int ms = 250; #if defined(Q_OS_WIN) Sleep(DWORD(ms)); #else struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; nanosleep(&ts, NULL); #endif } if (!connOk) return false; QByteArray uMsg(message.toUtf8()); QDataStream ds(&socket); ds.writeBytes(uMsg.constData(), uMsg.size()); bool res = socket.waitForBytesWritten(timeout); if (res) { res &= socket.waitForReadyRead(timeout); // wait for ack if (res) res &= (socket.read(qstrlen(ack)) == ack); } return res; } void QtLocalPeer::receiveConnection() { QLocalSocket* socket = server->nextPendingConnection(); if (!socket) return; while (true) { if (socket->state() == QLocalSocket::UnconnectedState) { qWarning("QtLocalPeer: Peer disconnected"); delete socket; return; } if (socket->bytesAvailable() >= qint64(sizeof(quint32))) break; socket->waitForReadyRead(); } QDataStream ds(socket); QByteArray uMsg; quint32 remaining; ds >> remaining; uMsg.resize(remaining); int got = 0; char* uMsgBuf = uMsg.data(); do { got = ds.readRawData(uMsgBuf, remaining); remaining -= got; uMsgBuf += got; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); if (got < 0) { qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); delete socket; return; } QString message(QString::fromUtf8(uMsg)); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); socket->waitForDisconnected(1000); // make sure client reads ack delete socket; emit messageReceived(message); //### (might take a long time to return) } ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtsingleapplication.h0000664000175000017500000000405715167645100026105 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #ifndef QTSINGLEAPPLICATION_H #define QTSINGLEAPPLICATION_H #include class QtLocalPeer; #if defined(Q_OS_WIN) # if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) # define QT_QTSINGLEAPPLICATION_EXPORT # elif defined(QT_QTSINGLEAPPLICATION_IMPORT) # if defined(QT_QTSINGLEAPPLICATION_EXPORT) # undef QT_QTSINGLEAPPLICATION_EXPORT # endif # define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport) # elif defined(QT_QTSINGLEAPPLICATION_EXPORT) # undef QT_QTSINGLEAPPLICATION_EXPORT # define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport) # endif #else # define QT_QTSINGLEAPPLICATION_EXPORT #endif class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication { Q_OBJECT public: QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); QtSingleApplication(const QString &id, int &argc, char **argv); #if QT_VERSION < 0x050000 QtSingleApplication(int &argc, char **argv, Type type); # if defined(Q_WS_X11) QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); # endif // Q_WS_X11 #endif // QT_VERSION < 0x050000 bool isRunning(); QString id() const; void setActivationWindow(QWidget* aw, bool activateOnMessage = true); QWidget* activationWindow() const; // Obsolete: void initialize(bool dummy = true) { isRunning(); Q_UNUSED(dummy) } public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); void activateWindow(); Q_SIGNALS: void messageReceived(const QString &message); private: void sysInit(const QString &appId = QString()); QtLocalPeer *peer; QWidget *actWin; }; #endif // QTSINGLEAPPLICATION_H ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtlockedfile_win.cpp0000664000175000017500000001112115167645100025677 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include "qtlockedfile.h" #include #include #define MUTEX_PREFIX "QtLockedFile mutex " // Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS #define MAX_READERS MAXIMUM_WAIT_OBJECTS #if QT_VERSION >= 0x050000 #define QT_WA(unicode, ansi) unicode #endif Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate) { if (mutexname.isEmpty()) { QFileInfo fi(*this); mutexname = QString::fromLatin1(MUTEX_PREFIX) + fi.absoluteFilePath().toLower(); } QString mname(mutexname); if (idx >= 0) mname += QString::number(idx); Qt::HANDLE mutex; if (doCreate) { QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); }, { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } ); if (!mutex) { qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); return 0; } } else { QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); }, { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); if (!mutex) { if (GetLastError() != ERROR_FILE_NOT_FOUND) qErrnoWarning("QtLockedFile::lock(): OpenMutex failed"); return 0; } } return mutex; } bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock) { Q_ASSERT(mutex); DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0); switch (res) { case WAIT_OBJECT_0: case WAIT_ABANDONED: return true; break; case WAIT_TIMEOUT: break; default: qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed"); } return false; } bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); if (!wmutex && !(wmutex = getMutexHandle(-1, true))) return false; if (!waitMutex(wmutex, block)) return false; if (mode == ReadLock) { int idx = 0; for (; idx < MAX_READERS; idx++) { rmutex = getMutexHandle(idx, false); if (!rmutex || waitMutex(rmutex, false)) break; CloseHandle(rmutex); } bool ok = true; if (idx >= MAX_READERS) { qWarning("QtLockedFile::lock(): too many readers"); rmutex = 0; ok = false; } else if (!rmutex) { rmutex = getMutexHandle(idx, true); if (!rmutex || !waitMutex(rmutex, false)) ok = false; } if (!ok && rmutex) { CloseHandle(rmutex); rmutex = 0; } ReleaseMutex(wmutex); if (!ok) return false; } else { Q_ASSERT(rmutexes.isEmpty()); for (int i = 0; i < MAX_READERS; i++) { Qt::HANDLE mutex = getMutexHandle(i, false); if (mutex) rmutexes.append(mutex); } if (rmutexes.size()) { DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), TRUE, block ? INFINITE : 0); if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) { if (res != WAIT_TIMEOUT) qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed"); m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky unlock(); return false; } } } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; if (m_lock_mode == ReadLock) { ReleaseMutex(rmutex); CloseHandle(rmutex); rmutex = 0; } else { foreach(Qt::HANDLE mutex, rmutexes) { ReleaseMutex(mutex); CloseHandle(mutex); } rmutexes.clear(); ReleaseMutex(wmutex); } m_lock_mode = QtLockedFile::NoLock; return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); if (wmutex) CloseHandle(wmutex); } ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.pri0000664000175000017500000000050415167645100027312 0ustar fengfengINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp QT *= network win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport) } ukui-panel/panel/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.cpp0000664000175000017500000000661515167645100027313 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include "qtsinglecoreapplication.h" #include "qtlocalpeer.h" /*! \class QtSingleCoreApplication qtsinglecoreapplication.h \brief A variant of the QtSingleApplication class for non-GUI applications. This class is a variant of QtSingleApplication suited for use in console (non-GUI) applications. It is an extension of QCoreApplication (instead of QApplication). It does not require the QtGui library. The API and usage is identical to QtSingleApplication, except that functions relating to the "activation window" are not present, for obvious reasons. Please refer to the QtSingleApplication documentation for explanation of the usage. A QtSingleCoreApplication instance can communicate to a QtSingleApplication instance if they share the same application id. Hence, this class can be used to create a light-weight command-line tool that sends commands to a GUI application. \sa QtSingleApplication */ /*! Creates a QtSingleCoreApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc and \a argv are passed on to the QCoreAppliation constructor. */ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) : QCoreApplication(argc, argv) { peer = new QtLocalPeer(this); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); } /*! Creates a QtSingleCoreApplication object with the application identifier \a appId. \a argc and \a argv are passed on to the QCoreAppliation constructor. */ QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv) : QCoreApplication(argc, argv) { peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); } /*! Returns true if another instance of this application is running; otherwise false. This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session). \sa sendMessage() */ bool QtSingleCoreApplication::isRunning() { return peer->isClient(); } /*! Tries to send the text \a message to the currently running instance. The QtSingleCoreApplication object in the running instance will emit the messageReceived() signal when it receives the message. This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within \a timeout milliseconds, this function return false. \sa isRunning(), messageReceived() */ bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) { return peer->sendMessage(message, timeout); } /*! Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application. */ QString QtSingleCoreApplication::id() const { return peer->applicationId(); } /*! \fn void QtSingleCoreApplication::messageReceived(const QString& message) This signal is emitted when the current instance receives a \a message from another instance of this application. \sa sendMessage() */ ukui-panel/panel/3rd-parties/qtsingleapplication/src/QtSingleApplication0000664000175000017500000000004115167645100025504 0ustar fengfeng#include "qtsingleapplication.h" ukui-panel/panel/3rd-parties/qtsingleapplication/doc/0000775000175000017500000000000015167645100021632 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/doc/images/0000775000175000017500000000000015167645100023077 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/doc/images/qt-logo.png0000664000175000017500000000775315167645100025203 0ustar fengfengPNG  IHDR9C:uIDATxb?bhJnJnJnJnJnJnԡ Є`r'Q( !!Nb_p??F&F312G.yG&ޏ?}eWSSgb( ~™t齸g0sVv`fcdY8E$xdUUex$xd9DDr=#gdd|Uףw9D- 2b8Ͽebddceᔐ╗SWScaB#cfd]-I\ _20110`xzw/).#'˯"ǯ*˫,+')@lY@}fۯͼ 2@d$1H')&#'ç,ϯ*˧,#/%́XgfdOX8Y9s2GC3g@ fFff.3O|v ,l%?fR_|bb`y엉3+ԇ,̌,4 "ͭ32>{E4އ ˯NԦ+Qefdϛ?6:&Ǜ?|"=\n$FFfF /0"`ddf cfbb`dx՛o yAP ,,eebWaá,QܬLL>5Lll10 m00wTVxOÚ bGB8GtUմXplII ׶R/@2 Y{ ]d9#ule+}N6XfJ"խJ13002³ @K"ŭzo?1000@{ lϿ`?ï2"ecgd H.fFfɆ}Ͽߌ"٭윌 y02000Ac<\po/."?;#ߛ!hgddd\<|\300<|?j"-U L9D8E i[ZP?z5fF6? o"b')~?3311g/ ֯cz߿>pvfL~g'""٭Qd'i `Ϳ'?HۅǞy?200 %)h1.7?."ͭ 32yVfFfGyO/:?LL [,?/?^}|:`luX-tN X"_CkǶ>w:7WlSofFcOv{OD7톚)*$@d"7$1CRgɉi[!.f&v_#ɧ{='JXXc`agպ]R\̅?ӧ_ᄏvѦ_2"g|fە(m )\!&&&F{ ba~>qci.O?l-"s܅Ǐ<Ϟn%hm)tN6P߿0H~̌,|ןhmF>1:19_/رcc7k䱞]ۯ咒SaB[?|}kf~?ɍkF/>9*qpQ( @##ïe1| QXn_ #ơp7B]X?F[a'K+ q/̌,,L L 7tDʡz /#300VnC")"/?110qp￿l_GVWNOU_UIPSCؐ?\e``=_R(2r-d?ÿ_?+78$$ +:xBVFn^?cbdd@yĂf```aba㔆L)J sI2Ҥ!#3 > ^y^~o (?+33d:.cfL(H*sJ`Mg222ڥž15,l l"< QtSingleApplication Class Reference
  Home

QtSingleApplication Class Reference

The QtSingleApplication class provides an API to detect and communicate with running instances of an application. More...

 #include <QtSingleApplication>

Inherits QApplication.


Public Functions

QtSingleApplication ( int & argc, char ** argv, bool GUIenabled = true )
QtSingleApplication ( const QString & appId, int & argc, char ** argv )
QtSingleApplication ( int & argc, char ** argv, Type type )
QtSingleApplication ( Display * dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )
QtSingleApplication ( Display * dpy, int & argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )
QtSingleApplication ( Display * dpy, const QString & appId, int argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )
QWidget * activationWindow () const
QString id () const
bool isRunning ()
void setActivationWindow ( QWidget * aw, bool activateOnMessage = true )

Public Slots

void activateWindow ()
bool sendMessage ( const QString & message, int timeout = 5000 )

Signals

void messageReceived ( const QString & message )

Additional Inherited Members


Detailed Description

The QtSingleApplication class provides an API to detect and communicate with running instances of an application.

This class allows you to create applications where only one instance should be running at a time. I.e., if the user tries to launch another instance, the already running instance will be activated instead. Another usecase is a client-server system, where the first started instance will assume the role of server, and the later instances will act as clients of that server.

By default, the full path of the executable file is used to determine whether two processes are instances of the same application. You can also provide an explicit identifier string that will be compared instead.

The application should create the QtSingleApplication object early in the startup phase, and call isRunning() to find out if another instance of this application is already running. If isRunning() returns false, it means that no other instance is running, and this instance has assumed the role as the running instance. In this case, the application should continue with the initialization of the application user interface before entering the event loop with exec(), as normal.

The messageReceived() signal will be emitted when the running application receives messages from another instance of the same application. When a message is received it might be helpful to the user to raise the application so that it becomes visible. To facilitate this, QtSingleApplication provides the setActivationWindow() function and the activateWindow() slot.

If isRunning() returns true, another instance is already running. It may be alerted to the fact that another instance has started by using the sendMessage() function. Also data such as startup parameters (e.g. the name of the file the user wanted this new instance to open) can be passed to the running instance with this function. Then, the application should terminate (or enter client mode).

If isRunning() returns true, but sendMessage() fails, that is an indication that the running instance is frozen.

Here's an example that shows how to convert an existing application to use QtSingleApplication. It is very simple and does not make use of all QtSingleApplication's functionality (see the examples for that).

 // Original
 int main(int argc, char **argv)
 {
     QApplication app(argc, argv);

     MyMainWidget mmw;
     mmw.show();
     return app.exec();
 }

 // Single instance
 int main(int argc, char **argv)
 {
     QtSingleApplication app(argc, argv);

     if (app.isRunning())
         return !app.sendMessage(someDataString);

     MyMainWidget mmw;
     app.setActivationWindow(&mmw);
     mmw.show();
     return app.exec();
 }

Once this QtSingleApplication instance is destroyed (normally when the process exits or crashes), when the user next attempts to run the application this instance will not, of course, be encountered. The next instance to call isRunning() or sendMessage() will assume the role as the new running instance.

For console (non-GUI) applications, QtSingleCoreApplication may be used instead of this class, to avoid the dependency on the QtGui library.

See also QtSingleCoreApplication.


Member Function Documentation

QtSingleApplication::QtSingleApplication ( int & argc, char ** argv, bool GUIenabled = true )

Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). argc, argv, and GUIenabled are passed on to the QAppliation constructor.

If you are creating a console application (i.e. setting GUIenabled to false), you may consider using QtSingleCoreApplication instead.

QtSingleApplication::QtSingleApplication ( const QString & appId, int & argc, char ** argv )

Creates a QtSingleApplication object with the application identifier appId. argc and argv are passed on to the QAppliation constructor.

QtSingleApplication::QtSingleApplication ( int & argc, char ** argv, Type type )

Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). argc, argv, and type are passed on to the QAppliation constructor.

QtSingleApplication::QtSingleApplication ( Display * dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )

Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). dpy, visual, and cmap are passed on to the QApplication constructor.

QtSingleApplication::QtSingleApplication ( Display * dpy, int & argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )

Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). dpy, argc, argv, visual, and cmap are passed on to the QApplication constructor.

QtSingleApplication::QtSingleApplication ( Display * dpy, const QString & appId, int argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )

Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be appId. dpy, argc, argv, visual, and cmap are passed on to the QApplication constructor.

void QtSingleApplication::activateWindow ()   [slot]

De-minimizes, raises, and activates this application's activation window. This function does nothing if no activation window has been set.

This is a convenience function to show the user that this application instance has been activated when he has tried to start another instance.

This function should typically be called in response to the messageReceived() signal. By default, that will happen automatically, if an activation window has been set.

See also setActivationWindow(), messageReceived(), and initialize().

QWidget * QtSingleApplication::activationWindow () const

Returns the applications activation window if one has been set by calling setActivationWindow(), otherwise returns 0.

See also setActivationWindow().

QString QtSingleApplication::id () const

Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application.

bool QtSingleApplication::isRunning ()

Returns true if another instance of this application is running; otherwise false.

This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session).

See also sendMessage().

void QtSingleApplication::messageReceived ( const QString & message )   [signal]

This signal is emitted when the current instance receives a message from another instance of this application.

See also sendMessage(), setActivationWindow(), and activateWindow().

bool QtSingleApplication::sendMessage ( const QString & message, int timeout = 5000 )   [slot]

Tries to send the text message to the currently running instance. The QtSingleApplication object in the running instance will emit the messageReceived() signal when it receives the message.

This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within timeout milliseconds, this function return false.

See also isRunning() and messageReceived().

void QtSingleApplication::setActivationWindow ( QWidget * aw, bool activateOnMessage = true )

Sets the activation window of this application to aw. The activation window is the widget that will be activated by activateWindow(). This is typically the application's main window.

If activateOnMessage is true (the default), the window will be activated automatically every time a message is received, just prior to the messageReceived() signal being emitted.

See also activationWindow(), activateWindow(), and messageReceived().


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-members.html0000664000175000017500000007370215167645100031177 0ustar fengfeng List of All Members for QtSingleApplication
  Home

List of All Members for QtSingleApplication

This is the complete list of members for QtSingleApplication, including inherited members.


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.dcf0000664000175000017500000000507115167645100027331 0ustar fengfeng
QtSingleApplication activateWindow activationWindow id isRunning messageReceived sendMessage setActivationWindow
QtSingleCoreApplication id isRunning messageReceived sendMessage
A non-GUI example
A Trivial Example
Loading Documents
Single Application
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-trivial.html0000664000175000017500000001243415167645100032643 0ustar fengfeng A Trivial Example
  Home

A Trivial Example

The application in this example has a log-view that displays messages sent by further instances of the same application.

The example demonstrates the use of the QtSingleApplication class to detect and communicate with a running instance of the application using the sendMessage() API. The messageReceived() signal is used to display received messages in a QTextEdit log.

 /****************************************************************************
 **
 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 ** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the Qt Solutions component.
 **
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
 **     the names of its contributors may be used to endorse or promote
 **     products derived from this software without specific prior written
 **     permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 **
 ****************************************************************************/

 #include <qtsingleapplication.h>
 #include <QtGui/QTextEdit>

 class TextEdit : public QTextEdit
 {
     Q_OBJECT
 public:
     TextEdit(QWidget *parent = 0)
         : QTextEdit(parent)
     {}
 public slots:
     void append(const QString &str)
     {
         QTextEdit::append(str);
     }
 };

 #include "main.moc"

 int main(int argc, char **argv)
 {
     QtSingleApplication instance(argc, argv);

The example has only the main entry point function. A QtSingleApplication object is created immediately.

     if (instance.sendMessage("Wake up!"))
         return 0;

If another instance of this application is already running, sendMessage() will succeed, and this instance just exits immediately.

     TextEdit logview;
     logview.setReadOnly(true);
     logview.show();

Otherwise the instance continues as normal and creates the user interface.

     instance.setActivationWindow(&logview);

     QObject::connect(&instance, SIGNAL(messageReceived(const QString&)),
                      &logview, SLOT(append(const QString&)));

     return instance.exec();

The logview object is also set as the application's activation window. Every time a message is received, the window will be raised and activated automatically.

The messageReceived() signal is also connected to the QTextEdit's append() slot. Every message received from further instances of this application will be displayed in the log.

Finally the event loop is entered.


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/images/0000775000175000017500000000000015167645100024043 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/images/qt-logo.png0000664000175000017500000000775315167645100026147 0ustar fengfengPNG  IHDR9C:uIDATxb?bhJnJnJnJnJnJnԡ Є`r'Q( !!Nb_p??F&F312G.yG&ޏ?}eWSSgb( ~™t齸g0sVv`fcdY8E$xdUUex$xd9DDr=#gdd|Uףw9D- 2b8Ͽebddceᔐ╗SWScaB#cfd]-I\ _20110`xzw/).#'˯"ǯ*˫,+')@lY@}fۯͼ 2@d$1H')&#'ç,ϯ*˧,#/%́XgfdOX8Y9s2GC3g@ fFff.3O|v ,l%?fR_|bb`y엉3+ԇ,̌,4 "ͭ32>{E4އ ˯NԦ+Qefdϛ?6:&Ǜ?|"=\n$FFfF /0"`ddf cfbb`dx՛o yAP ,,eebWaá,QܬLL>5Lll10 m00wTVxOÚ bGB8GtUմXplII ׶R/@2 Y{ ]d9#ule+}N6XfJ"խJ13002³ @K"ŭzo?1000@{ lϿ`?ï2"ecgd H.fFfɆ}Ͽߌ"٭윌 y02000Ac<\po/."?;#ߛ!hgddd\<|\300<|?j"-U L9D8E i[ZP?z5fF6? o"b')~?3311g/ ֯cz߿>pvfL~g'""٭Qd'i `Ϳ'?HۅǞy?200 %)h1.7?."ͭ 32yVfFfGyO/:?LL [,?/?^}|:`luX-tN X"_CkǶ>w:7WlSofFcOv{OD7톚)*$@d"7$1CRgɉi[!.f&v_#ɧ{='JXXc`agպ]R\̅?ӧ_ᄏvѦ_2"g|fە(m )\!&&&F{ ba~>qci.O?l-"s܅Ǐ<Ϟn%hm)tN6P߿0H~̌,|ןhmF>1:19_/رcc7k䱞]ۯ咒SaB[?|}kf~?ɍkF/>9*qpQ( @##ïe1| QXn_ #ơp7B]X?F[a'K+ q/̌,,L L 7tDʡz /#300VnC")"/?110qp￿l_GVWNOU_UIPSCؐ?\e``=_R(2r-d?ÿ_?+78$$ +:xBVFn^?cbdd@yĂf```aba㔆L)J sI2Ҥ!#3 > ^y^~o (?+33d:.cfL(H*sJ`Mg222ڥž15,l l"< A non-GUI example
  Home

A non-GUI example

This example shows how to use the single-application functionality in a console application. It does not require the QtGui library at all.

The only differences from the GUI application usage demonstrated in the other examples are:

1) The .pro file should include qtsinglecoreapplication.pri instead of qtsingleapplication.pri

2) The class name is QtSingleCoreApplication instead of QtSingleApplication.

3) No calls are made regarding window activation, for obvious reasons.

console.pro:

 TEMPLATE   = app
 CONFIG    += console
 SOURCES   += main.cpp
 include(../../src/qtsinglecoreapplication.pri)
 QT -= gui

main.cpp:

 /****************************************************************************
 **
 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 ** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the Qt Solutions component.
 **
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
 **     the names of its contributors may be used to endorse or promote
 **     products derived from this software without specific prior written
 **     permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 **
 ****************************************************************************/

 #include "qtsinglecoreapplication.h"
 #include <QtCore/QDebug>

 void report(const QString& msg)
 {
     qDebug("[%i] %s", (int)QCoreApplication::applicationPid(), qPrintable(msg));
 }

 class MainClass : public QObject
 {
     Q_OBJECT
 public:
     MainClass()
         : QObject()
         {}

 public slots:
     void handleMessage(const QString& message)
         {
             report( "Message received: \"" + message + "\"");
         }
 };

 int main(int argc, char **argv)
 {
     report("Starting up");

     QtSingleCoreApplication app(argc, argv);

     if (app.isRunning()) {
         QString msg(QString("Hi master, I am %1.").arg(QCoreApplication::applicationPid()));
         bool sentok = app.sendMessage(msg, 2000);
         QString rep("Another instance is running, so I will exit.");
         rep += sentok ? " Message sent ok." : " Message sending failed; the other instance may be frozen.";
         report(rep);
         return 0;
     } else {
         report("No other instance is running; so I will.");
         MainClass mainObj;
         QObject::connect(&app, SIGNAL(messageReceived(const QString&)),
                          &mainObj, SLOT(handleMessage(const QString&)));
         return app.exec();
     }
 }

 #include "main.moc"


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-loader.html0000664000175000017500000001670015167645100032437 0ustar fengfeng Loading Documents
  Home

Loading Documents

The application in this example loads or prints the documents passed as commandline parameters to further instances of this application.

 /****************************************************************************
 **
 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 ** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the Qt Solutions component.
 **
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
 **     the names of its contributors may be used to endorse or promote
 **     products derived from this software without specific prior written
 **     permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 **
 ****************************************************************************/

 #include <qtsingleapplication.h>
 #include <QtCore/QFile>
 #include <QtGui/QMainWindow>
 #include <QtGui/QPrinter>
 #include <QtGui/QPainter>
 #include <QtGui/QTextEdit>
 #include <QtGui/QMdiArea>
 #include <QtCore/QTextStream>

 class MainWindow : public QMainWindow
 {
     Q_OBJECT
 public:
     MainWindow();

 public slots:
     void handleMessage(const QString& message);

 signals:
     void needToShow();

 private:
     QMdiArea *workspace;
 };

The user interface in this application is a QMainWindow subclass with a QMdiArea as the central widget. It implements a slot handleMessage() that will be connected to the messageReceived() signal of the QtSingleApplication class.

 MainWindow::MainWindow()
 {
     workspace = new QMdiArea(this);

     setCentralWidget(workspace);
 }

The MainWindow constructor creates a minimal user interface.

 void MainWindow::handleMessage(const QString& message)
 {
     enum Action {
         Nothing,
         Open,
         Print
     } action;

     action = Nothing;
     QString filename = message;
     if (message.toLower().startsWith("/print ")) {
         filename = filename.mid(7);
         action = Print;
     } else if (!message.isEmpty()) {
         action = Open;
     }
     if (action == Nothing) {
         emit needToShow();
         return;
     }

     QFile file(filename);
     QString contents;
     if (file.open(QIODevice::ReadOnly))
         contents = file.readAll();
     else
         contents = "[[Error: Could not load file " + filename + "]]";

     QTextEdit *view = new QTextEdit;
     view->setPlainText(contents);

     switch(action) {

The handleMessage() slot interprets the message passed in as a filename that can be prepended with /print to indicate that the file should just be printed rather than loaded.

     case Print:
         {
             QPrinter printer;
             view->print(&printer);
             delete view;
         }
         break;

     case Open:
         {
             workspace->addSubWindow(view);
             view->setWindowTitle(message);
             view->show();
             emit needToShow();
         }
         break;
     default:
         break;
     };
 }

Loading the file will also activate the window.

 #include "main.moc"

 int main(int argc, char **argv)
 {
     QtSingleApplication instance("File loader QtSingleApplication example", argc, argv);
     QString message;
     for (int a = 1; a < argc; ++a) {
         message += argv[a];
         if (a < argc-1)
             message += " ";
     }

     if (instance.sendMessage(message))
         return 0;

The main entry point function creates a QtSingleApplication object, and creates a message to send to a running instance of the application. If the message was sent successfully the process exits immediately.

     MainWindow mw;
     mw.handleMessage(message);
     mw.show();

     QObject::connect(&instance, SIGNAL(messageReceived(const QString&)),
                      &mw, SLOT(handleMessage(const QString&)));

     instance.setActivationWindow(&mw, false);
     QObject::connect(&mw, SIGNAL(needToShow()), &instance, SLOT(activateWindow()));

     return instance.exec();
 }

If the message could not be sent the application starts up. Note that false is passed to the call to setActivationWindow() to prevent automatic activation for every message received, e.g. when the application should just print a file. Instead, the message handling function determines whether activation is requested, and signals that by emitting the needToShow() signal. This is then simply connected directly to QtSingleApplication's activateWindow() slot.


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication.html0000664000175000017500000002356615167645100030423 0ustar fengfeng QtSingleCoreApplication Class Reference
  Home

QtSingleCoreApplication Class Reference

A variant of the QtSingleApplication class for non-GUI applications. More...

 #include <QtSingleCoreApplication>

Inherits QCoreApplication.


Public Functions

QtSingleCoreApplication ( int & argc, char ** argv )
QtSingleCoreApplication ( const QString & appId, int & argc, char ** argv )
QString id () const
bool isRunning ()

Public Slots

bool sendMessage ( const QString & message, int timeout = 5000 )

Signals

void messageReceived ( const QString & message )

Additional Inherited Members


Detailed Description

A variant of the QtSingleApplication class for non-GUI applications.

This class is a variant of QtSingleApplication suited for use in console (non-GUI) applications. It is an extension of QCoreApplication (instead of QApplication). It does not require the QtGui library.

The API and usage is identical to QtSingleApplication, except that functions relating to the "activation window" are not present, for obvious reasons. Please refer to the QtSingleApplication documentation for explanation of the usage.

A QtSingleCoreApplication instance can communicate to a QtSingleApplication instance if they share the same application id. Hence, this class can be used to create a light-weight command-line tool that sends commands to a GUI application.

See also QtSingleApplication.


Member Function Documentation

QtSingleCoreApplication::QtSingleCoreApplication ( int & argc, char ** argv )

Creates a QtSingleCoreApplication object. The application identifier will be QCoreApplication::applicationFilePath(). argc and argv are passed on to the QCoreAppliation constructor.

QtSingleCoreApplication::QtSingleCoreApplication ( const QString & appId, int & argc, char ** argv )

Creates a QtSingleCoreApplication object with the application identifier appId. argc and argv are passed on to the QCoreAppliation constructor.

QString QtSingleCoreApplication::id () const

Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application.

bool QtSingleCoreApplication::isRunning ()

Returns true if another instance of this application is running; otherwise false.

This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session).

See also sendMessage().

void QtSingleCoreApplication::messageReceived ( const QString & message )   [signal]

This signal is emitted when the current instance receives a message from another instance of this application.

See also sendMessage().

bool QtSingleCoreApplication::sendMessage ( const QString & message, int timeout = 5000 )   [slot]

Tries to send the text message to the currently running instance. The QtSingleCoreApplication object in the running instance will emit the messageReceived() signal when it receives the message.

This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within timeout milliseconds, this function return false.

See also isRunning() and messageReceived().


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-members.html0000664000175000017500000003577715167645100032062 0ustar fengfeng List of All Members for QtSingleCoreApplication
  Home

List of All Members for QtSingleCoreApplication

This is the complete list of members for QtSingleCoreApplication, including inherited members.


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.index0000664000175000017500000003171415167645100027707 0ustar fengfeng ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-obsolete.html0000664000175000017500000000372115167645100031353 0ustar fengfeng Obsolete Members for QtSingleApplication
  Home

Obsolete Members for QtSingleApplication

The following class members are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code.

Public Functions

void initialize ( bool dummy = true )   (obsolete)

Member Function Documentation

void QtSingleApplication::initialize ( bool dummy = true )


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.qhp0000664000175000017500000000741115167645100027365 0ustar fengfeng com.nokia.qtsolutions.qtsingleapplication_head qdoc qt solutions qtsingleapplication qt solutions qtsingleapplication
qtsingleapplication.html index.html qtsingleapplication-example-trivial.html qtsinglecoreapplication.html qtsingleapplication-example-loader.html qtsinglecoreapplication-example-console.html classic.css images/qt-logo.png ukui-panel/panel/3rd-parties/qtsingleapplication/doc/html/index.html0000664000175000017500000000527515167645100024604 0ustar fengfeng Single Application
  Home

Single Application

Description

The QtSingleApplication component provides support for applications that can be only started once per user.

For some applications it is useful or even critical that they are started only once by any user. Future attempts to start the application should activate any already running instance, and possibly perform requested actions, e.g. loading a file, in that instance.

The QtSingleApplication class provides an interface to detect a running instance, and to send command strings to that instance. For console (non-GUI) applications, the QtSingleCoreApplication variant is provided, which avoids dependency on QtGui.

Classes

Examples

Tested platforms

  • Qt 4.4, 4.5 / Windows XP / MSVC.NET 2005
  • Qt 4.4, 4.5 / Linux / gcc
  • Qt 4.4, 4.5 / MacOS X 10.5 / gcc


Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Solutions
ukui-panel/panel/3rd-parties/qtsingleapplication/configure.bat0000664000175000017500000000176215167645100023544 0ustar fengfeng:: Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). :: SPDX-License-Identifier: BSD-3-Clause @echo off rem rem "Main" rem if not "%1"=="" ( if not "%1"=="-library" ( call :PrintUsage goto EOF ) ) if exist config.pri. del config.pri if "%1"=="-library" ( echo Configuring to build this component as a dynamic library. echo SOLUTIONS_LIBRARY = yes > config.pri ) echo . echo This component is now configured. echo . echo To build the component library (if requested) and example(s), echo run qmake and your make or nmake command. echo . echo To remove or reconfigure, run make (nmake) distclean. echo . goto EOF :PrintUsage echo Usage: configure.bat [-library] echo . echo -library: Build the component as a dynamic library (DLL). Default is to echo include the component source directly in the application. echo A DLL may be preferable for technical or licensing (LGPL) reasons. echo . goto EOF :EOF ukui-panel/panel/3rd-parties/qtsingleapplication/common.pri0000664000175000017500000000124715167645100023075 0ustar fengfengexists(config.pri):infile(config.pri, SOLUTIONS_LIBRARY, yes): CONFIG += qtsingleapplication-uselib TEMPLATE += fakelib greaterThan(QT_MAJOR_VERSION, 5)|\ if(equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4))|\ if(equals(QT_MAJOR_VERSION, 5):equals(QT_MINOR_VERSION, 4):greaterThan(QT_PATCH_VERSION, 1)) { QTSINGLEAPPLICATION_LIBNAME = $$qt5LibraryTarget(QtSolutions_SingleApplication-head) } else { QTSINGLEAPPLICATION_LIBNAME = $$qtLibraryTarget(QtSolutions_SingleApplication-head) } TEMPLATE -= fakelib QTSINGLEAPPLICATION_LIBDIR = $$PWD/lib unix:qtsingleapplication-uselib:!qtsingleapplication-buildlib:QMAKE_RPATHDIR += $$QTSINGLEAPPLICATION_LIBDIR ukui-panel/panel/3rd-parties/qtsingleapplication/qtsingleapplication.pro0000664000175000017500000000016515167645100025663 0ustar fengfengTEMPLATE=subdirs CONFIG += ordered include(common.pri) qtsingleapplication-uselib:SUBDIRS=buildlib SUBDIRS+=examples ukui-panel/panel/3rd-parties/qtsingleapplication/CMakeLists.txt0000664000175000017500000000105515167645100023626 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(qtsingleapplication) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Widgets Network REQUIRED) include_directories(src) set(SRCS src/qtsingleapplication.h src/qtsingleapplication.cpp src/qtlocalpeer.h src/qtlocalpeer.cpp) add_library(${PROJECT_NAME} STATIC ${SRCS}) target_include_directories(${PROJECT_NAME} PRIVATE src) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network) ukui-panel/panel/3rd-parties/qtsingleapplication/README.TXT0000664000175000017500000000164115167645100022425 0ustar fengfengQt Solutions Component: Single Application The QtSingleApplication component provides support for applications that can be only started once per user. Version history: 2.0: - Version 1.3 ported to Qt 4. 2.1: - Fix compilation problem on Mac. 2.2: - Really fix the Mac compilation problem. - Mac: fix crash due to wrong object releasing. - Mac: Fix memory leak. 2.3: - Windows: Force creation of internal widget to make it work with Qt 4.2. 2.4: - Fix the system for automatic window raising on message reception. NOTE: minor API change. 2.5: - Mac: Fix isRunning() to work and report correctly. 2.6: - - initialize() is now obsolete, no longer necessary to call it - - Fixed race condition where multiple instances migth be started - - QtSingleCoreApplication variant provided for non-GUI (console) usage - Complete reimplementation. Visible changes: - LGPL release. ukui-panel/panel/3rd-parties/qtsingleapplication/INSTALL.TXT0000664000175000017500000002237415167645100022604 0ustar fengfengINSTALLATION INSTRUCTIONS These instructions refer to the package you are installing as some-package.tar.gz or some-package.zip. The .zip file is intended for use on Windows. The directory you choose for the installation will be referred to as your-install-dir. Note to Qt Visual Studio Integration users: In the instructions below, instead of building from command line with nmake, you can use the menu command 'Qt->Open Solution from .pro file' on the .pro files in the example and plugin directories, and then build from within Visual Studio. Unpacking and installation -------------------------- 1. Unpacking the archive (if you have not done so already). On Unix and Mac OS X (in a terminal window): cd your-install-dir gunzip some-package.tar.gz tar xvf some-package.tar This creates the subdirectory some-package containing the files. On Windows: Unpack the .zip archive by right-clicking it in explorer and choosing "Extract All...". If your version of Windows does not have zip support, you can use the infozip tools available from www.info-zip.org. If you are using the infozip tools (in a command prompt window): cd your-install-dir unzip some-package.zip 2. Configuring the package. The configure script is called "configure" on unix/mac and "configure.bat" on Windows. It should be run from a command line after cd'ing to the package directory. You can choose whether you want to use the component by including its source code directly into your project, or build the component as a dynamic shared library (DLL) that is loaded into the application at run-time. The latter may be preferable for technical or licensing (LGPL) reasons. If you want to build a DLL, run the configure script with the argument "-library". Also see the note about usage below. (Components that are Qt plugins, e.g. styles and image formats, are by default built as a plugin DLL.) The configure script will prompt you in some cases for further information. Answer these questions and carefully read the license text before accepting the license conditions. The package cannot be used if you do not accept the license conditions. 3. Building the component and examples (when required). If a DLL is to be built, or if you would like to build the examples, next give the commands qmake make [or nmake if your are using Microsoft Visual C++] The example program(s) can be found in the directory called "examples" or "example". Components that are Qt plugins, e.g. styles and image formats, are ready to be used as soon as they are built, so the rest of this installation instruction can be skipped. 4. Building the Qt Designer plugin (optional). Some of the widget components are provided with plugins for Qt Designer. To build and install the plugin, cd into the some-package/plugin directory and give the commands qmake make [or nmake if your are using Microsoft Visual C++] Restart Qt Designer to make it load the new widget plugin. Note: If you are using the built-in Qt Designer from the Qt Visual Studio Integration, you will need to manually copy the plugin DLL file, i.e. copy %QTDIR%\plugins\designer\some-component.dll to the Qt Visual Studio Integration plugin path, typically: C:\Program Files\Trolltech\Qt VS Integration\plugins Note: If you for some reason are using a Qt Designer that is built in debug mode, you will need to build the plugin in debug mode also. Edit the file plugin.pro in the plugin directory, changing 'release' to 'debug' in the CONFIG line, before running qmake. Solutions components are intended to be used directly from the package directory during development, so there is no 'make install' procedure. Using a component in your project --------------------------------- To use this component in your project, add the following line to the project's .pro file (or do the equivalent in your IDE): include(your-install-dir/some-package/src/some-package.pri) This adds the package's sources and headers to the SOURCES and HEADERS project variables respectively (or, if the component has been configured as a DLL, it adds that library to the LIBS variable), and updates INCLUDEPATH to contain the package's src directory. Additionally, the .pri file may include some dependencies needed by the package. To include a header file from the package in your sources, you can now simply use: #include or alternatively, in pre-Qt 4 style: #include Refer to the documentation to see the classes and headers this components provides. Install documentation (optional) -------------------------------- The HTML documentation for the package's classes is located in the your-install-dir/some-package/doc/html/index.html. You can open this file and read the documentation with any web browser. To install the documentation into Qt Assistant (for Qt version 4.4 and later): 1. In Assistant, open the Edit->Preferences dialog and choose the Documentation tab. Click the Add... button and select the file your-install-dir/some-package/doc/html/some-package.qch For Qt versions prior to 4.4, do instead the following: 1. The directory your-install-dir/some-package/doc/html contains a file called some-package.dcf. Execute the following commands in a shell, command prompt or terminal window: cd your-install-dir/some-package/doc/html/ assistant -addContentFile some-package.dcf The next time you start Qt Assistant, you can access the package's documentation. Removing the documentation from assistant ----------------------------------------- If you have installed the documentation into Qt Assistant, and want to uninstall it, do as follows, for Qt version 4.4 and later: 1. In Assistant, open the Edit->Preferences dialog and choose the Documentation tab. In the list of Registered Documentation, select the item com.nokia.qtsolutions.some-package_version, and click the Remove button. For Qt versions prior to 4.4, do instead the following: 1. The directory your-install-dir/some-package/doc/html contains a file called some-package.dcf. Execute the following commands in a shell, command prompt or terminal window: cd your-install-dir/some-package/doc/html/ assistant -removeContentFile some-package.dcf Using the component as a DLL ---------------------------- 1. Normal components The shared library (DLL) is built and placed in the some-package/lib directory. It is intended to be used directly from there during development. When appropriate, both debug and release versions are built, since the run-time linker will in some cases refuse to load a debug-built DLL into a release-built application or vice versa. The following steps are taken by default to help the dynamic linker to locate the DLL at run-time (during development): Unix: The some-package.pri file will add linker instructions to add the some-package/lib directory to the rpath of the executable. (When distributing, or if your system does not support rpath, you can copy the shared library to another place that is searched by the dynamic linker, e.g. the "lib" directory of your Qt installation.) Mac: The full path to the library is hardcoded into the library itself, from where it is copied into the executable at link time, and ready by the dynamic linker at run-time. (When distributing, you will want to edit these hardcoded paths in the same way as for the Qt DLLs. Refer to the document "Deploying an Application on Mac OS X" in the Qt Reference Documentation.) Windows: the .dll file(s) are copied into the "bin" directory of your Qt installation. The Qt installation will already have set up that directory to be searched by the dynamic linker. 2. Plugins For Qt Solutions plugins (e.g. image formats), both debug and release versions of the plugin are built by default when appropriate, since in some cases the release Qt library will not load a debug plugin, and vice versa. The plugins are automatically copied into the plugins directory of your Qt installation when built, so no further setup is required. Plugins may also be built statically, i.e. as a library that will be linked into your application executable, and so will not need to be redistributed as a separate plugin DLL to end users. Static building is required if Qt itself is built statically. To do it, just add "static" to the CONFIG variable in the plugin/plugin.pro file before building. Refer to the "Static Plugins" section in the chapter "How to Create Qt Plugins" for explanation of how to use a static plugin in your application. The source code of the example program(s) will also typically contain the relevant instructions as comments. Uninstalling ------------ The following command will remove any fils that have been automatically placed outside the package directory itself during installation and building make distclean [or nmake if your are using Microsoft Visual C++] If Qt Assistant documentation or Qt Designer plugins have been installed, they can be uninstalled manually, ref. above. Enjoy! :) - The Qt Solutions Team. ukui-panel/panel/3rd-parties/qtsingleapplication/examples/0000775000175000017500000000000015167645100022703 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/examples/examples.pro0000664000175000017500000000011115167645100025234 0ustar fengfengTEMPLATE = subdirs SUBDIRS = trivial \ loader \ console ukui-panel/panel/3rd-parties/qtsingleapplication/examples/trivial/0000775000175000017500000000000015167645100024355 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/examples/trivial/trivial.qdoc0000664000175000017500000000271115167645100026700 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause /*! \page qtsingleapplication-example-trivial.html \title A Trivial Example The application in this example has a log-view that displays messages sent by further instances of the same application. The example demonstrates the use of the QtSingleApplication class to detect and communicate with a running instance of the application using the sendMessage() API. The messageReceived() signal is used to display received messages in a QTextEdit log. \quotefromfile trivial/main.cpp \printuntil instance The example has only the \c main entry point function. A QtSingleApplication object is created immediately. \printuntil return If another instance of this application is already running, sendMessage() will succeed, and this instance just exits immediately. \printuntil show() Otherwise the instance continues as normal and creates the user interface. \printuntil return instance.exec(); The \c logview object is also set as the application's activation window. Every time a message is received, the window will be raised and activated automatically. The messageReceived() signal is also connected to the QTextEdit's append() slot. Every message received from further instances of this application will be displayed in the log. Finally the event loop is entered. */ ukui-panel/panel/3rd-parties/qtsingleapplication/examples/trivial/trivial.pro0000664000175000017500000000012115167645100026543 0ustar fengfengTEMPLATE = app include(../../src/qtsingleapplication.pri) SOURCES += main.cpp ukui-panel/panel/3rd-parties/qtsingleapplication/examples/trivial/main.cpp0000664000175000017500000000145215167645100026007 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include #include class TextEdit : public QTextEdit { Q_OBJECT public: TextEdit(QWidget *parent = 0) : QTextEdit(parent) {} public slots: void append(const QString &str) { QTextEdit::append(str); } }; #include "main.moc" int main(int argc, char **argv) { QtSingleApplication instance(argc, argv); if (instance.sendMessage("Wake up!")) return 0; TextEdit logview; logview.setReadOnly(true); logview.show(); instance.setActivationWindow(&logview); QObject::connect(&instance, SIGNAL(messageReceived(const QString&)), &logview, SLOT(append(const QString&))); return instance.exec(); } ukui-panel/panel/3rd-parties/qtsingleapplication/examples/loader/0000775000175000017500000000000015167645100024151 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/examples/loader/loader.pro0000664000175000017500000000020615167645100026137 0ustar fengfenggreaterThan(QT_MAJOR_VERSION, 4): QT += printsupport TEMPLATE = app include(../../src/qtsingleapplication.pri) SOURCES += main.cpp ukui-panel/panel/3rd-parties/qtsingleapplication/examples/loader/file1.qsl0000664000175000017500000000000715167645100025667 0ustar fengfengFile 1 ukui-panel/panel/3rd-parties/qtsingleapplication/examples/loader/main.cpp0000664000175000017500000000432415167645100025604 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include #include #include #include #include #include #include #include class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); public slots: void handleMessage(const QString& message); signals: void needToShow(); private: QMdiArea *workspace; }; MainWindow::MainWindow() { workspace = new QMdiArea(this); setCentralWidget(workspace); } void MainWindow::handleMessage(const QString& message) { enum Action { Nothing, Open, Print } action; action = Nothing; QString filename = message; if (message.toLower().startsWith("/print ")) { filename = filename.mid(7); action = Print; } else if (!message.isEmpty()) { action = Open; } if (action == Nothing) { emit needToShow(); return; } QFile file(filename); QString contents; if (file.open(QIODevice::ReadOnly)) contents = file.readAll(); else contents = "[[Error: Could not load file " + filename + "]]"; QTextEdit *view = new QTextEdit; view->setPlainText(contents); switch(action) { case Print: { QPrinter printer; view->print(&printer); delete view; } break; case Open: { workspace->addSubWindow(view); view->setWindowTitle(message); view->show(); emit needToShow(); } break; default: break; }; } #include "main.moc" int main(int argc, char **argv) { QtSingleApplication instance("File loader QtSingleApplication example", argc, argv); QString message; for (int a = 1; a < argc; ++a) { message += argv[a]; if (a < argc-1) message += " "; } if (instance.sendMessage(message)) return 0; MainWindow mw; mw.handleMessage(message); mw.show(); QObject::connect(&instance, SIGNAL(messageReceived(const QString&)), &mw, SLOT(handleMessage(const QString&))); instance.setActivationWindow(&mw, false); QObject::connect(&mw, SIGNAL(needToShow()), &instance, SLOT(activateWindow())); return instance.exec(); } ukui-panel/panel/3rd-parties/qtsingleapplication/examples/loader/file2.qsl0000664000175000017500000000000715167645100025670 0ustar fengfengFile 2 ukui-panel/panel/3rd-parties/qtsingleapplication/examples/loader/loader.qdoc0000664000175000017500000000335515167645100026275 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause /*! \page qtsingleapplication-example-loader.html \title Loading Documents The application in this example loads or prints the documents passed as commandline parameters to further instances of this application. \quotefromfile loader/main.cpp \printuntil }; The user interface in this application is a QMainWindow subclass with a QMdiArea as the central widget. It implements a slot \c handleMessage() that will be connected to the messageReceived() signal of the QtSingleApplication class. \printuntil } The MainWindow constructor creates a minimal user interface. \printto case Print: The handleMessage() slot interprets the message passed in as a filename that can be prepended with \e /print to indicate that the file should just be printed rather than loaded. \printto #include Loading the file will also activate the window. \printto mw The \c main entry point function creates a QtSingleApplication object, and creates a message to send to a running instance of the application. If the message was sent successfully the process exits immediately. \printuntil } If the message could not be sent the application starts up. Note that \c false is passed to the call to setActivationWindow() to prevent automatic activation for every message received, e.g. when the application should just print a file. Instead, the message handling function determines whether activation is requested, and signals that by emitting the needToShow() signal. This is then simply connected directly to QtSingleApplication's activateWindow() slot. */ ukui-panel/panel/3rd-parties/qtsingleapplication/examples/console/0000775000175000017500000000000015167645100024345 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/examples/console/console.pro0000664000175000017500000000016515167645100026533 0ustar fengfengTEMPLATE = app CONFIG += console SOURCES += main.cpp include(../../src/qtsinglecoreapplication.pri) QT -= gui ukui-panel/panel/3rd-parties/qtsingleapplication/examples/console/console.qdoc0000664000175000017500000000150115167645100026654 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause /*! \page qtsinglecoreapplication-example-console.html \title A non-GUI example This example shows how to use the single-application functionality in a console application. It does not require the \c QtGui library at all. The only differences from the GUI application usage demonstrated in the other examples are: 1) The \c.pro file should include \c qtsinglecoreapplication.pri instead of \c qtsingleapplication.pri 2) The class name is \c QtSingleCoreApplication instead of \c QtSingleApplication. 3) No calls are made regarding window activation, for obvious reasons. console.pro: \quotefile console/console.pro main.cpp: \quotefile console/main.cpp */ ukui-panel/panel/3rd-parties/qtsingleapplication/examples/console/main.cpp0000664000175000017500000000245615167645100026004 0ustar fengfeng// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). // SPDX-License-Identifier: BSD-3-Clause #include "qtsinglecoreapplication.h" #include void report(const QString& msg) { qDebug("[%i] %s", (int)QCoreApplication::applicationPid(), qPrintable(msg)); } class MainClass : public QObject { Q_OBJECT public: MainClass() : QObject() {} public slots: void handleMessage(const QString& message) { report( "Message received: \"" + message + "\""); } }; int main(int argc, char **argv) { report("Starting up"); QtSingleCoreApplication app(argc, argv); if (app.isRunning()) { QString msg(QString("Hi master, I am %1.").arg(QCoreApplication::applicationPid())); bool sentok = app.sendMessage(msg, 2000); QString rep("Another instance is running, so I will exit."); rep += sentok ? " Message sent ok." : " Message sending failed; the other instance may be frozen."; report(rep); return 0; } else { report("No other instance is running; so I will."); MainClass mainObj; QObject::connect(&app, SIGNAL(messageReceived(const QString&)), &mainObj, SLOT(handleMessage(const QString&))); return app.exec(); } } #include "main.moc" ukui-panel/panel/3rd-parties/qtsingleapplication/buildlib/0000775000175000017500000000000015167645100022653 5ustar fengfengukui-panel/panel/3rd-parties/qtsingleapplication/buildlib/buildlib.pro0000664000175000017500000000072115167645100025163 0ustar fengfengTEMPLATE=lib CONFIG += qt dll qtsingleapplication-buildlib mac:CONFIG += absolute_library_soname win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release build_all include(../src/qtsingleapplication.pri) TARGET = $$QTSINGLEAPPLICATION_LIBNAME DESTDIR = $$QTSINGLEAPPLICATION_LIBDIR win32 { DLLDESTDIR = $$[QT_INSTALL_BINS] QMAKE_DISTCLEAN += $$[QT_INSTALL_BINS]\\$${QTSINGLEAPPLICATION_LIBNAME}.dll } target.path = $$DESTDIR INSTALLS += target ukui-panel/panel/3rd-parties/qtsingleapplication/configure0000775000175000017500000000126115167645100022774 0ustar fengfeng#!/bin/sh if [ "x$1" != "x" -a "x$1" != "x-library" ]; then echo "Usage: $0 [-library]" echo echo "-library: Build the component as a dynamic library (DLL). Default is to" echo " include the component source code directly in the application." echo exit 0 fi rm -f config.pri if [ "x$1" = "x-library" ]; then echo "Configuring to build this component as a dynamic library." echo "SOLUTIONS_LIBRARY = yes" > config.pri fi echo echo "This component is now configured." echo echo "To build the component library (if requested) and example(s)," echo "run qmake and your make command." echo echo "To remove or reconfigure, run make distclean." echo ukui-panel/panel/data/0000775000175000017500000000000015167645111013571 5ustar fengfengukui-panel/panel/data/org.ukui.panel.settings.gschema.xml0000664000175000017500000000411015167645100022413 0ustar fengfeng 46 panelsize the size of UKUI Panel 0 PanelPosition The Position of ukui-panel false If taskbar needs to hide If taskbar needs to hide false If taskbar needs to lock If taskbar needs to lock [] PanelLength The Length of ukui-panel 0 PanelType The Type of ukui-panel 0 The Position of DataIsland The Position of DataIsland 0 The Position of SettingsIsland The Position of SettingsIsland 32 The Size of TopBar The Size of TopBar ukui-panel/cmake/0000775000175000017500000000000015167645100012637 5ustar fengfengukui-panel/cmake/Commons.cmake0000664000175000017500000000000015167645100015242 0ustar fengfengukui-panel/NEWS0000664000175000017500000000005215167645100012253 0ustar fengfeng### ukui-panel 4.10.1.0 * A new start.